This is the mail archive of the gdb@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

GDB internals document contribution (frame chain assembly)


 

Please feel free to include this in the GDB Internals document if it is appropriate.  Please post corrections, clarifications, suggestions. Note some formatting has been munged.

                             Bill

>
> Tracing and Displaying stack frames in GDB
> -------------------------------------------------
>
> In gdb, commands such as bt (backtrace), where, and up display information
>about callee and caller names as well as local variables and function arguments.
>Being able to display such information requires gdb to parse the information in
>the call stack. The "call stack" is used by the process to make function calls by
>saving the return address, function arguments and local variables to memory. As
>the name call stack suggests, this data is pushed onto the stack when the call
>is made and popped on return.
>
>When a process is executed, it contains only a single stack frame, called the
>outermost frame. Each time a function is called, a stack frame is created. The
>stack frame for the currently executing function is called the innermost frame.
>The stack data structure works well because as functions return, the stack frame
>is "popped" and the data is effectively freed.
>
>Looking at what a classical compiler might generate as a call stack for
>a simple C program:
>
> int myseed;
>
> void
> apple( int seed1, int seed2, int seed3 )
> {
> int foo;
> }
>
> void
> banana()
> {
> apple( myseed1, myseed2, myseed3 );
> }
>
>might create a stack which looks like
>
> ---------------------
> | Low Memory |
> | |
> | |
> | |
> ^ | |
> | |------------------ |
> | | return_address |
> | | foo |
> | | |
> stack | |
> |-------------------|
> | return address |
> | myseed1 |
> | myseed2 |
> | myseed3 |
> | |
> | |
> | High Memory |
> | |
>STACK_END ---------------------
>
>The arguments myseed1, for example, can be directly accessed by sp+4. Local
>variables, like foo, are allocated space on the stack. The compiler determines
>the stack offsets for the locals and arguments.
>
>As most recent architectures have a large number of registers, arguments don't normally go
>on the stack, they are usually passed in registers. In exceptional circumstances the last
>few registers are pushed onto the stack, but the first N will always be in registers. Most
>local variables live in registers. The majority of the traffic on the stack frame is the saving
>and restoring of registers which the caller would consider untouched by the callee,
>but the callee needs anyway.
>
>As far as following the backtrace of function calls, the main job is to pull off the return addresses
>from which we can determine the function names in the backtrace.
>
>Function Prologues
>------------------
>
>The function prologue is code generated by the compiler preceeding the code giving the
>functionality of the routine. The prologue is responsible for setting up the stack frame,
>initializing the frame pointer register, and saving registers that must be saved. It must contain
>an appropriate stack frame size given the number of local variables and registers that need to be
>saved to preserve context. The exact contents of the function prologue are compiler and
>architecture dependent.
>
>Identifying function names in backtrace:
>-----------------------------------------
>
> gdb builds a list of struct frame_info's as listed below:
>
>struct frame_info
> {
> CORE_ADDR frame;
> CORE_ADDR pc;
> int signal_handler_caller;
> CORE_ADDR *saved_regs;
>#ifdef EXTRA_FRAME_INFO
> EXTRA_FRAME_INFO
>#endif
> struct frame_extra_info *extra_info;
> struct frame_info *next, *prev;
> };
>
> The frame field contains the actual address of the stack frame and
>is machine dependent. The pc is the current pc for the innermost frame,
>otherwise its the call return address. If signal_handler_caller is
>non-zero, the frame is associated with a signal handler. The saved_regs
>stores the location of where the registers were stored on entry to
>this frame. EXTRA_FRAME_INFO has been deprecated, and the extra_frame_info
>is used instead to store machine specific information. For instance, some
>architectures have variable stack pointers which can only be determined
>by parsing the function prologue. Also, one can store the call return
>address (e.g. extra_info->return_pc) which is essential in the call frame
>chain building process.
>
>The struct frame_info list building starts at the current (innermost) frame.
>This case is treated separately, and is proceed through frames 1 to N, where
>frame N is the outermost frame.
>
>Frame 0:
>--------
>
>For the innermost frame, frame 0, the frame_info pc is usually read from register PC_REGNUM.
>The frame field is read from the frame pointer register. In some architectures, it is necessary to
>parse the function proglogue to determine frame_info.frame. The prologue of the function corresponding
>to the aforementioned pc is examined to determine the size of the call frame and the call return address.
>The prologue examination is discussed in "Prologue Examination" section below and is architecture
>dependent. The call frame size is determined by tracking decrements to the stack pointer (sp)
>in the function prologue. The total decrement to the sp noted in the prologue is the size of
>the call frame. The extra_info.return_pc for frame 0 can usually be taken from a hardware register.
>We call this register the "link" register. The next and prev fields are initialized to NULL.
>
>Frames 1..N:
>------------
>
>For frames n=1..N, the pc is the extra_info->return_pc of the frame n-1. The frame location is
>the frame n-1 + size of the current frame. The prologue of function( pc ) is once again
>examined to determine the size of the current frame. The extra_info.return_pc (value of link register at the time
>the frame is created) is stored on the stack. Its location is determined by tracking the link
>register in the prologue through register transitions in the function prologue. The next and prev links
>as used to form a doubly linked list of frame_info's.
>
>Of course, we need to terminate the frame list creation process. The STACK_END (see picture)
>is at architecture dependent and determined at compile time. If the calculated new frame address
>is above the STACK_END, then we are finished the frame list creation process.
>
>Function Prologue Examination Example:
>--------------------------------------
>
>In this example, the goal of looking at the function prologue is to determine
>which register is being used as a stack pointer, the size of the call frame and
>whether the frame corresponds to a leaf.
>
>In the main section, the prologue starting at pc (the start of a given function)
>is examined one instruction at a time. We examine instructions until hit a
>control instruction (a function prologue never contains a control instruction),
>or until we have gone a given fixed distance (pc_default_search_limit_for_prologue).
>
> Algorithm:
>
> current_pc = pc
> while current_pc < pc_default_search_limit_for_prologue {
> word = read_instruction( current_pc );
> seen_control_word = examine_word(word, &leaf, &sp)
> if( seen_control_word )
> break
> current_pc+=instruction_size;
> }
> return leaf, sp, depth of frame (value of sp decrement).
>
>----
>
> examine_word( word, *leaf, *sp )
>
> if instruction is loading link into register
> note register contains link
> if instruction is storing a register
> if its storing the link register
> leaf = 0
> track location of where register is stored. Don't erase
> previous record if register used before.
> if atom is an add(reg_dest, reg_src, val)
> if we havnt determined a sp for the frame
> if reg_src is on stack pointer list
> sp = reg_src
> if atom is control atom
> return 1.
> else
> return 0;
>
>Leaf Notes:
>----------
>
> The question of whether a frame belongs to a leaf function is used by the
>architecture independent code in gdb to determine how to continue moving
>through the frame chains (get_prev_frame() in blockframe.c)
>
>If the frame is the innermost frame (childless) and a leaf, the frame
>address for this new struct frame_info is the frame address of the
>previous frame_info. If its not a leaf, this new frame address is
>taken from the frame_chain of the child.
>
>Locals and Arguments
>--------------------
>
> As well as building frame lists and displaying function names, astro-gdb
>displays values of function arguments and local variables. For each frame,
>astro-gdb displays the function name and source file location (as described
>in the previous document).
>
> As documented previously, gdb creates a list of struct frame_infos. As part
>of struct frame_info, the location of the frame is known (the field "frame"). The
>struct frame_info combined with the information which the compiler stores in the
>object file via the symbol table can be used to print the entire stack frame, function names,
>arguments, locals + annotations.
>
>The printing of the function name and arguments is covered by print_frame(), which
>calls print_args_stub() which wraps print_frame_args(). For each symbol which is
>an argument, gdb knows from the compiler how the argument is stored. For instance, the argument
>can be stored on the stack directly, or the arguments address can be on the stack, or the
>arguments or addresses can be passed by registers. If the argument itself
>is on the stack, the stack offset which is stored by the compiler is combined
>with the frame info structure (which contains a pointer to the actual frame)
>to give us the target address of the argument. gdb can then read this
>information from the target and display it. If the gdb determines from
>the compiler that the argument of interest is passed by way of register(s), the register
>in question is read from the target machine rather than a specific address.
>In the case of gcc on modern architectures, arguments are usually passed by way of
>registers as resources permit.
>
>Printing out locals works much the same way as arguments, however, printing
>of locals is treated as optional in gdb. Using compiler object file info,
>and the information stored in struct frame_info yields the effective address.
>The arguments and locals both use the same interface read_var_value()
>to read the information from the architecture being debugged.
>
>Note that with opimizations, we may lost information about arguments and locals. We
>only can guarantee success with no or minimal optimizations.
>
>
>
>
>
>
>
>
>


Get your FREE download of MSN Explorer at http://explorer.msn.com


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]