Thread: Illegal Instruction at perfectly fine Code

  1. #16
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    Add some debug code.

    Code:
    void doProt ( void *addr, size_t size ) {
        const char *a1 = addr;
        size_t offset = (unsigned long)addr % 4096;
        printf("Addr=%p, base=%p, size=%zd, totalsize=%zd\n", addr, a1-offset, size, size+offset );
    }
    Unless your AnfNS is a "char*" of some sort, then your pointer arithmetic is off.


    Another though - is the memory suitably aligned (like a 4-byte boundary)?
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  2. #17
    Registered User
    Join Date
    Oct 2008
    Location
    TX
    Posts
    2,059
    Quote Originally Posted by m00ni View Post
    My very minimalistic example works fine now, but as soon as the created code becomes larger I get Sigill in the middle of execution. Is there something wrong with my memory range calculation for mprotect?

    To align with page size I do this to calculate starting address: pointer - pointer % 4096
    then I do this for length: array size + pointer % 4096

    That should cover the whole array, shouldn't it?
    Besides aligning on a page boundary, each individual instruction needs to be aligned on a word boundary too.
    Otherwise fetches will straddle the word boundary and the decoding of an arbitrary bit pattern generating a sigill.

  3. #18
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    You guys are being a bit haphazard with your terminology...

    Attempting to execute non-executable memory will generate SIGSEGV.
    Attempting to execute an instruction from a badly aligned address will generate SIGBUS.
    Attempting to execute an illegal instruction will generate SIGILL.

    In short, the only reason you should get SIGILL is executing an illegal instruction. I suspect whatever code you've written that actually copies the instructions into the buffer where they are going to execute, must have a bug in it.

    Either that or your RAM or memory bus is faulty, but if that were true, I think you'd be having more serious issues (like whole-system crashes)
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  4. #19
    Registered User
    Join Date
    Oct 2008
    Location
    TX
    Posts
    2,059
    Quote Originally Posted by brewbuck View Post
    You guys are being a bit haphazard with your terminology...

    Attempting to execute non-executable memory will generate SIGSEGV.
    Attempting to execute an instruction from a badly aligned address will generate SIGBUS.
    Attempting to execute an illegal instruction will generate SIGILL.

    In short, the only reason you should get SIGILL is executing an illegal instruction. I suspect whatever code you've written that actually copies the instructions into the buffer where they are going to execute, must have a bug in it.

    Either that or your RAM or memory bus is faulty, but if that were true, I think you'd be having more serious issues (like whole-system crashes)
    Hmm! you have a point, but why then it runs in single step mode, SIGILLs otherwise.
    Normally it won't run at all, irrespective of the mcu mode i.e. single step or normal.

  5. #20
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by itCbitC View Post
    Hmm! you have a point, but why then it runs in single step mode, SIGILLs otherwise.
    That would lead me to suspect some kind of cache-related problem. I'm not very familiar with PPC, but maybe the instruction cache is stale -- single stepping involves switching to another process entirely and slows things down by a factor of at least a million, which is likely to purge the cache lines containing the stale code... You come back from the debugger to execute the next single step and the cache is refreshed.

    Just speculation. On x86, what I just described cannot happen (instruction cache lines are invalidated when overlapping data cache lines get an update), but it might be otherwise on PPC.

    The OP might try setting the instruction area non-cacheable and see if that changes things. At least you could rule out the above problem...
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  6. #21
    Registered User
    Join Date
    Feb 2011
    Posts
    11
    Hey there,

    Thanks for all the help and information. I was actually thinking about the same thing today at work (it is already midnight here so I am not at work anymore =D), I mean that I get Sigill and treat it like SigSev but the funny thing is, at least for my mini example the mprotect stuff worked for some reason.

    About the memory yes it is 4 byte aligned the memalloc of the RTE takes care of it. Also I really checked everything about the instructions, every damn bit and the instructions and all involved registers/memory store exactly what the are supposed to store. The cache thing might be something that is worth looking into because I noticed this today:

    With the PC software (which transfers the native code that is compiled on the pc not on the ppc) I can reset and thereby restart the RTE which results in new code creation and a fresh launch of the native code. So with my working mini example I have this behavior: I start RTE and execute my locally generated nc => everything is fine. I trigger the RTE to stop executing the code and recompile everything the restart the execution without restarting the RTE => Everything works fine. If I do that AGAIN I get SIGILL at first instruction of my NC. So I changed NOTHING but I suddenly get a SIGILL. So maybe there is something wrong with the cache.

    Do you have any suggestions how I could test that. besides getting a different ppc platform?

    Ah also, I keep forgetting to emphasize that the downloaded nc, which is the same as my locally generated nc for the examples that I used so far, is being executed without any problems. And as I sayd it is the same nc with the same parameters/registers etc. The only difference is the location where the nc is stored. Thats what got me hooked on the memory problems...
    Last edited by m00ni; 02-10-2011 at 04:22 PM.

  7. #22
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    Your RTE should have an API call to invalidate the cache.
    If not, it's usually just a bit of time with the processor reference manual to see what few instructions you need to put in an "asm" block.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  8. #23
    Registered User
    Join Date
    Oct 2008
    Location
    TX
    Posts
    2,059
    Quote Originally Posted by m00ni View Post
    Code:
    LZSBYTE (*NC_fct)(LZSDWORD, LZSDWORD, LZSDWORD);
    LZSBYTE *AnfNS;
    
    ...
    
    NC_fct = (LZSBYTE(*)()) AnfNS;
    bRetCode = (*NC_fct)((LZSDWORD) pSegTab_l, (LZSDWORD) pAdrDS, (LZSWORD) hChildInst_p);
    It'd help if you posted more of the code instead of the small snippet above.
    Post code referenced by *NC_fct and the definition/initialization of NC Array.

  9. #24
    Registered User
    Join Date
    Feb 2011
    Posts
    11
    Hey,

    Sorry for the long delay, but I was not at work at the weekend so I did not have access to the code. So here is a little bit more:

    Code:
    typedef struct {
    	tPlcMemPtr m_pArray; //Actual address to an Array
    	LZSWORD m_wOffset; //Next free Offset
    
    } tLzsNcSegment;
    
    typedef struct {
    	LZSWORD m_wDataSegmentInst;
    	tLzsNcSegment m_pNativeCodeSegment;
    } tLzsCompilationTable;
    
    tLzsCompilationTable *pDataSegmentNativeSegmentMap_g;
    LZSWORD wDataSegmentNativeSegmentMapSize_g;
    
    pDataSegmentNativeSegmentMap_g = (tLzsCompilationTable *) LzsEnvMemAlloc(wDSInSegTab * sizeof(tLzsCompilationTable)); 
    //wDSInSegTab is just a counter for the size of the Map
    
    (...)
    
    pDataSegmentNativeSegmentMap_g[wDSInSegTab].m_pNativeCodeSegment.m_pArray= (LZSBYTE *) LzsEnvMemAlloc(wNativeCodeArraySize); 
    //wDSInSegTab is here again a counter which increases for certain conditions to a maximum of the map size
    pDataSegmentNativeSegmentMap_g[wDSInSegTab].m_pNativeCodeSegment.m_wOffset= 0;
    This is how I initialize my native code arrays p_DataSegmentNativeSegmentMap is a global variable. After this I fill the array with nc, which works perfectly.

    Code:
    typedef LZSBYTE LZSFAR* tPlcMemPtr;     /* Ptr to a segment (LZSFAR Address) */
    
    LZSBYTE (*NC_fct)(LZSDWORD, LZSDWORD, LZSDWORD);
    
    tPlcMemPtr pNS;
    pNS = LZSGetNcAddressForDS(hChildInst_p); //returns a BYTE* to the beginning of nc array
    
    AnfNS = pNS;
    AnfNS += bHeaderSize; /* skip header info */
    
    NC_fct = (LZSBYTE(*)()) AnfNS;
    bRetCode = (*NC_fct)((LZSDWORD) pSegTab_l, (LZSDWORD) pAdrDS, (LZSWORD) hChildInst_p);
    
    if (bRetCode) {
    	return bRetCode;
    }

  10. #25
    Registered User
    Join Date
    Feb 2011
    Posts
    11
    The whole code creating function without subfunctions to calculate value and/or insert values to the array:

    Code:
    LZSBYTE LzsCompileSegmentTable(tLzsSegTabEntry LZSFAR *pSegTab_i,
    		LZSUINT unSegTabEntries_i, LZSWORD wTask_i) {
    
    	LZSWORD wNativeCodeArraySize; //Size of Native Code array for this Ucode Segment
    	LZSWORD wUCodeNCodeMapSize; //Size of mapping tables for UCode# to position in Segments
    	LZSWORD wJumpTableSize; //Amount of jumps in Code
    	LZSWORD wDSInSegTab; //Number of data segments in seg table
    	tLzsSegTabEntry LZSFAR *pSegmentTable; //Pointer to SegmentTable
    	tLzsCompilationUnit *CompilationList; //List of Compilation Units
    	tPlcMemPtr pPrimarySegment; //Primary entry in Seg Table
    	tPlcMemPtr pSecondarySegment; //Secondary entry in seg table
    	tPlcMemPtr pToFree; // Pointer to memory that can be freed
    	LZSWORD wTemp;
    	LZSBYTE bRetCode;
    	LZSUINT i;
    
    	pSegmentTable = pSegTab_i;
    	wDSInSegTab = 0;
    	bRetCode = 0;
    	pToFree = LZSNULL;
    	for (i = 0; i < unSegTabEntries_i; i++) {
    		pPrimarySegment = pSegmentTable->m_pPrimarySeg;
    		if (pPrimarySegment != LZSNULL && 0x01 == pPrimarySegment[2]) { //Current Segment is a data segment
    			if (pSegmentTable->m_pSecundarySeg != LZSNULL) {
    				pToFree = LzsSegGetAddr(i, kPlcSegNativeCode);
    				LZSFREE(pToFree);
    			}
    			wDSInSegTab++;
    		}
    		pSegmentTable++;
    	}
    	//Total number of data segments is now in wDSInSegTab
    	//Every Datasegment needs to be linked to a single Native Code block.
    	CompilationList = (tLzsCompilationUnit*) LzsEnvMemAlloc(wDSInSegTab
    			* sizeof(tLzsCompilationUnit));
    	//Every compile unit includes all necessary information to compile the code with the according data segment
    	pDataSegmentNativeSegmentMap_g = (tLzsCompilationTable *) LzsEnvMemAlloc(
    			wDSInSegTab * sizeof(tLzsCompilationTable));
    	wDataSegmentNativeSegmentMapSize_g = wDSInSegTab;
    	//Iterate through all datasegments in segment table -> Calculate sizes for each datasegment in a
    	//first compiler pass through then allocate all necessary memory.
    	wDSInSegTab = 0;
    	pSegmentTable = pSegTab_i;
    	for (i = 0; i < unSegTabEntries_i; i++) {
    		wNativeCodeArraySize = 0;
    		wUCodeNCodeMapSize = 0;
    		wJumpTableSize = 0;
    		pPrimarySegment = pSegmentTable->m_pPrimarySeg;
    		if (pPrimarySegment != LZSNULL && 0x01 == pPrimarySegment[2]) { //Current Segment is a data segment
    			pSecondarySegment = pSegmentTable->m_pSecundarySeg;
    			bRetCode
    					= CompilerFirstPass(pPrimarySegment, pSecondarySegment,
    							&wNativeCodeArraySize, &wUCodeNCodeMapSize,
    							&wJumpTableSize);
    			if (bRetCode != 0) {
    				return bRetCode;
    			}
    			pDataSegmentNativeSegmentMap_g[wDSInSegTab].m_pNativeCodeSegment.m_pArray
    					= (LZSBYTE *) LzsEnvMemAlloc(wNativeCodeArraySize);
    			pDataSegmentNativeSegmentMap_g[wDSInSegTab].m_pNativeCodeSegment.m_wOffset
    					= 0;
    			pDataSegmentNativeSegmentMap_g[wDSInSegTab].m_wDataSegmentInst = i;
    			CompilationList[wDSInSegTab].m_wNativeCodeSegmentSize
    					= wNativeCodeArraySize;
    			CompilationList[wDSInSegTab].m_pUCodeSegment = pSecondarySegment;
    			CompilationList[wDSInSegTab].m_wDataSegmentInst = i;
    			CompilationList[wDSInSegTab].m_arrNCodeMap
    					= (LZSWORD *) LzsEnvMemAlloc(wUCodeNCodeMapSize
    							* sizeof(LZSWORD));
    			CompilationList[wDSInSegTab].m_arrUCodeMap
    					= (LZSWORD *) LzsEnvMemAlloc(wUCodeNCodeMapSize
    							* sizeof(LZSWORD));
    			CompilationList[wDSInSegTab].m_arrPatchPos
    					= (LZSWORD *) LzsEnvMemAlloc(wJumpTableSize
    							* sizeof(LZSWORD));
    			CompilationList[wDSInSegTab].m_arrTargetPos
    					= (LZSWORD *) LzsEnvMemAlloc(wJumpTableSize
    							* sizeof(LZSWORD));
    			CompilationList[wDSInSegTab].m_wJumps = wJumpTableSize;
    			CompilationList[wDSInSegTab].m_wOPCodes = wUCodeNCodeMapSize;
    			CompilationList[wDSInSegTab].m_pNativeCodeSegment
    					= &pDataSegmentNativeSegmentMap_g[wDSInSegTab].m_pNativeCodeSegment;
    			wDSInSegTab++;
    		}
    		pSegmentTable++;
    	}
    
    	//Compile every Compilation Unit
    	for (i = 0; i < wDSInSegTab; i++) {
    		bRetCode = CompilerSecondPass(&CompilationList[i], wTask_i);
    		if (bRetCode != 0) {
    			return bRetCode;
    		}
    		bRetCode = FixJumpsForSegment(&CompilationList[i]);
    		if (bRetCode != 0) {
    			return bRetCode;
    		}
    	}
    	FreeCompilationUnits(CompilationList, wDSInSegTab);
    	return bRetCode;
    }

    The whole calling function:
    Code:
    LZSBYTE LzsNccCallNc(tPlchInst hChildInst_p, LZSDWORD dOffset_p) {
    	LZSBYTE LZSFAR* AnfNS; //Pointer to the start of NC
    	tPlcMemPtr pAdrDS; //Pointer to the start of the DS that is bound to the nc
    	tPlcMemPtr pNS; //Another pointer to nc
    	tSegHeader SegHdrInf; //Stores Header information for a segment
    	LZSBYTE bHeaderSize; //Header size for a segment
    	LZSBYTE (*NC_fct)(LZSDWORD, LZSDWORD, LZSDWORD); //Function definition for calling nc
    	LZSBYTE bRetCode; /* ErrorCode of function */
    
    	bRetCode = kLzsSuccess;
    	pNS = LZSGetNcAddressForDS(hChildInst_p);
    	LzsMemGetSegHeader(pNS, &SegHdrInf);
    	bHeaderSize = LzsMemAbsGetByte((LZSBYTE LZSFAR*) &SegHdrInf.m_HeaderSize);
    
    	/*we also need the adress of DataSegment */
    	pAdrDS = LzsSegReadSegAddr(hChildInst_p, LZSPRIMARY);
    	/* Update the NC Help Segment, we could have changed the instance */
    	LzsNccUpdateInstInHelpSeg(hChildInst_p);
    
    	AnfNS = pNS;
    	AnfNS += bHeaderSize; /* skip header info */
    
    	NC_fct = (LZSBYTE(*)()) AnfNS;
    	bRetCode = (*NC_fct)((LZSDWORD) pSegTab_l, (LZSDWORD) pAdrDS,
    			(LZSWORD) hChildInst_p);
    	if (bRetCode) {
    		return bRetCode;
    	}
    
    	return bRetCode;
    }
    So I do not have any of that permission stuff in any more. So I am back to guessing whats wrong. Right now if I have native code which is just i = i + 1; It sometimes runs and sometimes doesn't, I am not joking here, sometimes when I start debugging it is perfectly fine and sometimes I get SIGILL at the first Instruction. Again, the nc which is stored somewhere else in the memory, not far just about 1kb or so, is running fine every damn time.

    The only difference is the location in the memory, as far as I can tell.
    Last edited by m00ni; 02-14-2011 at 03:12 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. dynamic array
    By mouse666666 in forum C Programming
    Replies: 36
    Last Post: 04-11-2010, 02:27 AM
  2. Beginner: What is wrong with my code? It seems fine!
    By shivdude in forum C Programming
    Replies: 10
    Last Post: 08-03-2009, 03:36 PM
  3. Explain this C code in english
    By soadlink in forum C Programming
    Replies: 16
    Last Post: 08-31-2006, 12:48 AM
  4. Replies: 4
    Last Post: 01-16-2002, 12:04 AM
  5. Big Code, Little Problem
    By CodeMonkey in forum Windows Programming
    Replies: 4
    Last Post: 10-03-2001, 05:14 PM