Troubleshooting: Difference between revisions

Jump to navigation Jump to search
[unchecked revision][unchecked revision]
Content deleted Content added
m Bot: Replace deprecated source tag with syntaxhighlight
Line 9: Line 9:


<!-- The following code example should be more generalized (e.g. exc_0d_handler, gpfExcHandler renamed to more meaningful names).-->
<!-- The following code example should be more generalized (e.g. exc_0d_handler, gpfExcHandler renamed to more meaningful names).-->
<source lang="asm">
<syntaxhighlight lang="asm">
exc_0d_handler:
exc_0d_handler:
push gs
push gs
Line 37: Line 37:
pop gs
pop gs
iret
iret
</syntaxhighlight>
</source>


Once you have implemented such a technique, it may be wise to test it, deliberately issuing 'faulty' instructions to see if the correct code is displayed. Having the 'double fault' exception (08) displayed somewhere else on the screen may also be a smart move.
Once you have implemented such a technique, it may be wise to test it, deliberately issuing 'faulty' instructions to see if the correct code is displayed. Having the 'double fault' exception (08) displayed somewhere else on the screen may also be a smart move.
Line 54: Line 54:
In order to avoid recursive exceptions to occur endlessly, you can easily maintain a 'nested exceptions counter' that will be incremented every time you enter an exception handler and decremented just before you leave that handler. If the counter is above a certain threshold of a few units (3 should give interesting enough results), the kernel will abort trying to solve the exception and enter a 'panic' mode (red background, flashing LED, whatever).
In order to avoid recursive exceptions to occur endlessly, you can easily maintain a 'nested exceptions counter' that will be incremented every time you enter an exception handler and decremented just before you leave that handler. If the counter is above a certain threshold of a few units (3 should give interesting enough results), the kernel will abort trying to solve the exception and enter a 'panic' mode (red background, flashing LED, whatever).


<source lang="c">
<syntaxhighlight lang="c">
int nestexc = 0;
int nestexc = 0;


Line 68: Line 68:
return;
return;
}
}
</syntaxhighlight>
</source>


You need to know, of course, that some exceptions are not 'resumable'. If your kernel issued a division by zero, trying to return to the 'div' instruction will only trigger the exception one more time (yeah! altogether, now :). Such loops cannot be solved by the 'nestexc' counter
You need to know, of course, that some exceptions are not 'resumable'. If your kernel issued a division by zero, trying to return to the 'div' instruction will only trigger the exception one more time (yeah! altogether, now :). Such loops cannot be solved by the 'nestexc' counter
Line 77: Line 77:
The stack content is still in memory. The [[EBP]] value of the erroring process is still in memory, and points to the start of the stack frame for the current function. Everything from this address and up was the current stack. Now, you can use the value in ebp as the source. Just use the following call:
The stack content is still in memory. The [[EBP]] value of the erroring process is still in memory, and points to the start of the stack frame for the current function. Everything from this address and up was the current stack. Now, you can use the value in ebp as the source. Just use the following call:


<source lang="asm">
<syntaxhighlight lang="asm">
stack_dump:
stack_dump:
push ebp
push ebp
Line 84: Line 84:
pop ebp
pop ebp
ret ; note that this is not going to work, but it should be here for completion.
ret ; note that this is not going to work, but it should be here for completion.
</syntaxhighlight>
</source>


and use <tt>void dump_hex(char *stack)</tt>.
and use <tt>void dump_hex(char *stack)</tt>.
Line 144: Line 144:
Each time a function is called it gets the following head/tail: ([[GCC]] 3.3.2)
Each time a function is called it gets the following head/tail: ([[GCC]] 3.3.2)


<source lang="asm">
<syntaxhighlight lang="asm">
push ebp
push ebp
mov ebp, esp
mov ebp, esp
Line 150: Line 150:
leave
leave
ret
ret
</syntaxhighlight>
</source>


