GDB internals document contribution (frame chain assembly)

William Cole wscole@hotmail.com
Wed Mar 21 15:59:00 GMT 2001


 
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




More information about the Gdb mailing list