tools/elf4rom/libs/dwarf-20071209/libdwarf/dwarf_addr_finder.c
changeset 34 92d87f2e53c2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/elf4rom/libs/dwarf-20071209/libdwarf/dwarf_addr_finder.c	Fri Jan 15 09:07:44 2010 +0000
@@ -0,0 +1,688 @@
+/*
+
+  Copyright (C) 2000,2002,2004 Silicon Graphics, Inc.  All Rights Reserved.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms of version 2.1 of the GNU Lesser General Public License 
+  as published by the Free Software Foundation.
+
+  This program is distributed in the hope that it would be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+
+  Further, this software is distributed without any warranty that it is
+  free of the rightful claim of any third person regarding infringement 
+  or the like.  Any license provided herein, whether implied or 
+  otherwise, applies only to this software file.  Patent licenses, if
+  any, provided herein do not apply to combinations of this program with 
+  other software, or any other product whatsoever.  
+
+  You should have received a copy of the GNU Lesser General Public 
+  License along with this program; if not, write the Free Software 
+  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
+  USA.
+
+  Contact information:  Silicon Graphics, Inc., 1500 Crittenden Lane,
+  Mountain View, CA 94043, or:
+
+  http://www.sgi.com
+
+  For further information regarding this notice, see:
+
+  http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+*/
+/* This code used by SGI-IRIX rqs processing, not needed by
+   any other system or application.
+*/
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#ifdef HAVE_ELF_H
+#include <elf.h>
+#endif
+#include <dwarf.h>
+#include <libdwarf.h>
+#include "dwarf_base_types.h"
+#include "dwarf_alloc.h"
+#include "dwarf_opaque.h"
+#include "dwarf_arange.h"
+#include "dwarf_line.h"
+#include "dwarf_frame.h"
+#include <cmplrs/dwarf_addr_finder.h>
+#include "dwarf_error.h"
+
+typedef unsigned long long ull;
+
+static int do_this_die_and_dealloc(Dwarf_Debug dbg, Dwarf_Die die,
+				   int *errval);
+static int
+  handle_debug_info(Dwarf_Debug dbg, int *errval);
+static int
+  handle_debug_frame(Dwarf_Debug dbg, Dwarf_addr_callback_func cb_func, int *errval);
+static int
+  handle_debug_aranges(Dwarf_Debug dbg, Dwarf_addr_callback_func cb_func, int *errval);
+static int
+  handle_debug_line(Dwarf_Debug dbg, Dwarf_Die cu_die, Dwarf_addr_callback_func cb_func, int *errval);
+static int
+  handle_debug_loc(void);
+
+
+static Dwarf_addr_callback_func send_addr_note;
+
+int
+_dwarf_addr_finder(dwarf_elf_handle elf_file_ptr,
+		   Dwarf_addr_callback_func cb_func, int *dwerr)
+{
+
+    Dwarf_Error err = 0;
+    Dwarf_Debug dbg = 0;
+    int res = 0;
+    int errval = 0;
+    int sections_found = 0;
+
+    res = dwarf_elf_init(elf_file_ptr, DW_DLC_READ, /* errhand */ 0,
+			 /* errarg */ 0, &dbg, &err);
+    if (res == DW_DLV_ERROR) {
+	int errv = (int) dwarf_errno(err);
+
+	return errv;
+    }
+    if (res == DW_DLV_NO_ENTRY) {
+	return res;
+    }
+
+    send_addr_note = cb_func;
+
+    res = handle_debug_info(dbg, &errval);
+    switch (res) {
+    case DW_DLV_OK:
+	++sections_found;
+	break;
+    case DW_DLV_NO_ENTRY:
+
+	break;
+    default:
+    case DW_DLV_ERROR:
+	dwarf_finish(dbg, &err);
+	*dwerr = errval;
+	return res;
+    }
+
+    res = handle_debug_aranges(dbg, cb_func, &errval);
+    switch (res) {
+    case DW_DLV_OK:
+	++sections_found;
+	break;
+    case DW_DLV_NO_ENTRY:
+	break;
+    default:
+    case DW_DLV_ERROR:
+	dwarf_finish(dbg, &err);
+	*dwerr = errval;
+	return res;
+    }
+    res = handle_debug_frame(dbg, cb_func, &errval);
+    switch (res) {
+    case DW_DLV_OK:
+	++sections_found;
+	break;
+    case DW_DLV_NO_ENTRY:
+	break;
+    default:
+    case DW_DLV_ERROR:
+	dwarf_finish(dbg, &err);
+	*dwerr = errval;
+	return res;
+    }
+
+    res = handle_debug_loc();	/* does nothing */
+    switch (res) {
+    case DW_DLV_OK:
+	++sections_found;
+	break;
+    case DW_DLV_NO_ENTRY:
+	break;
+    default:
+    case DW_DLV_ERROR:
+	/* IMPOSSIBLE : handle_debug_loc cannot return this */
+	dwarf_finish(dbg, &err);
+	*dwerr = errval;
+	return res;
+    }
+
+
+
+    *dwerr = 0;
+    res = dwarf_finish(dbg, &err);
+    if (res == DW_DLV_ERROR) {
+	*dwerr = (int) dwarf_errno(err);
+	return DW_DLV_ERROR;
+    }
+    if (sections_found == 0) {
+	return DW_DLV_NO_ENTRY;
+    }
+    return DW_DLV_OK;
+
+}
+
+/*
+	Return DW_DLV_OK, ERROR, or NO_ENTRY.
+*/
+static int
+handle_debug_info(Dwarf_Debug dbg, int *errval)
+{
+    Dwarf_Unsigned nxtoff = 1;
+    Dwarf_Unsigned hdr_length;
+    Dwarf_Half version_stamp;
+    Dwarf_Unsigned abbrev_offset;
+    Dwarf_Half addr_size;
+    Dwarf_Error err;
+    int terminate_now = 0;
+    int res = 0;
+    Dwarf_Die sibdie;
+    int sibres;
+    int nres = DW_DLV_OK;
+
+
+    for (nres = dwarf_next_cu_header(dbg, &hdr_length, &version_stamp,
+				     &abbrev_offset,
+				     &addr_size, &nxtoff, &err);
+	 terminate_now == 0 && nres == DW_DLV_OK;
+	 nres = dwarf_next_cu_header(dbg, &hdr_length, &version_stamp,
+				     &abbrev_offset,
+				     &addr_size, &nxtoff, &err)
+	) {
+
+	Dwarf_Die curdie = 0;
+
+	/* try to get the compilation unit die */
+	sibres = dwarf_siblingof(dbg, curdie, &sibdie, &err);
+	if (sibres == DW_DLV_OK) {
+	    res = do_this_die_and_dealloc(dbg, sibdie, errval);
+	    switch (res) {
+	    case DW_DLV_OK:
+		break;
+	    case DW_DLV_NO_ENTRY:
+		break;
+	    default:
+	    case DW_DLV_ERROR:
+		return DW_DLV_ERROR;
+	    }
+	} else if (sibres == DW_DLV_ERROR) {
+	    *errval = (int) dwarf_errno(err);
+	    return DW_DLV_ERROR;
+	} else {
+	    /* NO ENTRY! */
+	    /* impossible? */
+	}
+
+    }
+    if (nres == DW_DLV_ERROR) {
+	int localerr = (int) dwarf_errno(err);
+
+	*errval = localerr;
+	return DW_DLV_ERROR;
+    }
+    return DW_DLV_OK;
+}
+
+static int
+  might_have_addr[] = {
+    DW_AT_high_pc,
+    DW_AT_low_pc,
+};
+static int
+  might_have_locdesc[] = {
+    DW_AT_segment,
+    DW_AT_return_addr,
+    DW_AT_frame_base,
+    DW_AT_static_link,
+    DW_AT_data_member_location,
+    DW_AT_string_length,
+    DW_AT_location,
+    DW_AT_use_location,
+    DW_AT_vtable_elem_location,
+};
+
+/*
+	Return DW_DLV_OK if handling this went ok.
+*/
+static int
+handle_attr_addr(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Half attrnum,
+		 Dwarf_Error * perr)
+{
+    int res = DW_DLV_OK;
+    Dwarf_Off offset;
+    Dwarf_Addr addr;
+    Dwarf_Half form;
+    int ares;
+
+    Dwarf_Attribute attr;
+
+    ares = dwarf_attr(die, attrnum, &attr, perr);
+    if (ares == DW_DLV_OK) {
+	int formres = dwarf_whatform(attr, &form, perr);
+
+	switch (formres) {
+	case DW_DLV_OK:
+	    break;
+	case DW_DLV_ERROR:
+	case DW_DLV_NO_ENTRY:	/* impossible. */
+	    return formres;
+
+	}
+
+	switch (form) {
+	case DW_FORM_ref_addr:
+	case DW_FORM_addr:
+	    res = dwarf_attr_offset(die, attr, &offset, perr);
+	    if (res == DW_DLV_OK) {
+		ares = dwarf_formaddr(attr, &addr, perr);
+		if (ares == DW_DLV_OK) {
+		    send_addr_note(DW_SECTION_INFO, offset, addr);
+		} else if (ares == DW_DLV_ERROR) {
+		    return ares;
+		}		/* no entry: ok. */
+	    } else {
+		res = DW_DLV_ERROR;	/* NO_ENTRY is impossible. */
+	    }
+	    break;
+
+	default:
+	    /* surprising! An error? */
+
+	    ;			/* do nothing */
+	}
+	dwarf_dealloc(dbg, attr, DW_DLA_ATTR);
+
+    } else {
+	res = ares;
+    }
+    return res;
+}
+
+/*
+	Return DW_DLV_OK if handling this went ok.
+*/
+static int
+handle_attr_locdesc(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Half attrnum,
+		    Dwarf_Error * perr)
+{
+    int retval = DW_DLV_OK;
+    Dwarf_Attribute attr;
+    Dwarf_Locdesc *llbuf;
+    Dwarf_Signed i;
+    Dwarf_Off offset;
+    Dwarf_Loc *locp;
+    unsigned int entindx;
+    int res;
+    int ares;
+
+
+    ares = dwarf_attr(die, attrnum, &attr, perr);
+    if (ares == DW_DLV_OK) {
+	Dwarf_Half form;
+	int fres = dwarf_whatform(attr, &form, perr);
+
+	if (fres == DW_DLV_OK) {
+	    switch (form) {
+	    case DW_FORM_block1:
+	    case DW_FORM_block2:
+	    case DW_FORM_block4:
+		/* must be location description */
+		res = dwarf_attr_offset(die, attr, &offset, perr);
+		llbuf = 0;
+		if (res == DW_DLV_OK) {
+		    Dwarf_Signed count;
+		    int lres =
+			dwarf_loclist(attr, &llbuf, &count, perr);
+		    if (lres != DW_DLV_OK) {
+			return lres;
+		    }
+		    if (count != 1) {
+			/* this cannot happen! */
+			/* perr? */
+			_dwarf_error(dbg, perr,
+				     DW_DLE_LOCDESC_COUNT_WRONG);
+			retval = DW_DLV_ERROR;
+			return retval;
+		    }
+		    for (i = 0; i < count; ++i) {
+			unsigned int ents = llbuf[i].ld_cents;
+
+			locp = llbuf[i].ld_s;
+			for (entindx = 0; entindx < ents; entindx++) {
+			    Dwarf_Loc *llocp;
+
+			    llocp = locp + entindx;
+			    if (llocp->lr_atom == DW_OP_addr) {
+				send_addr_note(DW_SECTION_INFO, offset +
+					       llocp->lr_offset + 1
+					       /* The offset is the
+					          offset of the atom,
+					          ** and we know the
+					          addr is 1 past it. */
+					       , llocp->lr_number);
+			    }
+			}
+		    }
+
+
+		    if (count > 0) {
+			for (i = 0; i < count; ++i) {
+			    dwarf_dealloc(dbg, llbuf[i].ld_s,
+					  DW_DLA_LOC_BLOCK);
+			}
+			dwarf_dealloc(dbg, llbuf, DW_DLA_LOCDESC);
+		    }
+		} else {
+		    retval = res;
+		}
+		break;
+
+	    default:
+		/* must be a const offset in debug_loc */
+		;		/* do nothing */
+	    }
+	    dwarf_dealloc(dbg, attr, DW_DLA_ATTR);
+	}			/* else error or no entry */
+	retval = fres;
+    } else {
+	retval = ares;
+    }
+    return retval;
+}
+
+/*
+  Return DW_DLV_OK, or DW_DLV_ERROR
+
+  Handle the addrs in a single die.
+*/
+static int
+process_this_die_attrs(Dwarf_Debug dbg, Dwarf_Die newdie, int *errval)
+{
+    Dwarf_Error err;
+    Dwarf_Half i;
+    Dwarf_Half newattrnum;
+    int res;
+    int tres;
+    Dwarf_Half ltag;
+
+    Dwarf_Off doff;
+    int doffres = dwarf_dieoffset(newdie, &doff, &err);
+
+    if (doffres != DW_DLV_OK) {
+	if (doffres == DW_DLV_ERROR) {
+	    *errval = (int) dwarf_errno(err);
+	}
+	return doffres;
+    }
+    tres = dwarf_tag(newdie, &ltag, &err);
+    if (tres != DW_DLV_OK) {
+	return tres;
+    }
+    if (DW_TAG_compile_unit == ltag) {
+	/* because of the way the dwarf_line code works, we do lines 
+	   only per compile unit. This may turn out to be wrong if
+	   we have lines left unconnected to a CU. of course such 
+	   lines will not, at present, be used by gnome. This is
+	   not ideal as coded due to the dwarf_line.c issue. */
+	int lres;
+
+	lres = handle_debug_line(dbg, newdie, send_addr_note, errval);
+	if (lres == DW_DLV_ERROR) {
+	    return lres;
+	}
+    }
+
+    for (i = 0; i < sizeof(might_have_addr) / sizeof(int); i++) {
+	int resattr;
+	Dwarf_Bool hasattr;
+
+	newattrnum = might_have_addr[i];
+	err = 0;
+	resattr = dwarf_hasattr(newdie, newattrnum, &hasattr, &err);
+	if (DW_DLV_OK == resattr) {
+	    if (hasattr) {
+		res = handle_attr_addr(dbg, newdie, newattrnum, &err);
+		if (res != DW_DLV_OK) {
+		    *errval = (int) dwarf_errno(err);
+		    return DW_DLV_ERROR;
+		}
+	    }
+	} else {
+	    if (resattr == DW_DLV_ERROR) {
+		*errval = (int) dwarf_errno(err);
+		return resattr;
+	    }
+	}
+    }
+    for (i = 0; i < sizeof(might_have_locdesc) / sizeof(int); i++) {
+	int resattr;
+	Dwarf_Bool hasattr;
+
+	newattrnum = might_have_locdesc[i];
+	err = 0;
+	resattr = dwarf_hasattr(newdie, newattrnum, &hasattr, &err);
+	if (DW_DLV_OK == resattr) {
+	    if (hasattr) {
+		res =
+		    handle_attr_locdesc(dbg, newdie, newattrnum, &err);
+		if (res != DW_DLV_OK) {
+		    *errval = (int) dwarf_errno(err);
+		    return DW_DLV_ERROR;
+		}
+	    }
+	} else {
+	    if (resattr == DW_DLV_ERROR) {
+		*errval = (int) dwarf_errno(err);
+		return resattr;
+	    }
+	}
+    }
+
+    return DW_DLV_OK;
+}
+
+/*
+	Handle siblings as a list,
+	Do children by recursing.
+	Effectively this is walking the tree preorder.
+
+	This dealloc's any die passed to it, so the
+	caller should not do that dealloc.
+	It seems more logical to have the one causing
+	the alloc to do the dealloc, but that way this
+	routine became a mess.
+
+*/
+static int
+do_this_die_and_dealloc(Dwarf_Debug dbg, Dwarf_Die die, int *errval)
+{
+
+    Dwarf_Die prevdie = 0;
+    Dwarf_Die newdie = die;
+    Dwarf_Error err = 0;
+    int res = 0;
+    int sibres = DW_DLV_OK;
+    int tres = DW_DLV_OK;
+    Dwarf_Die sibdie;
+
+    while (sibres == DW_DLV_OK) {
+	Dwarf_Die ch_die;
+
+
+	res = process_this_die_attrs(dbg, newdie, errval);
+	switch (res) {
+	case DW_DLV_OK:
+	    break;
+	case DW_DLV_NO_ENTRY:
+	    break;
+	default:
+	case DW_DLV_ERROR:
+	    if (prevdie) {
+		dwarf_dealloc(dbg, prevdie, DW_DLA_DIE);
+		prevdie = 0;
+	    }
+	    return DW_DLV_ERROR;
+	}
+
+	tres = dwarf_child(newdie, &ch_die, &err);
+
+	if (tres == DW_DLV_OK) {
+	    res = do_this_die_and_dealloc(dbg, ch_die, errval);
+	    switch (res) {
+	    case DW_DLV_OK:
+		break;
+	    case DW_DLV_NO_ENTRY:
+		break;
+	    default:
+	    case DW_DLV_ERROR:
+		if (prevdie) {
+		    dwarf_dealloc(dbg, prevdie, DW_DLA_DIE);
+		    prevdie = 0;
+		}
+		return DW_DLV_ERROR;
+	    }
+	} else if (tres == DW_DLV_ERROR) {
+	    /* An error! */
+	    *errval = (int) dwarf_errno(err);
+	    if (prevdie) {
+		dwarf_dealloc(dbg, prevdie, DW_DLA_DIE);
+		prevdie = 0;
+	    }
+	    dwarf_dealloc(dbg, err, DW_DLA_ERROR);
+	    return DW_DLV_ERROR;
+	}			/* else was NO ENTRY */
+	prevdie = newdie;
+	sibdie = 0;
+	sibres = dwarf_siblingof(dbg, newdie, &sibdie, &err);
+	if (prevdie) {
+	    dwarf_dealloc(dbg, prevdie, DW_DLA_DIE);
+	    prevdie = 0;
+	}
+	newdie = sibdie;
+
+    }
+    if (sibres == DW_DLV_NO_ENTRY) {
+	return DW_DLV_OK;
+    }
+    /* error. */
+    *errval = (int) dwarf_errno(err);
+    if (prevdie) {
+	dwarf_dealloc(dbg, prevdie, DW_DLA_DIE);
+	prevdie = 0;
+    }
+    dwarf_dealloc(dbg, err, DW_DLA_ERROR);
+    return DW_DLV_ERROR;
+
+}
+
+
+static int
+handle_debug_frame(Dwarf_Debug dbg, Dwarf_addr_callback_func cb_func,
+		   int *errval)
+{
+    int retval = DW_DLV_OK;
+    int res;
+    Dwarf_Error err;
+    Dwarf_Addr *addrlist;
+    Dwarf_Off *offsetlist;
+    Dwarf_Signed count;
+    int i;
+
+    res =
+	_dwarf_frame_address_offsets(dbg, &addrlist, &offsetlist,
+				     &count, &err);
+    if (res == DW_DLV_OK) {
+	for (i = 0; i < count; i++) {
+	    cb_func(DW_SECTION_FRAME, offsetlist[i], addrlist[i]);
+	}
+	dwarf_dealloc(dbg, offsetlist, DW_DLA_ADDR);
+	dwarf_dealloc(dbg, addrlist, DW_DLA_ADDR);
+    } else if (res == DW_DLV_NO_ENTRY) {
+	retval = res;
+    } else {
+	*errval = (int) dwarf_errno(err);
+	retval = DW_DLV_ERROR;
+    }
+    return retval;
+
+}
+static int
+handle_debug_aranges(Dwarf_Debug dbg, Dwarf_addr_callback_func cb_func,
+		     int *errval)
+{
+    int retval = DW_DLV_OK;
+    Dwarf_Error err;
+    Dwarf_Addr *aranges;
+    Dwarf_Signed count;
+    int indx;
+    Dwarf_Off *offsets;
+
+    retval =
+	_dwarf_get_aranges_addr_offsets(dbg, &aranges, &offsets, &count,
+					&err);
+    if (retval == DW_DLV_OK) {
+	if (count == 0) {
+	    retval = DW_DLV_NO_ENTRY;
+	} else {
+	    for (indx = 0; indx < count; indx++) {
+		cb_func(DW_SECTION_ARANGES, offsets[indx],
+			aranges[indx]);
+	    }
+	}
+	dwarf_dealloc(dbg, aranges, DW_DLA_ADDR);
+	dwarf_dealloc(dbg, offsets, DW_DLA_ADDR);
+    } else if (retval == DW_DLV_NO_ENTRY) {
+	;			/* do nothing */
+    } else {
+	*errval = (int) dwarf_errno(err);
+	retval = DW_DLV_ERROR;
+    }
+    return retval;
+}
+static int
+handle_debug_line(Dwarf_Debug dbg, Dwarf_Die cu_die,
+		  Dwarf_addr_callback_func cb_func, int *errval)
+{
+    int retval = DW_DLV_OK;
+    int res;
+    Dwarf_Error err;
+    Dwarf_Addr *addrlist;
+    Dwarf_Off *offsetlist;
+    Dwarf_Unsigned count;
+    Dwarf_Unsigned i;
+
+    res =
+	_dwarf_line_address_offsets(dbg, cu_die, &addrlist, &offsetlist,
+				    &count, &err);
+    if (res == DW_DLV_OK) {
+	for (i = 0; i < count; i++) {
+	    cb_func(DW_SECTION_LINE, offsetlist[i], addrlist[i]);
+
+	}
+	dwarf_dealloc(dbg, offsetlist, DW_DLA_ADDR);
+	dwarf_dealloc(dbg, addrlist, DW_DLA_ADDR);
+    } else if (res == DW_DLV_NO_ENTRY) {
+	retval = res;
+    } else {
+	*errval = (int) dwarf_errno(err);
+	retval = DW_DLV_ERROR;
+    }
+    return retval;
+}
+
+/*
+	We need to add support for this. Currently we do not
+	generate this section.
+	FIX!
+*/
+static int
+handle_debug_loc(void)
+{
+    int retval = DW_DLV_NO_ENTRY;
+
+    return retval;
+}