From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 893 invoked by alias); 19 Jul 2010 14:19:29 -0000 Received: (qmail 884 invoked by uid 22791); 19 Jul 2010 14:19:28 -0000 X-SWARE-Spam-Status: No, hits=-1.9 required=5.0 tests=AWL,BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,T_TO_NO_BRKTS_FREEMAIL X-Spam-Check-By: sourceware.org Received: from mail-ww0-f43.google.com (HELO mail-ww0-f43.google.com) (74.125.82.43) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 19 Jul 2010 14:19:20 +0000 Received: by wwb22 with SMTP id 22so224169wwb.12 for ; Mon, 19 Jul 2010 07:19:18 -0700 (PDT) MIME-Version: 1.0 Received: by 10.227.138.70 with SMTP id z6mr4133859wbt.22.1279549157285; Mon, 19 Jul 2010 07:19:17 -0700 (PDT) Received: by 10.216.61.205 with HTTP; Mon, 19 Jul 2010 07:19:17 -0700 (PDT) In-Reply-To: References: <20100716191203.GA20877@host1.dyn.jankratochvil.net> Date: Mon, 19 Jul 2010 14:19:00 -0000 Message-ID: Subject: Re: Debugging variable arguments functions (stdarg) From: G To: gdb@sourceware.org Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Mailing-List: contact gdb-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-owner@sourceware.org X-SW-Source: 2010-07/txt/msg00075.txt.bz2 On Sun, Jul 18, 2010 at 9:27 PM, Petr Hluz=EDn wrot= e: > On 16 July 2010 21:12, Jan Kratochvil wrote: >> On Fri, 16 Jul 2010 20:57:57 +0200, Petr Hluz=EDn wrote: >>> Workaround B: >>> Get value of stack pointer (RSP?) of frame MysqlWrapper() and dump raw >>> memory around the address. You should see these values somewhere >>> around: >>> 0x00000000004041e2 (return address in MysqlWrapper) >>> 0x406bf0 (the third argument to WriteLog) >>> Between these two values should be the values of 3rd and 4th argument. >> >> This is not so simple on x86_64, it passes even (first few) stdarg param= eters >> in registers. >> =A0 =A0 =A0 =A0http://www.x86-64.org/documentation/abi.pdf > > Nice reading. > I suppose it is documented section "3.5.7 Variable Argument Lists". > Unfortunately I was not able to find any specific wording. > But it makes sense. You are probably right. > > It should be possible by reading the document to determine if the two > arguments go to stack or remained in registers. I failed to figure > that out. > > Ok, this means that G has to examine stack memory of all frames - infeasi= ble. First, thanks for the replies. I've actually found a solution which lets me look at the arguments passed in the "..." list without too much effort, and thought I'd share it. A Google search for "gdb variadic" instead of "gdb variable arguments" turned up a blog post at http://www.moythreads.com/wordpress/2008/05/ which contained an almost complete solution. In case that blog post disappears, and for archiving reasons, I'm including a very short writeup/example here. First some simple code: #include #include void myfunc(const char *fmt, ...) { va_list args; va_start(args, fmt); vprintf(fmt, args); va_end(args); return; } int main(int argc, char *argv[]) { myfunc("test 1: %s %s\n", "one", "two"); myfunc("test 2: %s %d %c\n", "apple", 222, 'y'); return 0; } A short debugging session with some comments so that some gdb novice like myself might get an idea of what is happening (I hope my comments are correct...): $ gdb testprog GNU gdb (GDB) 7.1-debian [snip] Reading symbols from /home/user/testprog...done. (gdb) break myfunc Breakpoint 1 at 0x400552: file testprog.c, line 7. (gdb) run Starting program: /home/user/testprog Breakpoint 1, myfunc (fmt=3D0x4006f4 "test 1: %s %s\n") at testprog.c:7 7 va_start(args, fmt); (gdb) # initialize args to hold correct values: (gdb) step 8 vprintf(fmt, args); (gdb) # print first argument in "..." list which we know is a char*: (gdb) p *(char **)(((char *)args[0].reg_save_area)+args[0].gp_offset) $1 =3D 0x4006f0 "one" (gdb) # print first byte in argument in "..." list which we know is a char*: (gdb) p **(char **)(((char *)args[0].reg_save_area)+args[0].gp_offset) $2 =3D 111 'o' (gdb) # print first byte in second argument in "..." list which is also a c= har* (gdb) # (we use +8 since this is a 64-bit machine): (gdb) p **(char **)(((char *)args[0].reg_save_area)+args[0].gp_offset+8) $3 =3D 116 't' (gdb) # print second argument in "..." list: (gdb) p *(char **)(((char *)args[0].reg_save_area)+args[0].gp_offset+8) $4 =3D 0x4006ec "two" (gdb) # look at what lies beyond: (gdb) p *(long *)(((char *)args[0].reg_save_area)+args[0].gp_offset+16) $5 =3D 0 (gdb) # step program to execute the vprintf() call: (gdb) next test 1: one two 11 } (gdb) # return to main(): (gdb) next main (argc=3D1, argv=3D0x7fffffffeb58) at testprog.c:16 16 myfunc("test 2: %s %d %c\n", "apple", 222, 'y'); (gdb) # execute call to myfunc() a second time with different arguments: (gdb) next Breakpoint 1, myfunc (fmt=3D0x400715 "test 2: %s %s %s\n") at testprog.c:7 7 va_start(args, fmt); (gdb) # initialize args to hold correct values: (gdb) step 8 vprintf(fmt, args); (gdb) # print first argument in "..." list which again we know is a char*: (gdb) p *(char **)(((char *)args[0].reg_save_area)+args[0].gp_offset) $6 =3D 0x40070f "apple" (gdb) # print second argument in "..." list which is an int: (gdb) p *(int *)(((char *)args[0].reg_save_area)+args[0].gp_offset+8) $7 =3D 222 (gdb) # print third argument in "..." list which is a char: (gdb) p *(char *)(((char *)args[0].reg_save_area)+args[0].gp_offset+16) $8 =3D 121 'y' (gdb) # look at what lies beyond: (gdb) p *(long *)(((char *)args[0].reg_save_area)+args[0].gp_offset+24) $9 =3D 1 (gdb) # OK, so the 0 at the end of the last "..." list seems like just a (gdb) # coincidence, not an intentional NULL value. (gdb) # let program finish: (gdb) cont Continuing. test 2: apple 222 y Program exited normally. (gdb)