When a program fails because of an assertion violation, segmentation fault or some other cause, the amount of information provided on most systems is fairly minimal.
One piece of information that I would like to see would be the stack trace (or call history) for the program. For instance, I'd like to see a message of the form:
pc=0x4f1c09 int_stack.c: 53
pc=0x40300e eval_expr.c: 1140
pc=0x530ef7 parse_file.c: 5131
pc=052d94de main.c: 1926
assertion "len_int_stack(stack) > 0" failed: file int_stack.c, line 53
This immediately gives me some insight into what could be going wrong, and where to focus debugging.
Clearly, one could get the same information by rerunning the program under the debugger, and then asking for a stack-trace when the program fails. However:
When working on a large project, we build a module to dump the stack-trace for us. This is extremely system dependent, so I won't be able to give you an implementation. Instead, I shall describe the steps involved, and you will have to figure out how to do it in your environment.
Before we get into how to implement stack tracing, lets go over the stack organization of most systems.
---------
stack-pointer-->| X |
| |
| |
| |
---------
X -->| Y |
| pc0 |
| |
| |
---------
Y -->| Z |
| pc1 |
| |
| |
---------
Z -->| 0 |
| pc2 |
| |
| |
---------
The piece of ASCII art above indicates a possible stack. In this stack, there are 4 frames. The back-chain consists of X, Y, and Z. The function currently executing will return to pc0, which in turn returns to pc1, which in turn returns to pc2. pc2 is probably the system function that called main().
The steps involved in writing a stack trace module are:
struct sigcontext argument.
One of the fields of the structure will contain the actual
top-of-stack. The structure will also contain the pc for the
top-most routine.
gdb port to the system I am working on,
I look to see how gdb does it. Of course, if the environment you
are working in is based on the GNU binutils, then you can use
functions provided by libbfd.a. Look at:
bfd_init(): to enable use of bfd.
bfd_set_default_target(): to setup the target type.
bfd_openr(): to open the executable.
bfd_get_section_by_name(): to extract the ".text" section.
bfd_find_nearest_line(): to map pc onto source name/line number.