简体   繁体   中英

Printf Symbol Resolution

I'm writing a little program which trace all the syscall and calls of a binary file (elf) using ptrace (singlestep, getregs, pick_text, opcodes comparison, etc).

So far I've succeed to trace syscalls and simple calls like user defined functions.

But I failed to get the name of the printf symbol from the address I pick thanks to ptrace.

My question is: For dynamic linked function as printf, strlen, etc, how can I retrieve in the elf file the name of the symbol from the address ?

With simple calls it's kind of easy, I run through the .strtab section and when an address match I return the corresponding str.

But for printf, the symbol is known in the .strtab but has the address "0".

objdump -d somehow succeed to link a call to printf with its address.

Do you have any idea ?

I think you may need to read up a little more about dynamic linking. Let's take strlen as an example symbol as printf is a bit special (fortification stuff).

Your problem is (I think) that you want to take the address of a symbol and translate that back into an address. You're trying to do this by parsing the ELF file of the program you are debugging. This works with symbols that are in your program, but not with dynamically linked symbols such as strlen . And you want to know how to resolve that.

The reason for that is that the address of symbols such as strlen are not held within your ELF program. They are instead unresolved references that are resolved dynamically when the program loads . Indeed modern Linux will (I believe) load dynamic libraries (which contain relocatable aka position independent code) in a randomised order and at randomised addresses, so the location of those symbols won't be known until the program loads.

For libraries that you have opened with dlopen() (ie where you are doing the loading yourself in the program), you can retrieve the address of such symbols using dlsym() ; that's not much good if they are linked into the program at compile/link time.

On gcc, to resolve the position of symbols in general, use the gcc extension dladdr() . From the man page:

   The function dladdr() takes a function pointer and tries to
   resolve name and file where it is located.   Information  is
   stored in the Dl_info structure:

       typedef struct {
           const char *dli_fname;  /* Pathname of shared object that
                                      contains address */
           void       *dli_fbase;  /* Address at which shared object
                                      is loaded */
           const char *dli_sname;  /* Name of nearest symbol with address
                                      lower than addr */
           void       *dli_saddr;  /* Exact address of symbol named
                                      in dli_sname */
       } Dl_info;

   If no symbol matching addr could be found, then dli_sname and
   dli_saddr are set to NULL.

   dladdr() returns 0 on error, and nonzero on success.

I believe that will work for you.

For further information, I suggest you look at the source to ltrace which traces library calls, and how backtrace_symbols (and here ) works; note that particularly for non-global symbols this is going to be unreliable, and note the comment re adding -r dynamic to the link line.

You might also want to look at addr2line and its source .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM