Viewing variable values via gdb of a va_list is not as straight forward as gdb> p myvar. It requires a few extra steps not only in execution but in understanding. Read on if you want to know how va_* works and how to view the underlying variables.
Step 1:
The first step is to understand the underlying structure of variable arguments and in particular va_list. This blog https://bobobobo.wordpress.com/2008/01/28/how-to-use-variable-argument-lists-va_list/ does a really good job.
The summary from this site:
- va_list, va_start, va_end, va_arg are the macros needed.
- The very first step is to create a pointer to point to the first element of the variable argument list. (va_list myListPointer;)
- use va_start(myListPointer, numargs) to actually make myListPointer point to the first variable. (You need to at least step past this line in order to start inspecting memory).
- The rest involves looping through and printing/calculating the values.
Step 2:
Copy the sample code from https://en.wikipedia.org/wiki/Variadic_function and compile it. Change the input to average as required.
Step 3:
Read through these 2 further posts that shows you the gdb command to run in order to view the value of your variable.
The summary is that you need to type this in gdb:
- p *(int *)(((char *)args[0].reg_save_area)+args[0].gp_offset)
Note to change args to the name of your variable .
Here is another angle. The key is “gp_offset is how many bytes after reg_save_area the first argument is”. So you could find the pointer of first argument via:
>> ap[0].reg_save_area+ap[0].gp_offset
Then you can view it via:
>> x/c 0x7fff5fbffa18
My variable here was ‘8’. To get the content of the next variable, you have to increment the reg_save_area by the number of bytes you know the argument to take. ie run through the loop again calling va_arg(). This will then increment gp_offset.
“…gp_offset will be only incremented after calling va_arg() macro, if you want to see more arguments you must increment reg_save_area by the number of bytes you know arguments take…”
Step 4:
Check out the definition of reg_save_area, overflow_arg_area, gp_offset and fp_offset at: http://stackoverflow.com/questions/4958384/what-is-the-format-of-the-x86-64-va-list-structure
Reason being is if you tried gdb> p args, you would come across these variables. Note my variable is called “ap”
Step 5:
This post does a great job explaining step 4.
https://blog.nelhage.com/2010/10/amd64-and-va_arg/
Conclusion
This is not for the faint hearted, but if you want to truely understand how it actually works, put in the time and figure it out.
(gdb) p *ap Attempt to dereference a generic pointer. (gdb) p ap $13 = (va_list) 0x3fc93014 (gdb) p *(int *)(((char *)ap[0].reg_save_area)+ap[0].gp_offset) Attempt to dereference a generic pointer.