On the place of the ... the rest of the code is filled in. Now, if you analyze the stack output, it looks something like:
On the place of the ... the rest of the code is filled in. Now, if you analyze the stack output, it looks something like:
Line 182: Line 182:
If your function <tt>x()</tt> wreaks havoc only after 1000 calls it may not suffice to put a <tt>panic()</tt> statement inside the functions to see where the functions breaks. You may want to know which call is malignant. To do this, one might use a global or static var to count calls and panic() after an amount to see if it managed to crash. If not, you try twice that amount; if it does crash, you try bisection to find the amount.
If your function <tt>x()</tt> wreaks havoc only after 1000 calls it may not suffice to put a <tt>panic()</tt> statement inside the functions to see where the functions breaks. You may want to know which call is malignant. To do this, one might use a global or static var to count calls and panic() after an amount to see if it managed to crash. If not, you try twice that amount; if it does crash, you try bisection to find the amount.


<source lang="c">
<syntaxhighlight lang="c">
void scheduler_choose_task() {
void scheduler_choose_task() {
static uint32_t Z=0;
static uint32_t Z=0;
Line 191: Line 191:
...
...
}
}
</syntaxhighlight>
</source>
...and then check how far does it go:
...and then check how far does it go:
<source lang="c">
<syntaxhighlight lang="c">
Z++;
Z++;
uint32_t N = 1000;
uint32_t N = 1000;
Line 199: Line 199:
if (in_critical_section()) return;
if (in_critical_section()) return;
if (Z > N) panic(); //do we get here to panic() before a crash?
if (Z > N) panic(); //do we get here to panic() before a crash?
</syntaxhighlight>
</source>
However as complexity rises or multithreading is involved, it is less probable that a crash would be consistently occurring at the same point, after the same amount of calls every time. Then it would not be possible to find the number of the call to <tt>scheduler_choose_talk()</tt> that crashes it (because that number changes). Debugging needs some imagination; what if you knew, by tracing the program flow with <tt>print(__LINE__)</tt> that <tt>scheduler_choose_task()</tt> crashes only when a call to <tt>fun1()</tt> is in progress? You might use a global var <tt>uint32_t dbg</tt> or an array (<tt>uint32_t dbg[20]</tt>) of various <tt>dbg</tt> vars (which are used only in debugging code which is cleaned after the programmer ceases to debug) in a manner such as:
However as complexity rises or multithreading is involved, it is less probable that a crash would be consistently occurring at the same point, after the same amount of calls every time. Then it would not be possible to find the number of the call to <tt>scheduler_choose_talk()</tt> that crashes it (because that number changes). Debugging needs some imagination; what if you knew, by tracing the program flow with <tt>print(__LINE__)</tt> that <tt>scheduler_choose_task()</tt> crashes only when a call to <tt>fun1()</tt> is in progress? You might use a global var <tt>uint32_t dbg</tt> or an array (<tt>uint32_t dbg[20]</tt>) of various <tt>dbg</tt> vars (which are used only in debugging code which is cleaned after the programmer ceases to debug) in a manner such as:
<source lang="c">
<syntaxhighlight lang="c">
void fun1() {
void fun1() {
dbg[3] = 1;
dbg[3] = 1;
Line 209: Line 209:
dbg[3] = 0;
dbg[3] = 0;
}
}
</syntaxhighlight>
</source>
...and:
...and:
<source lang="c">
<syntaxhighlight lang="c">
void scheduler_choose_task() {
void scheduler_choose_task() {
// if (dbg[3]==1) panic(); //check here.. a panic saves the day from crashing!
// if (dbg[3]==1) panic(); //check here.. a panic saves the day from crashing!
Line 217: Line 217:
if (dbg[3]==1) panic(); //check here.. it crashes
if (dbg[3]==1) panic(); //check here.. it crashes
}
}
</syntaxhighlight>
</source>
(Or mix it with a call count, <tt>Z++; if (Z>5 && dbg[3] == 1) panic()</tt>.)
(Or mix it with a call count, <tt>Z++; if (Z>5 && dbg[3] == 1) panic()</tt>.)


Using the <tt>__LINE__</tt> aids tracing the program flow:
Using the <tt>__LINE__</tt> aids tracing the program flow:
<source lang="c">
<syntaxhighlight lang="c">
print(__LINE__);
print(__LINE__);
</syntaxhighlight>
</source>
See [[C preprocessor#Uses for debugging|Uses for debugging]] for more info.
See [[C preprocessor#Uses for debugging|Uses for debugging]] for more info.