dwarf.c 4.79 KB
/*==============================================================================
    Module: dwarf.c
    $Revision: 1.1.1.2 $
    $Date: 2002/10/29 08:07:15 $
    $Author: blythe $
    $Source: /root/leakn64/depot/rf/sw/n64os20l/tools/gcord/com/dwarf.c,v $

    This file contains the routines used to handle ELF executable format
    and dwarf symbol table.
==============================================================================*/
#include <stddef.h>
#include <sys/types.h>
#include <fcntl.h>
#include <elf.h>
#include <stdio.h>
#include <libelf.h>
#include <string.h>
#include <sys/mman.h>
#include <malloc.h>
#include <stdlib.h>

#include <dwarf.h>
#include <libdwarf.h>

#include "global.h"
#include "option.h"

static Dwarf_Error err;

void print_dwarf_error(Dwarf_Debug, int, Dwarf_Error, char *, ...);

/*------------------------------------------------------------------------------
  Search through a die and it's siblings and children for procedures.
------------------------------------------------------------------------------*/
static void 
get_dwarf_proc (char *filename, Dwarf_Debug dbg, Dwarf_Die die)
{
    Dwarf_Die 	child;
    Dwarf_Die 	sibling;
    Dwarf_Half 	tag;
    int 	code;

    /*------------------
	look at this die
    ------------------*/
    code = dwarf_tag(die, &tag, &err);
    if (code != DW_DLV_OK)
	 print_dwarf_error(dbg, code, err, "dwarf_tag");
    if (tag == DW_TAG_subprogram) {
	Proc 		*proc;
	Dwarf_Addr 	highpc;
	Dwarf_Addr 	lowpc;
	char		*proc_name;
	char		*name;
	int 		code;

	code = dwarf_diename(die, &name, &err);
	if (code != DW_DLV_OK)
	{
	     print_dwarf_error(dbg, code, err, "dwarf_diename");
	}
	else
	{
	     proc_name = strdup(name);
	     dwarf_dealloc(dbg, name, DW_DLA_STRING);
	}

		/* get high pc */
	code = dwarf_highpc(die, &highpc, &err);
	if (code == DW_DLV_NO_ENTRY) {
	    Dwarf_Attribute attr;
	    if (dwarf_attr(die, DW_AT_declaration,&attr, &err) == DW_DLV_OK){
	        /* a declaration, not a subprogram */
	        dwarf_dealloc(dbg,attr, DW_DLA_ATTR);
	        goto check_siblings_and_childs;
	    }else{
	        print_dwarf_error(dbg, code, err, "dwarf_highpc in %s", 
			proc_name);
	    }
	}
	else if (code != DW_DLV_OK)
	     print_dwarf_error(dbg, code, err, "dwarf_highpc in %s", proc_name);

		/* get low pc */
	code = dwarf_lowpc(die, &lowpc, &err);
	if (code != DW_DLV_OK)
	     print_dwarf_error(dbg, code, err, "dwarf_lowpc in %s", proc_name);

	proc = new_proc();
	proc->file_name = filename;
	proc->name = proc_name;
	proc->begin = lowpc;
	proc->size = highpc -lowpc;

	if (option.debug & DEBUG_DEBUG)
	dump("  Subprogram: %s(%#llx-%#llx)",
	    proc->name, (Uint64) lowpc, (Uint64) highpc);
    }

check_siblings_and_childs:

    /*------------------
	search for siblings
    ------------------*/
    code = dwarf_siblingof(dbg, die, &sibling, &err);
    if (code == DW_DLV_OK){
        get_dwarf_proc(filename, dbg, sibling);
        dwarf_dealloc(dbg, sibling, DW_DLA_DIE);
    }
    else if (code == DW_DLV_ERROR)
	print_dwarf_error(dbg, code, err, "dwarf_dibling");

    /*------------------
	search for childs
    ------------------*/
    code = dwarf_child(die, &child, &err);
    if (code == DW_DLV_OK){
        get_dwarf_proc(filename, dbg, child);
        dwarf_dealloc(dbg, child, DW_DLA_DIE);
    }
    else if (code == DW_DLV_ERROR)
	print_dwarf_error(dbg, code, err, "dwarf_child");

}

/*------------------------------------------------------------------------------
   interface for dwarf to get procedure ranges
------------------------------------------------------------------------------*/
void
dwarf_interface (Elf *elf)
{
    Dwarf_Debug 	dbg;
    Dwarf_Unsigned 	cu_offset;
    Dwarf_Unsigned 	cu_header_length;
    Dwarf_Half 		address_size;
    Dwarf_Die 		cu_die;
    char 		*filename;
    int			code;
    int			i;

    i = dwarf_elf_init(elf, DW_DLC_READ, NULL, NULL, &dbg, &err);
    ASSERT(i != DW_DLV_ERROR);
    ASSERT(i != DW_DLV_NO_ENTRY);

    while ((code = dwarf_next_cu_header(dbg, 
		(Dwarf_Unsigned *) NULL, (Dwarf_Half *) NULL, 
		(Dwarf_Off *) NULL, (Dwarf_Half *) NULL,
		&cu_offset, &err)) == DW_DLV_OK) {

	ASSERT(cu_offset != DW_DLV_BADOFFSET);

	code = dwarf_siblingof(dbg, NULL, &cu_die,  &err);
	if (code != DW_DLV_OK)
	     print_dwarf_error(dbg, code, err, "dwarf_siblingof");

	/* file */
	code = dwarf_diename(cu_die, &filename, &err);
	if (code != DW_DLV_OK)
	     print_dwarf_error(dbg, code, err, "dwarf_diename");

	if (option.debug & DEBUG_DEBUG)
	    dump("File:  %s", filename);
		
	/* now go through the file die to get the procedures */
	get_dwarf_proc(filename, dbg, cu_die);

	dwarf_dealloc(dbg, cu_die, DW_DLA_DIE);
    }
    if (code == DW_DLV_ERROR)
	print_dwarf_error(dbg, code, err, "dwarf_next_cu_header");

    code = dwarf_finish(dbg, &err);
    if (code != DW_DLV_OK)
	print_dwarf_error(dbg, code, err, "dwarf_next_cu_header");

}