From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 5593 invoked by alias); 30 Nov 2007 16:40:13 -0000 Received: (qmail 5541 invoked by uid 22791); 30 Nov 2007 16:40:10 -0000 X-Spam-Check-By: sourceware.org Received: from wr-out-0506.google.com (HELO wr-out-0506.google.com) (64.233.184.224) by sourceware.org (qpsmtpd/0.31) with ESMTP; Fri, 30 Nov 2007 16:39:58 +0000 Received: by wr-out-0506.google.com with SMTP id 68so2137709wri for ; Fri, 30 Nov 2007 08:39:56 -0800 (PST) Received: by 10.150.57.5 with SMTP id f5mr562696yba.1196440796313; Fri, 30 Nov 2007 08:39:56 -0800 (PST) Received: from ?78.130.102.96? ( [78.130.102.96]) by mx.google.com with ESMTPS id 33sm8028055nfu.2007.11.30.08.39.51 (version=TLSv1/SSLv3 cipher=RC4-MD5); Fri, 30 Nov 2007 08:39:55 -0800 (PST) Message-ID: <47503C57.6010308@portugalmail.pt> Date: Fri, 30 Nov 2007 16:40:00 -0000 From: Pedro Alves User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.13pre) Gecko/20071023 Thunderbird/1.5.0.14pre Mnenhy/0.7.5.0 MIME-Version: 1.0 To: gdb-patches@sourceware.org Subject: [i386/stabs] Arguments of main on gcc >= 4.1 Content-Type: multipart/mixed; boundary="------------020909060009040903060002" X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2007-11/txt/msg00567.txt.bz2 This is a multi-part message in MIME format. --------------020909060009040903060002 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Content-length: 6531 Hi, On gcc/stabs, a function with a normal frame setup sequence has the parameter offsets output as offsets from the frame pointer: E.g., from funcargs.c: void call0a (char c, short s, int i, long l); .stabs "call0a:F(0,15)",36,0,32,call0a .stabs "c:p(0,1)",160,0,31,8 .stabs "s:p(0,1)",160,0,31,12 .stabs "i:p(0,1)",160,0,31,16 .stabs "l:p(0,3)",160,0,31,20 .globl call0a .type call0a, @function call0a: .stabd 46,0,0 Notice the 8 on the first parameter ("c:p(0,1)",160,0,31,8) -- that would be argument word 0 at 8($ebp). Since gcc 4.1 and later started putting code in the prologue to realign the stack pointer, the offset on the parameter stabs changed from being relative to the frame pointer to being relative to the argument's address. E.g.: int main (int argc, char **argv, char **envp); notice the 0, 4, 8: .zero 16 .text .stabs "main:F(0,1)",36,0,10,main .stabs "argc:p(0,1)",160,0,9,0 .stabs "argv:p(0,16)=*(3,54)",160,0,9,4 .stabs "envp:p(0,16)",160,0,9,8 .globl main .type main, @function I don't know if this is a gcc bug or if this is specified somewhere. Several gcc's have been out with this problem, so I guess the best option is to account for it in gdb. The attached patch adds that special casing. In order to fully fix the issue, there is another tweak that needs to be made. By the time we're analyzing the frame, to read the value of a parameter, the register that holds the %esp of the previous frame may have been clobbered. If we see it being saved in the stack before being clobbered, we can still get to it. Eg from args.exp: int main (int argc, char **argv) { 80483e4: 8d 4c 24 04 lea 0x4(%esp),%ecx 80483e8: 83 e4 f0 and $0xfffffff0,%esp 80483eb: ff 71 fc pushl 0xfffffffc(%ecx) 80483ee: 55 push %ebp 80483ef: 89 e5 mov %esp,%ebp 80483f1: 51 push %ecx << register save, 80483f2: 83 ec 24 sub $0x24,%esp << before stack adjustment 80483f5: 89 4d e8 mov %ecx,0xffffffe8(%ebp) int i = 0; While fixing this, I noticed that i386_analyze_stack_align recognizes %ecx, %edx or %eax as the register that is used to hold the %esp of the calling frame, but i386_frame_cache always expected it in %ecx. I've added a new variable in struct i386_frame_cache to represent which register it was, and use it in the i386_frame_cache function. Another change, which is purely cosmetic, is the s/saved_sp/prev_frame_sp/ renaming. For normal, non-main frames, this field doesn't hold anything "saved", but computed in i386_frame_cache: cache->saved_sp = cache->base + 8; The patch has been tested on i686-pc-linux-gnu/dwarf, i686-pc-linux-gnu/"--target_board=unix/gdb:debug_flags=-gstabs+" and on i686-pc-cygwin. On stabs, I get these fixes: --- 0/gdb.sum 2007-11-30 01:30:02.000000000 +0000 +++ 1/gdb.sum 2007-11-30 01:45:33.000000000 +0000 @@ -1,4 +1,4 @@ -Test Run By pedro on Fri Nov 30 01:16:23 2007 +Test Run By pedro on Fri Nov 30 01:31:55 2007 Native configuration is i686-pc-linux-gnu === gdb tests === @@ -283,31 +283,31 @@ PASS: gdb.base/annota3.exp: signal sent PASS: gdb.base/annota3.exp: cleanup core file (removed) Running /home/pedro/gdb/autotester/frame_args_stabs/src/gdb/testsuite/gdb.base/args.exp ... PASS: gdb.base/args.exp: continue to breakpoint: breakpoint for basic -FAIL: gdb.base/args.exp: argc for basic -FAIL: gdb.base/args.exp: argv[1] for basic -FAIL: gdb.base/args.exp: argv[2] for basic +PASS: gdb.base/args.exp: argc for basic +PASS: gdb.base/args.exp: argv[1] for basic +PASS: gdb.base/args.exp: argv[2] for basic PASS: gdb.base/args.exp: continue to breakpoint: breakpoint for one empty -FAIL: gdb.base/args.exp: argc for one empty -FAIL: gdb.base/args.exp: argv[1] for one empty -FAIL: gdb.base/args.exp: argv[2] for one empty -FAIL: gdb.base/args.exp: argv[3] for one empty +PASS: gdb.base/args.exp: argc for one empty +PASS: gdb.base/args.exp: argv[1] for one empty +PASS: gdb.base/args.exp: argv[2] for one empty +PASS: gdb.base/args.exp: argv[3] for one empty PASS: gdb.base/args.exp: continue to breakpoint: breakpoint for two empty -FAIL: gdb.base/args.exp: argc for two empty -FAIL: gdb.base/args.exp: argv[1] for two empty -FAIL: gdb.base/args.exp: argv[2] for two empty -FAIL: gdb.base/args.exp: argv[3] for two empty -FAIL: gdb.base/args.exp: argv[4] for two empty +PASS: gdb.base/args.exp: argc for two empty +PASS: gdb.base/args.exp: argv[1] for two empty +PASS: gdb.base/args.exp: argv[2] for two empty +PASS: gdb.base/args.exp: argv[3] for two empty +PASS: gdb.base/args.exp: argv[4] for two empty PASS: gdb.base/args.exp: continue to breakpoint: breakpoint for one empty -FAIL: gdb.base/args.exp: argc for one empty -FAIL: gdb.base/args.exp: argv[1] for one empty -FAIL: gdb.base/args.exp: argv[2] for one empty -FAIL: gdb.base/args.exp: argv[3] for one empty +PASS: gdb.base/args.exp: argc for one empty +PASS: gdb.base/args.exp: argv[1] for one empty +PASS: gdb.base/args.exp: argv[2] for one empty +PASS: gdb.base/args.exp: argv[3] for one empty PASS: gdb.base/args.exp: continue to breakpoint: breakpoint for two empty -FAIL: gdb.base/args.exp: argc for two empty -FAIL: gdb.base/args.exp: argv[1] for two empty -FAIL: gdb.base/args.exp: argv[2] for two empty -FAIL: gdb.base/args.exp: argv[3] for two empty -FAIL: gdb.base/args.exp: argv[4] for two empty +PASS: gdb.base/args.exp: argc for two empty +PASS: gdb.base/args.exp: argv[1] for two empty +PASS: gdb.base/args.exp: argv[2] for two empty +PASS: gdb.base/args.exp: argv[3] for two empty +PASS: gdb.base/args.exp: argv[4] for two empty Running /home/pedro/gdb/autotester/frame_args_stabs/src/gdb/testsuite/gdb.base/arithmet.exp ... PASS: gdb.base/arithmet.exp: set variable x=14 PASS: gdb.base/arithmet.exp: set variable y=2 @@ -12259,8 +12259,8 @@ PASS: gdb.xml/tdesc-xinclude.exp: set td === gdb Summary === -# of expected passes 11491 -# of unexpected failures 207 +# of expected passes 11512 +# of unexpected failures 186 # of unexpected successes 4 # of expected failures 52 # of unknown successes 6 On dwarf, there are no changes to the testsuite, as in that case, get_frame_args_address is only used for 'info frame'. -- Pedro Alves --------------020909060009040903060002 Content-Type: text/x-diff; name="i386_frame_args.diff" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="i386_frame_args.diff" Content-length: 10167 2007-11-30 Pedro Alves * i386-tdep.c (struct i386_frame_cache): Rename saved_sp to prev_frame_sp. Add saved_sp_regnum field. (i386_alloc_frame_cache): Update. (i386_analyze_stack_align): Record which register holds %esp in saved_sp_regnum. (i386_analyze_register_saves): Move higher on the file. (i386_analyze_frame_setup): Account for register saves before stack adjustment. (i386_frame_cache): If possible, prefer reading the register that holds the previous stack pointer from the stack . (i386_frame_prev_register): Update. (i386_frame_args_address): New. (i386_frame_base): Set i386_frame_args_address as args method. --- gdb/i386-tdep.c | 177 +++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 126 insertions(+), 51 deletions(-) Index: src/gdb/i386-tdep.c =================================================================== --- src.orig/gdb/i386-tdep.c 2007-11-29 01:09:37.000000000 +0000 +++ src/gdb/i386-tdep.c 2007-11-30 15:58:07.000000000 +0000 @@ -298,6 +298,24 @@ i386_breakpoint_from_pc (struct gdbarch registers mentioned above, and %eip. */ #define I386_NUM_SAVED_REGS I386_NUM_GREGS +/* The standard stack frame according to the System V ABI: + + Position | Contents | Frame + -----------+--------------------------+----------- + 4n+8(%ebp) | argument word n | + | ... | Previous + 8(%ebp) | argument word 0 | + -----------+--------------------------+----------- + 4(%ebp) | return address | + +--------------------------+ + 0(%ebp) | previous %ebp (optional) | + +--------------------------+ Current + -4(%ebp) | unspecified | + | ... | + 0(%esp) | variable size | + -----------+--------------------------+----------- +*/ + struct i386_frame_cache { /* Base address. */ @@ -307,8 +325,17 @@ struct i386_frame_cache /* Saved registers. */ CORE_ADDR saved_regs[I386_NUM_SAVED_REGS]; - CORE_ADDR saved_sp; + + /* The value of %esp in the calling frame. */ + CORE_ADDR prev_frame_sp; + + /* Non-zero if this frame has enforced stack alignment. */ int stack_align; + + /* If STACK_ALIGN, which register holds %esp of the calling frame, + else undefined. */ + int saved_sp_regnum; + int pc_in_eax; /* Stack space reserved for local variables. */ @@ -334,7 +361,7 @@ i386_alloc_frame_cache (void) offset (that's where %ebp is supposed to be stored). */ for (i = 0; i < I386_NUM_SAVED_REGS; i++) cache->saved_regs[i] = -1; - cache->saved_sp = 0; + cache->prev_frame_sp = 0; cache->stack_align = 0; cache->pc_in_eax = 0; @@ -517,15 +544,25 @@ i386_analyze_stack_align (CORE_ADDR pc, 0xff, 0x70, 0xfc /* pushl -4(%eax) */ }; gdb_byte buf[10]; + int regnum; - if (target_read_memory (pc, buf, sizeof buf) - || (memcmp (buf, insns_ecx, sizeof buf) != 0 - && memcmp (buf, insns_edx, sizeof buf) != 0 - && memcmp (buf, insns_eax, sizeof buf) != 0)) + if (target_read_memory (pc, buf, sizeof buf)) + return pc; + + if (memcmp (buf, insns_ecx, sizeof buf) == 0) + regnum = I386_ECX_REGNUM; + else if (memcmp (buf, insns_edx, sizeof buf) == 0) + regnum = I386_EDX_REGNUM; + else if (memcmp (buf, insns_eax, sizeof buf) == 0) + regnum = I386_EAX_REGNUM; + else return pc; if (current_pc > pc + 4) - cache->stack_align = 1; + { + cache->stack_align = 1; + cache->saved_sp_regnum = regnum; + } return min (pc + 10, current_pc); } @@ -579,6 +616,36 @@ i386_match_insn (CORE_ADDR pc, struct i3 return NULL; } +/* Check whether PC points at code that saves registers on the stack. + If so, it updates CACHE and returns the address of the first + instruction after the register saves or CURRENT_PC, whichever is + smaller. Otherwise, return PC. */ + +static CORE_ADDR +i386_analyze_register_saves (CORE_ADDR pc, CORE_ADDR current_pc, + struct i386_frame_cache *cache) +{ + CORE_ADDR offset = 0; + gdb_byte op; + int i; + + if (cache->locals > 0) + offset -= cache->locals; + for (i = 0; i < 8 && pc < current_pc; i++) + { + read_memory_nobpt (pc, &op, 1); + if (op < 0x50 || op > 0x57) + break; + + offset -= 4; + cache->saved_regs[op - 0x50] = offset; + cache->sp_offset += 4; + pc++; + } + + return pc; +} + /* Some special instructions that might be migrated by GCC into the part of the prologue that sets up the new stack frame. Because the stack frame hasn't been setup yet, no registers have been saved @@ -713,7 +780,11 @@ i386_analyze_frame_setup (CORE_ADDR pc, if (limit <= pc) return limit; - /* Check for stack adjustment + /* There may be registers saves before the stack is grown for + locals. */ + pc = i386_analyze_register_saves (pc, limit, cache); + + /* Check for stack adjustment subl $XXX, %esp @@ -758,36 +829,6 @@ i386_analyze_frame_setup (CORE_ADDR pc, return pc; } -/* Check whether PC points at code that saves registers on the stack. - If so, it updates CACHE and returns the address of the first - instruction after the register saves or CURRENT_PC, whichever is - smaller. Otherwise, return PC. */ - -static CORE_ADDR -i386_analyze_register_saves (CORE_ADDR pc, CORE_ADDR current_pc, - struct i386_frame_cache *cache) -{ - CORE_ADDR offset = 0; - gdb_byte op; - int i; - - if (cache->locals > 0) - offset -= cache->locals; - for (i = 0; i < 8 && pc < current_pc; i++) - { - read_memory_nobpt (pc, &op, 1); - if (op < 0x50 || op > 0x57) - break; - - offset -= 4; - cache->saved_regs[op - 0x50] = offset; - cache->sp_offset += 4; - pc++; - } - - return pc; -} - /* Do a full analysis of the prologue at PC and update CACHE accordingly. Bail out early if CURRENT_PC is reached. Return the address where the analysis stopped. @@ -811,7 +852,7 @@ i386_analyze_register_saves (CORE_ADDR p %ebx (and sometimes a harmless bug causes it to also save but not restore %eax); however, the code below is willing to see the pushes in any order, and will handle up to 8 of them. - + If the setup sequence is at the end of the function, then the next instruction will be a branch back to the start. */ @@ -925,6 +966,7 @@ i386_frame_cache (struct frame_info *nex struct i386_frame_cache *cache; gdb_byte buf[4]; int i; + CORE_ADDR saved_sp = 0; if (*this_cache) return *this_cache; @@ -955,9 +997,23 @@ i386_frame_cache (struct frame_info *nex if (cache->stack_align) { - /* Saved stack pointer has been saved in %ecx. */ - frame_unwind_register (next_frame, I386_ECX_REGNUM, buf); - cache->saved_sp = extract_unsigned_integer(buf, 4); + /* The previous frame stack pointer has been saved in %ecx, %edx + or %eax at the beginning of the frame setup. Since the + storing register may have been clobbered by the time we're + analyzing this frame, we prefer reading it from the stack if + we've seen it being pushed. */ + if (cache->saved_regs[cache->saved_sp_regnum] != -1) + { + /* We can only see it being pushed if we found a valid + frame, so we can safely access cache->base here. */ + CORE_ADDR reg + = cache->base + cache->saved_regs[cache->saved_sp_regnum]; + read_memory (reg, buf, 4); + } + else + frame_unwind_register (next_frame, cache->saved_sp_regnum, buf); + + saved_sp = extract_unsigned_integer (buf, 4); } if (cache->locals < 0) @@ -973,8 +1029,8 @@ i386_frame_cache (struct frame_info *nex if (cache->stack_align) { /* We're halfway aligning the stack. */ - cache->base = ((cache->saved_sp - 4) & 0xfffffff0) - 4; - cache->saved_regs[I386_EIP_REGNUM] = cache->saved_sp - 4; + cache->base = ((saved_sp - 4) & 0xfffffff0) - 4; + cache->saved_regs[I386_EIP_REGNUM] = saved_sp - 4; /* This will be added back below. */ cache->saved_regs[I386_EIP_REGNUM] -= cache->base; @@ -988,8 +1044,11 @@ i386_frame_cache (struct frame_info *nex /* Now that we have the base address for the stack frame we can calculate the value of %esp in the calling frame. */ - if (cache->saved_sp == 0) - cache->saved_sp = cache->base + 8; + + if (cache->stack_align) + cache->prev_frame_sp = saved_sp; + else + cache->prev_frame_sp = cache->base + 8; /* Adjust all the saved registers such that they contain addresses instead of offsets. */ @@ -1074,7 +1133,7 @@ i386_frame_prev_register (struct frame_i return; } - if (regnum == I386_ESP_REGNUM && cache->saved_sp) + if (regnum == I386_ESP_REGNUM && cache->prev_frame_sp) { *optimizedp = 0; *lvalp = not_lval; @@ -1083,7 +1142,7 @@ i386_frame_prev_register (struct frame_i if (valuep) { /* Store the value. */ - store_unsigned_integer (valuep, 4, cache->saved_sp); + store_unsigned_integer (valuep, 4, cache->prev_frame_sp); } return; } @@ -1233,12 +1292,28 @@ i386_frame_base_address (struct frame_in return cache->base; } +static CORE_ADDR +i386_frame_args_address (struct frame_info *next_frame, void **this_cache) +{ + struct i386_frame_cache *cache = i386_frame_cache (next_frame, this_cache); + + if (cache->stack_align) + /* For `main', the values of LOC_ARG variables are offsets + relative to the arglist address, while for other functions the + offsets are relative to the frame base. */ + return cache->prev_frame_sp; + + /* Arguments are found at 8(%ebp), but STABS parameter values are + offsets from %ebp. */ + return cache->base; +} + static const struct frame_base i386_frame_base = { &i386_frame_unwind, - i386_frame_base_address, - i386_frame_base_address, - i386_frame_base_address + i386_frame_base_address, /* base */ + i386_frame_base_address, /* locals */ + i386_frame_args_address /* args */ }; static struct frame_id --------------020909060009040903060002--