Technical Blog Post
Abstract
== DEBUGGING CORE FILES [05] == STACK TRACE <-> SOURCE CODE
Body
== DEBUGGING CORE FILES [05] == STACK TRACE <-> SOURCE CODE
We know now what is a stack trace, what help it can provide and how
to read it. When a program is compiled with -g the stack trace will
usually contain the line number in the source file. In that case it
is quite easy to find the exact location in the source.
It becomes a bit more complicated when the program was not compiled
with -g and most of the time this is the case. To add to this many
other things can make your quest even harder, to name a few only:
static functions, C++, AIX FDPR and so on...
Let's take a few examples:
- If function 'f1()' calls 'f2()' at only one place in the source
code, then no possible confusion. You can spot the call quite easily.
- If function 'f1()' calls 'f2()' from different location in the source
then things become a bit more complicated and looking at the assembly
will be the only way to spot the accurate location of the call in
the source.
- If this is the last line of the source, as we mentioned before, the
address you'll see in the stack trace will be the address of the
instruction at the time of the trap. So here again no other choice but
looking at the assembly.
- Sometimes the core file might have been generated while the program
was executing an instruction in some system library for which you
won't have the source code. Most of the time this is because the
arguments passed to the function were incorrect. So the idea here
would be to locate that call in your program for which you do have
the source code.
One doesn't need to be an expert in assembly to follow things but most
likely the first times you'll do it you'll need someone to answer the
multiple questions you'll probably have. But the more you do it the easier
it will become.
When you have to match assembly with source code one of the things you
want to do is find some 'easy things' to locate. Those would for example
be literal number assignment like 'i = 673' because you would see the
value '673' in the assembly output. Another example would be a 'printf'
because the core file would contain the 'format' string and it would
be quite easy to locate.
Now the question is where do we start?
Well, the top line of the stack trace will provide the address of
the instruction that was executing when the core file was generated.
It can also be found in the special register that holds the current
instruction address. The name of that register varies with the
platform you are running on:
AIX : 'iar'
LINUX X86: 'rip'
SOLARIS : 'pc'
For viewing the value of the registers in the debugger you can use:
AIX : dbx - (dbx) registers
LINUX X86: gdb - (gdb) info regs
SOLARIS : dbx - (dbx) regs
Also, something that might come handy (though we'll speak of it in more
details later) is the name of the registers used to pass arguments to
functions:
AIX : $r3 to $r10 (arg0 to arg7)
LINUX X86: $rdi, $rsi, $rdx, $rcx, $r8, $r9 (arg0 to arg5)
SOLARIS : $o0 to $o5 (arg0 to arg5)
[{"Business Unit":{"code":"BU058","label":"IBM Infrastructure w\/TPS"},"Product":{"code":"SSEPGG","label":"Db2 for Linux, UNIX and Windows"},"Component":"","Platform":[{"code":"PF025","label":"Platform Independent"}],"Version":"","Edition":"","Line of Business":{"code":"LOB10","label":"Data and AI"}}]
UID
ibm13286071