This is the mail archive of the elfutils-devel@sourceware.org mailing list for the elfutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Crash Feature to print dwarf debugging information


Peter
   Thanks for the input, I was able to redesign the code with your 
suggestions. I was infact looking into dwarfdump code and it uses 
libdwarf.h header, but this header files doesn't seems to be there any 
more in elfutils package.
   This code uses only libdw.h and dwarf.h, Please have a look, I have 
removed most of the error checking (non existence of dwarf information) 
, which I will include later.
   I looked into libdwfl.h, which is used by systemtap, as I understand 
this will be useful in debugging running machine and not the case I am 
looking for so I am considering only libdw.h for the time being.
Let me know your thoughts
Thanks
Sharyathi Nagesh




Petr Machata wrote:
> Sharyathi Nagesh wrote:
>>    Since I was not able to find a good documentation I was not able to 
>> validate the code design. If some one can review and provide me 
>> guidance it will help me immensely.
>>     Challenges are
>>     a. Efficient way of accessing the function/subprogram DIE (Debug 
>> Information Entry) in an executable that contains multiple Complier 
>> Units (CU)
>>     b. Is the sequence of dwarf API calls appropriate
> 
> I think you shouldn't be using <libdwarf.h>, but rather <libdw.h>.
> 
> In fact, you might want to look at libdwfl, which might be a better 
> match for what you do.  I know it supports common core files directly, 
> but I don't how and if vmcore files differ from that, so you may end up 
> having to write some support code yourself.  I don't know much about 
> this library though, so will stick with <libdw.h>.
> 
> Also, use <gelf.h>, it will let you handle 32bit as well as 64bit ELF 
> data structures transparently.
> 
> dwarf_begin_elf will give you Dwarf *dbg that you can work with further. 
>  You can that use dwarf_nextcu to iterate CUs and dwarf_offdie to get CU 
> DIE of each CU:
> 
>     Dwarf_Off cu_off = 0, next_off;
>     size_t header_size;
>     while (!dwarf_nextcu (dbg, cu_off, &next_off, &header_size,
>                   NULL, NULL, NULL)) {
>         Dwarf_Die cudie;
>         if (!dwarf_offdie (dbg, cu_off + header_size, &cudie))
>             return 0;
> 
>         /* per-CU processing here, for example: */
>         int each_fun (Dwarf_Die *die, void *spaces) {
>             Dwarf_Attribute attr;
>             if (dwarf_attr (die, DW_AT_name, &attr) != NULL)
>                 printf ("%s%s\n", spaces,
>                     dwarf_formstring (&attr)
>                     ?: "???");
>             return DWARF_CB_OK;
>         }
>         each_fun (&cudie, "");
>         dwarf_getfuncs (&cudie, each_fun, "  ", 0);
> 
>         cu_off = next_off;
>     }
> 
> The example above will list names of all CUs and for each of them give a 
> list of functions defined therein.  each_fun is a callback, which I 
> abuse to also print out CU names.  You would put your per-function 
> processing there and likely not call it for CU DIE itself.
> 
>>     c. Scalability of the application, especially architecture dependency
> 
> The above should work pretty much everywhere.
> 
>> 2. Converting the address mentioned in DW_AT_location to actual 
>> address of the local variable/arguments. System tap function 
>> literal_stmt_for_local() has an implementation for this, I am going 
>> thorough this some help in this direction will help me immensly.
> 
> I don't know any deep secrets about this.  dwarf_getlocation_addr looks 
> to me like the right function to call to get hands on stream of location 
> operands for given DIE.  The address argument that it needs is, I think, 
> the instruction pointer (the location of the variable changes depending 
> on where in code you are;  it can be a register here, stack over there, 
> etc.)
> 
> dwfl_module_return_value_location from libdwfl looks like an interesting 
> alternative to me.
> 
> You would still need to write evaluator for DW_AT_location.  I think 
> some things in that are pretty easy, namely general arithmetic, but most 
> of the interesting stuff involves reading register values, and that's 
> pretty specific for your problem domain.  That's actually something that 
> peeking in systemtap sources might help with.
> 
>> 3. Converting the address generated from DW_AT_location to actual 
>> address in vmcore dump. I am assuming the address we get from the 
>> dwarf tag will be a virtual address and that needs to be mapped to a 
>> location at vmocre file. crash tool has a routine readmem(), I am 
>> currently looking into it for probable solution.
> 
> That's something I can't help with at all.
> 
> As a sidenote, in your code you seem to be doing a lookup by name.  If 
> you are trying to annotate a stack trace (which I don't know if you do), 
> I would think that you would do lookup by address.  That is, given stack 
> trace of PCs that you have somehow obtained from the core file, call 
> dwarf_addrdie to get CU DIE that covers given PC, and then use that with 
> dwarf_getscopes to get "stack" of DIEs around that PC.  Then find 
> closest function DIE in that stack, iterate its arguments, evaluate 
> their location expressions to find values, etc.
> 
> Hope that helps,
> PM
> 

#include <stdio.h>
#include <libdw.h>    // Include gelf.h
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <dwarf.h>
#include <string.h>

int process_debug_information(Dwarf *, Dwarf_Addr *);
int process_each_cu(Dwarf_Die *, Dwarf_Addr *);
int function_callback(Dwarf_Die *, void *);
int verify_arguments(int argc, char **argv);
int open_file(char *);

int main(int argc, char *argv[])
{
    	Elf_Cmd elf_cmd = ELF_C_READ;
	Dwarf_Cmd dwarf_cmd = DWARF_C_READ;
	Elf *archive_descriptor, *elf_descriptor;
	int fd;
//	GElf_Ehdir elf_file_header;
	Dwarf *dbg;
	
	if (verify_arguments(argc,argv) == -1)
		exit(0);
	 // (void) elf_version(EV_NONE);
    	if (elf_version(EV_CURRENT) == EV_NONE) {
		fprintf(stderr, "libelf.a out of date.\n");
		exit(0);
	}
	fd = open_file(argv[1] /* Executable */);
	archive_descriptor = elf_begin(fd,  elf_cmd, (Elf *) 0);
	while((elf_descriptor = elf_begin(fd, elf_cmd, archive_descriptor))!= 0){  
		//Looping is required in case if it is archive
		//elf_file_header = gelf_getehdr(elf_header);
		dbg = dwarf_begin_elf(elf_descriptor, dwarf_cmd, NULL);
		if (process_debug_information(dbg, (Dwarf_Addr *) argv[2]) == -1)
			exit(0);
	elf_cmd = elf_next(elf_descriptor);
	elf_end(elf_descriptor); //If it is archive: Not required here
	}
	return 0;
}

int process_debug_information(Dwarf *dbg, Dwarf_Addr *addr)
{
	Dwarf_Off cu_off = 0, next_off;
    	size_t header_size;

    	while (!dwarf_nextcu (dbg, cu_off, &next_off, &header_size,
                  NULL, NULL, NULL)) {
        	Dwarf_Die cudie;
	        if (!dwarf_offdie (dbg, cu_off + header_size, &cudie))
	        	return -1;
		if ( process_each_cu(&cudie,addr) == -1)
			return -1;
		cu_off = next_off;	
	}
	return 0;
}

int process_each_cu(Dwarf_Die *cudie, Dwarf_Addr *addr)
{
        dwarf_getfuncs (cudie, function_callback, "  ", 0);
	return 0;
}

int function_callback(Dwarf_Die *fun_die, void *empty)
{
	Dwarf_Attribute attr;
        if (dwarf_attr (fun_die, DW_AT_name, &attr) != NULL)
        	printf ("%s%s\n", (char *)empty, dwarf_formstring (&attr));
	return DWARF_CB_OK;
}
int open_file(char *file_name)
{
	return open(file_name, O_RDONLY);
}
int verify_arguments(int argc, char **argv)
{
	if(argc < 3){
		(void)fprintf(stderr, "not enough arguments being passed\n");
		return -1;
	}
	return 0;
}


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]