tools/elf4rom/libs/dwarf-20071209/dwarfdump/print_die.c
changeset 34 92d87f2e53c2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/elf4rom/libs/dwarf-20071209/dwarfdump/print_die.c	Fri Jan 15 09:07:44 2010 +0000
@@ -0,0 +1,1313 @@
+/* 
+  Copyright (C) 2000,2004,2005,2006 Silicon Graphics, Inc.  All Rights Reserved.
+  Portions Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+  Portions Copyright 2007 David Anderson. All rights reserved.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms of version 2 of the GNU 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 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
+
+
+$ Header: /plroot/cmplrs.src/v7.4.5m/.RCS/PL/dwarfdump/RCS/print_die.c,v 1.51 2006/04/01 16:20:21 davea Exp $ */
+
+#include "globals.h"
+#include "dwarf_names.h"
+#include "esb.h"		/* For flexible string buffer. */
+#include "makename.h"		/* Non-duplicating string table. */
+
+static void get_attr_value(Dwarf_Debug dbg, Dwarf_Half tag,
+			   Dwarf_Attribute attrib, 
+                           char **srcfiles,
+			   Dwarf_Signed cnt, struct esb_s *esbp);
+static void print_attribute(Dwarf_Debug dbg, Dwarf_Die die,
+			    Dwarf_Half attr,
+			    Dwarf_Attribute actual_addr,
+			    boolean print_information, char **srcfiles,
+			    Dwarf_Signed cnt);
+static void get_location_list(Dwarf_Debug dbg, Dwarf_Die die,
+			      Dwarf_Attribute attr, struct esb_s *esbp);
+static int tag_attr_combination(Dwarf_Half tag, Dwarf_Half attr);
+static int _dwarf_print_one_expr_op(Dwarf_Debug dbg,Dwarf_Loc* expr,int index, struct esb_s *string_out);
+
+/* esb_base is static so gets initialized to zeros.  
+   It is not thread-safe or
+   safe for multiple open producer instances for
+   but that does not matter here in dwarfdump.
+
+   The memory used by esb_base is never freed.
+*/
+static struct esb_s esb_base;	
+
+static int indent_level = 0;
+static boolean local_symbols_already_began = FALSE;
+
+typedef string(*encoding_type_func) (Dwarf_Debug dbg, Dwarf_Half val);
+
+Dwarf_Off fde_offset_for_cu_low = DW_DLV_BADOFFSET;
+Dwarf_Off fde_offset_for_cu_high = DW_DLV_BADOFFSET;
+
+/* Dwarf_Half list_of_attrs[] */
+/*#include "at_list.i" unreferenced */
+
+#define DIE_STACK_SIZE 300
+static Dwarf_Die die_stack[DIE_STACK_SIZE];
+
+#define PUSH_DIE_STACK(x) { die_stack[indent_level] = x; }
+#define POP_DIE_STACK { die_stack[indent_level] = 0; }
+
+#include "_tag_tree_table.c"
+
+/*
+   Look only at valid table entries
+   The check here must match the building-logic in
+   tag_tree.c
+   And must match the tags defined in dwarf.h
+*/
+#define MAX_CHECKED_TAG_ID 0x35
+static int
+tag_tree_combination(Dwarf_Half tag_parent, Dwarf_Half tag_child)
+{
+    if (tag_parent > 0 && tag_parent <= MAX_CHECKED_TAG_ID
+	&& tag_child > 0 && tag_child <= MAX_CHECKED_TAG_ID) {
+	return ((tag_tree_combination_table[tag_parent]
+		 [tag_child / 0x20]
+		 & (1 << (tag_child % 0x20))) > 0 ? TRUE : FALSE);
+    } else
+	return (FALSE);
+}
+
+/* recursively follow the die tree */
+extern void
+print_die_and_children(Dwarf_Debug dbg, Dwarf_Die in_die_in,
+		       char **srcfiles, Dwarf_Signed cnt)
+{
+    Dwarf_Die child;
+    Dwarf_Die sibling;
+    Dwarf_Error err;
+    int tres;
+    int cdres;
+    Dwarf_Die in_die = in_die_in;
+
+    for (;;) {
+	PUSH_DIE_STACK(in_die);
+
+	if (check_tag_tree) {
+	    tag_tree_result.checks++;
+	    if (indent_level == 0) {
+		Dwarf_Half tag;
+
+		tres = dwarf_tag(in_die, &tag, &err);
+		if (tres != DW_DLV_OK) {
+		    tag_tree_result.errors++;
+		    DWARF_CHECK_ERROR
+			("Tag-tree root is not DW_TAG_compile_unit")
+		} else if (tag == DW_TAG_compile_unit) {
+		    /* OK */
+		} else {
+		    tag_tree_result.errors++;
+		    DWARF_CHECK_ERROR
+			("tag-tree root is not DW_TAG_compile_unit")
+		}
+	    } else {
+		Dwarf_Half tag_parent, tag_child;
+		int pres;
+		int cres;
+		char *ctagname = "<child tag invalid>";
+		char *ptagname = "<parent tag invalid>";
+
+		pres =
+		    dwarf_tag(die_stack[indent_level - 1], &tag_parent,
+			      &err);
+		cres = dwarf_tag(in_die, &tag_child, &err);
+		if (pres != DW_DLV_OK)
+		    tag_parent = 0;
+		if (cres != DW_DLV_OK)
+		    tag_child = 0;
+		if (cres != DW_DLV_OK || pres != DW_DLV_OK) {
+		    if (cres == DW_DLV_OK) {
+			ctagname = get_TAG_name(dbg, tag_child);
+		    }
+		    if (pres == DW_DLV_OK) {
+			ptagname = get_TAG_name(dbg, tag_parent);
+		    }
+		    DWARF_CHECK_ERROR3(ptagname,
+				       ctagname,
+				       "Tag-tree relation is not standard..");
+		} else if (tag_tree_combination(tag_parent, tag_child)) {
+		    /* OK */
+		} else {
+		    DWARF_CHECK_ERROR3(get_TAG_name(dbg, tag_parent),
+				       get_TAG_name(dbg, tag_child),
+				       "tag-tree relation is not standard.");
+		}
+	    }
+	}
+
+	/* here to pre-descent processing of the die */
+	print_one_die(dbg, in_die, info_flag, srcfiles, cnt);
+
+	cdres = dwarf_child(in_die, &child, &err);
+	/* child first: we are doing depth-first walk */
+	if (cdres == DW_DLV_OK) {
+	    indent_level++;
+	    if(indent_level >= DIE_STACK_SIZE ) {
+	        print_error(dbg,
+                  "compiled in DIE_STACK_SIZE limit exceeded",
+                  DW_DLV_OK,err);
+	    }
+	    print_die_and_children(dbg, child, srcfiles, cnt);
+	    indent_level--;
+	    if (indent_level == 0)
+		local_symbols_already_began = FALSE;
+	    dwarf_dealloc(dbg, child, DW_DLA_DIE);
+	} else if (cdres == DW_DLV_ERROR) {
+	    print_error(dbg, "dwarf_child", cdres, err);
+	}
+
+	cdres = dwarf_siblingof(dbg, in_die, &sibling, &err);
+	if (cdres == DW_DLV_OK) {
+	    /* print_die_and_children(dbg, sibling, srcfiles, cnt); We
+	       loop around to actually print this, rather than
+	       recursing. Recursing is horribly wasteful of stack
+	       space. */
+	} else if (cdres == DW_DLV_ERROR) {
+	    print_error(dbg, "dwarf_siblingof", cdres, err);
+	}
+
+	/* Here do any post-descent (ie post-dwarf_child) processing of 
+	   the in_die. */
+
+	POP_DIE_STACK;
+	if (in_die != in_die_in) {
+	    /* Dealloc our in_die, but not the argument die, it belongs 
+	       to our caller. Whether the siblingof call worked or not. 
+	     */
+	    dwarf_dealloc(dbg, in_die, DW_DLA_DIE);
+	}
+	if (cdres == DW_DLV_OK) {
+	    /* Set to process the sibling, loop again. */
+	    in_die = sibling;
+	} else {
+	    /* We are done, no more siblings at this level. */
+
+	    break;
+	}
+    }				/* end for loop on siblings */
+    return;
+}
+
+#define SPACE(x) { register int i; for (i=0;i<x;i++) putchar(' '); }
+
+
+/* print info about die */
+void
+print_one_die(Dwarf_Debug dbg, Dwarf_Die die, boolean print_information,
+	      char **srcfiles, Dwarf_Signed cnt)
+{
+    Dwarf_Signed i;
+    Dwarf_Off offset, overall_offset;
+    string tagname;
+    Dwarf_Half tag;
+    Dwarf_Signed atcnt;
+    Dwarf_Attribute *atlist;
+    int tres;
+    int ores;
+    int atres;
+
+    tres = dwarf_tag(die, &tag, &err);
+    if (tres != DW_DLV_OK) {
+	print_error(dbg, "accessing tag of die!", tres, err);
+    }
+    tagname = get_TAG_name(dbg, tag);
+    ores = dwarf_dieoffset(die, &overall_offset, &err);
+    if (ores != DW_DLV_OK) {
+	print_error(dbg, "dwarf_dieoffset", ores, err);
+    }
+    ores = dwarf_die_CU_offset(die, &offset, &err);
+    if (ores != DW_DLV_OK) {
+	print_error(dbg, "dwarf_die_CU_offset", ores, err);
+    }
+
+    if (!dst_format && print_information) {
+	if (indent_level == 0) {
+	    if (dense)
+		printf("\n");
+	    else {
+		printf
+		    ("\nCOMPILE_UNIT<header overall offset = %llu>:\n",
+		     overall_offset - offset);
+	    }
+	} else if (local_symbols_already_began == FALSE &&
+		   indent_level == 1 && !dense) {
+	    printf("\nLOCAL_SYMBOLS:\n");
+	    local_symbols_already_began = TRUE;
+	}
+	if (dense) {
+            if (show_global_offsets) {
+	        if (indent_level == 0) {
+		    printf("<%d><%llu+%llu GOFF=%llu><%s>", indent_level,
+		       overall_offset - offset, offset,
+                       overall_offset, tagname);
+	        } else {
+		    printf("<%d><%llu GOFF=%llu><%s>", indent_level, 
+                       offset, overall_offset, tagname);
+	        }
+            } else {
+	        if (indent_level == 0) {
+		    printf("<%d><%llu+%llu><%s>", indent_level,
+		       overall_offset - offset, offset, tagname);
+	        } else {
+		    printf("<%d><%llu><%s>", indent_level, offset, tagname);
+	        }
+	    }
+	} else {
+            if (show_global_offsets) {
+	        printf("<%d><%5llu GOFF=%llu>\t%s\n", indent_level, offset,
+                    overall_offset, tagname);
+            } else {
+	        printf("<%d><%5llu>\t%s\n", indent_level, offset, tagname);
+	    }
+	}
+    }
+
+    atres = dwarf_attrlist(die, &atlist, &atcnt, &err);
+    if (atres == DW_DLV_ERROR) {
+	print_error(dbg, "dwarf_attrlist", atres, err);
+    } else if (atres == DW_DLV_NO_ENTRY) {
+	/* indicates there are no attrs.  It is not an error. */
+	atcnt = 0;
+    }
+
+
+    for (i = 0; i < atcnt; i++) {
+	Dwarf_Half attr;
+	int ares;
+
+	ares = dwarf_whatattr(atlist[i], &attr, &err);
+	if (ares == DW_DLV_OK) {
+	    print_attribute(dbg, die, attr,
+			    atlist[i],
+			    print_information, srcfiles, cnt);
+	} else {
+	    print_error(dbg, "dwarf_whatattr entry missing", ares, err);
+	}
+    }
+
+    for (i = 0; i < atcnt; i++) {
+	dwarf_dealloc(dbg, atlist[i], DW_DLA_ATTR);
+    }
+    if (atres == DW_DLV_OK) {
+	dwarf_dealloc(dbg, atlist, DW_DLA_LIST);
+    }
+
+    if (dense && print_information) {
+	printf("\n\n");
+    }
+    return;
+}
+
+/* Encodings have undefined signedness. Accept either
+   signedness.  The values are small (they are defined
+   in the DWARF specification), so the
+   form the compiler uses (as long as it is
+   a constant value) is a non-issue.
+
+   If string_out is non-NULL, construct a string output, either
+   an error message or the name of the encoding.
+   The function pointer passed in is to code generated
+   by a script at dwarfdump build time. The code for
+   the val_as_string function is generated
+   from dwarf.h.  See <build dir>/dwarf_names.c
+
+   If string_out is non-NULL then attr_name and val_as_string
+   must also be non-NULL.
+
+*/
+int
+get_small_encoding_integer_and_name(Dwarf_Debug dbg,
+				    Dwarf_Attribute attrib,
+				    Dwarf_Unsigned * uval_out,
+				    char *attr_name,
+				    string * string_out,
+				    encoding_type_func val_as_string,
+				    Dwarf_Error * err)
+{
+    Dwarf_Unsigned uval = 0;
+    char buf[100];		/* The strings are small. */
+    int vres = dwarf_formudata(attrib, &uval, err);
+
+    if (vres != DW_DLV_OK) {
+	Dwarf_Signed sval = 0;
+
+	vres = dwarf_formsdata(attrib, &sval, err);
+	if (vres != DW_DLV_OK) {
+	    if (string_out != 0) {
+		snprintf(buf, sizeof(buf),
+			 "%s has a bad form.", attr_name);
+		*string_out = makename(buf);
+	    }
+	    return vres;
+	}
+	*uval_out = (Dwarf_Unsigned) sval;
+    } else {
+	*uval_out = uval;
+    }
+    if (string_out)
+	*string_out = val_as_string(dbg, (Dwarf_Half) uval);
+
+    return DW_DLV_OK;
+
+}
+
+
+
+
+/*
+ * We need a 32-bit signed number here, but there's no portable
+ * way of getting that.  So use __uint32_t instead.  It's supplied
+ * in a reliable way by the autoconf infrastructure.
+ */
+
+static void
+get_FLAG_BLOCK_string(Dwarf_Debug dbg, Dwarf_Attribute attrib)
+{
+    int fres = 0;
+    Dwarf_Block *tempb = 0;
+    __uint32_t * array = 0;
+    Dwarf_Unsigned array_len = 0;
+    __uint32_t * array_ptr;
+    Dwarf_Unsigned array_remain = 0;
+    char linebuf[100];
+
+    esb_empty_string(&esb_base);
+    esb_append(&esb_base, "\n");
+
+    /* first get compressed block data */
+    fres = dwarf_formblock (attrib,&tempb, &err);
+    if (fres != DW_DLV_OK) {
+	print_error(dbg,"DW_FORM_blockn cannot get block\n",fres,err);
+	return;
+    }
+
+    /* uncompress block into int array */
+    array = dwarf_uncompress_integer_block(dbg,
+			   1, /* 'true' (meaning signed ints)*/
+			   32, /* bits per unit */
+			   tempb->bl_data,
+			   tempb->bl_len,
+			   &array_len, /* len of out array */
+			   &err);
+    if (array == (void*) DW_DLV_BADOFFSET) {
+	print_error(dbg,"DW_AT_SUN_func_offsets cannot uncompress data\n",0,err);
+	return;
+    }
+    if (array_len == 0) {
+	print_error(dbg,"DW_AT_SUN_func_offsets has no data\n",0,err);
+	return;
+    }
+    
+    /* fill in string buffer */
+    array_remain = array_len;
+    array_ptr = array;
+    while (array_remain > 8) {
+	/* print a full line */
+	/* if you touch this string, update the magic number 78 below! */
+	snprintf(linebuf, sizeof(linebuf), 
+		"\n  %8x %8x %8x %8x %8x %8x %8x %8x",
+		array_ptr[0],		array_ptr[1],
+		array_ptr[2],		array_ptr[3],
+		array_ptr[4],		array_ptr[5],
+		array_ptr[6],		array_ptr[7]);
+	array_ptr += 8;
+	array_remain -= 8;
+	esb_append(&esb_base, linebuf);
+    }
+
+    /* now do the last line */
+    if (array_remain > 0) {
+	esb_append(&esb_base, "\n ");
+	while (array_remain > 0) {
+	    snprintf(linebuf, sizeof(linebuf), " %8x", *array_ptr);
+	    array_remain--;
+	    array_ptr++;
+	    esb_append(&esb_base, linebuf);
+	}
+    }
+    
+    /* free array buffer */
+    dwarf_dealloc_uncompressed_block(dbg, array);
+
+}
+
+static void
+print_attribute(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Half attr,
+		Dwarf_Attribute attr_in,
+		boolean print_information,
+		char **srcfiles, Dwarf_Signed cnt)
+{
+    Dwarf_Attribute attrib = 0;
+    Dwarf_Unsigned uval = 0;
+    string atname = 0;
+    string valname = 0;
+    int tres = 0;
+    Dwarf_Half tag = 0;
+
+    atname = get_AT_name(dbg, attr);
+
+    /* the following gets the real attribute, even in the face of an 
+       incorrect doubling, or worse, of attributes */
+    attrib = attr_in;
+    /* do not get attr via dwarf_attr: if there are (erroneously) 
+       multiple of an attr in a DIE, dwarf_attr will not get the
+       second, erroneous one and dwarfdump will print the first one
+       multiple times. Oops. */
+
+    tres = dwarf_tag(die, &tag, &err);
+    if (tres == DW_DLV_ERROR) {
+	tag = 0;
+    } else if (tres == DW_DLV_NO_ENTRY) {
+	tag = 0;
+    } else {
+	/* ok */
+    }
+    if (check_attr_tag) {
+	char *tagname = "<tag invalid>";
+
+	attr_tag_result.checks++;
+	if (tres == DW_DLV_ERROR) {
+	    attr_tag_result.errors++;
+	    DWARF_CHECK_ERROR3(tagname,
+			       get_AT_name(dbg, attr),
+			       "check the tag-attr combination.");
+	} else if (tres == DW_DLV_NO_ENTRY) {
+	    attr_tag_result.errors++;
+	    DWARF_CHECK_ERROR3(tagname,
+			       get_AT_name(dbg, attr),
+			       "check the tag-attr combination..")
+	} else if (tag_attr_combination(tag, attr)) {
+	    /* OK */
+	} else {
+	    attr_tag_result.errors++;
+	    tagname = get_TAG_name(dbg, tag);
+	    DWARF_CHECK_ERROR3(tagname,
+			       get_AT_name(dbg, attr),
+			       "check the tag-attr combination")
+	}
+    }
+
+    switch (attr) {
+    case DW_AT_language:
+	get_small_encoding_integer_and_name(dbg, attrib, &uval,
+					    "DW_AT_language", &valname,
+					    get_LANG_name, &err);
+	break;
+    case DW_AT_accessibility:
+	get_small_encoding_integer_and_name(dbg, attrib, &uval,
+					    "DW_AT_accessibility",
+					    &valname, get_ACCESS_name,
+					    &err);
+	break;
+    case DW_AT_visibility:
+	get_small_encoding_integer_and_name(dbg, attrib, &uval,
+					    "DW_AT_visibility",
+					    &valname, get_VIS_name,
+					    &err);
+	break;
+    case DW_AT_virtuality:
+	get_small_encoding_integer_and_name(dbg, attrib, &uval,
+					    "DW_AT_virtuality",
+					    &valname,
+					    get_VIRTUALITY_name, &err);
+	break;
+    case DW_AT_identifier_case:
+	get_small_encoding_integer_and_name(dbg, attrib, &uval,
+					    "DW_AT_identifier",
+					    &valname, get_ID_name,
+					    &err);
+	break;
+    case DW_AT_inline:
+	get_small_encoding_integer_and_name(dbg, attrib, &uval,
+					    "DW_AT_inline", &valname,
+					    get_INL_name, &err);
+	break;
+    case DW_AT_encoding:
+	get_small_encoding_integer_and_name(dbg, attrib, &uval,
+					    "DW_AT_encoding", &valname,
+					    get_ATE_name, &err);
+	break;
+    case DW_AT_ordering:
+	get_small_encoding_integer_and_name(dbg, attrib, &uval,
+					    "DW_AT_ordering", &valname,
+					    get_ORD_name, &err);
+	break;
+    case DW_AT_calling_convention:
+	get_small_encoding_integer_and_name(dbg, attrib, &uval,
+					    "DW_AT_calling_convention",
+					    &valname, get_CC_name,
+					    &err);
+	break;
+    case DW_AT_discr_list:	/* DWARF3 */
+	get_small_encoding_integer_and_name(dbg, attrib, &uval,
+					    "DW_AT_discr_list",
+					    &valname, get_DSC_name,
+					    &err);
+	break;
+    case DW_AT_location:
+    case DW_AT_data_member_location:
+    case DW_AT_vtable_elem_location:
+    case DW_AT_string_length:
+    case DW_AT_return_addr:
+    case DW_AT_use_location:
+    case DW_AT_static_link:
+    case DW_AT_frame_base:
+	/* value is a location description or location list */
+	esb_empty_string(&esb_base);
+	get_location_list(dbg, die, attrib, &esb_base);
+	valname = esb_get_string(&esb_base);
+	break;
+    case DW_AT_SUN_func_offsets:
+	get_FLAG_BLOCK_string(dbg, attrib);
+	valname = esb_get_string(&esb_base);
+	break;
+    case DW_AT_SUN_cf_kind:
+	{
+	    Dwarf_Half kind;
+	    Dwarf_Unsigned tempud;
+	    Dwarf_Error err;
+	    int wres;
+	    wres = dwarf_formudata (attrib,&tempud, &err);
+	    if(wres == DW_DLV_OK) {
+		kind = tempud;
+		valname = get_ATCF_name(dbg, kind);
+	    } else if (wres == DW_DLV_NO_ENTRY) {
+		valname = "?";
+	    } else {
+		print_error(dbg,"Cannot get formudata....",wres,err);
+		valname = "??";
+	    }
+	}
+	break;
+    case DW_AT_upper_bound:
+	{
+	    Dwarf_Half theform;
+	    int rv;
+	    rv = dwarf_whatform(attrib,&theform,&err);
+	    /* depending on the form and the attribute, process the form */
+	    if(rv == DW_DLV_ERROR) {
+		print_error(dbg, "dwarf_whatform cannot find attr form",
+			    rv, err);
+	    } else if (rv == DW_DLV_NO_ENTRY) {
+		break;
+	    }
+
+	    switch (theform) {
+	    case DW_FORM_block1:
+		get_location_list(dbg, die, attrib, &esb_base);
+		valname = esb_get_string(&esb_base);
+		break;
+	    default:
+		esb_empty_string(&esb_base);
+		get_attr_value(dbg, tag, attrib, srcfiles, cnt, &esb_base);
+		valname = esb_get_string(&esb_base);
+		break;
+	    }
+	    break;
+	}
+    case DW_AT_high_pc:
+        {
+	    Dwarf_Half theform;
+	    int rv;
+	    rv = dwarf_whatform(attrib,&theform,&err);
+	    /* depending on the form and the attribute, process the form */
+	    if(rv == DW_DLV_ERROR) {
+		print_error(dbg, "dwarf_whatform cannot find attr form",
+			    rv, err);
+	    } else if (rv == DW_DLV_NO_ENTRY) {
+		break;
+	    }
+	    esb_empty_string(&esb_base);
+	    get_attr_value(dbg, tag, attrib, srcfiles, cnt, &esb_base);
+            if( theform != DW_FORM_addr) {
+              /* New in DWARF4: other forms are not an address
+                 but are instead offset from pc.
+                 One could test for DWARF4 here before adding
+                 this string, but that seems unnecessary as this
+                 could not happen with DWARF3 or earlier. 
+                 A normal consumer would have to add this value to
+                 DW_AT_low_pc to get a grue pc. */
+              esb_append(&esb_base,"<offset-from-lowpc>");
+            }
+	    valname = esb_get_string(&esb_base);
+        }
+    default:
+	esb_empty_string(&esb_base);
+	get_attr_value(dbg, tag, attrib, srcfiles, cnt, &esb_base);
+	valname = esb_get_string(&esb_base);
+	break;
+    }
+    if (print_information) {
+	if (dense)
+	    printf(" %s<%s>", atname, valname);
+	else
+	    printf("\t\t%-28s%s\n", atname, valname);
+    }
+}
+
+
+int
+dwarfdump_print_one_locdesc(Dwarf_Debug dbg,
+			 Dwarf_Locdesc * llbuf,
+                         int skip_locdesc_header,
+			 struct esb_s *string_out)
+{
+
+    Dwarf_Locdesc *locd = 0;
+    Dwarf_Half no_of_ops = 0;
+    int i = 0;
+    char small_buf[100];
+
+
+    if (!skip_locdesc_header && (verbose || llbuf->ld_from_loclist)) {
+	snprintf(small_buf, sizeof(small_buf), "<lowpc=0x%llx>",
+		 (unsigned long long) llbuf->ld_lopc);
+	esb_append(string_out, small_buf);
+
+
+	snprintf(small_buf, sizeof(small_buf), "<highpc=0x%llx>",
+		 (unsigned long long) llbuf->ld_hipc);
+	esb_append(string_out, small_buf);
+	if (verbose) {
+	    snprintf(small_buf, sizeof(small_buf),
+		     "<from %s offset 0x%llx>",
+		     llbuf->
+		     ld_from_loclist ? ".debug_loc" : ".debug_info",
+		     (unsigned long long) llbuf->ld_section_offset);
+	    esb_append(string_out, small_buf);
+
+	}
+    }
+
+
+    locd = llbuf;
+    no_of_ops = llbuf->ld_cents;
+    for (i = 0; i < no_of_ops; i++) {
+        Dwarf_Loc * op = &locd->ld_s[i];
+
+        int res = _dwarf_print_one_expr_op(dbg,op,i,string_out);
+        if(res == DW_DLV_ERROR) {
+          return res;
+        }
+    }
+    return DW_DLV_OK;
+}
+
+int
+_dwarf_print_one_expr_op(Dwarf_Debug dbg,Dwarf_Loc* expr,int index,
+	struct esb_s *string_out)
+{
+     /* local_space_needed is intended to be 'more than big enough'
+       for a short group of loclist entries.  */
+    char small_buf[100];
+    Dwarf_Small op;
+    Dwarf_Unsigned opd1;  
+    Dwarf_Unsigned opd2;
+    string op_name;
+
+
+    if (index > 0)
+        esb_append(string_out, " ");
+
+    op = expr->lr_atom;
+    if (op > DW_OP_nop) {
+        print_error(dbg, "dwarf_op unexpected value", DW_DLV_OK,
+			err);
+	return DW_DLV_ERROR;
+    }
+    op_name = get_OP_name(dbg, op);
+    esb_append(string_out, op_name);
+
+    opd1 = expr->lr_number;
+    if (op >= DW_OP_breg0 && op <= DW_OP_breg31) {
+	    snprintf(small_buf, sizeof(small_buf),
+		     "%+lld", (Dwarf_Signed) opd1);
+	    esb_append(string_out, small_buf);
+    } else {
+        switch (op) {
+        case DW_OP_addr:
+		snprintf(small_buf, sizeof(small_buf), " %#llx", opd1);
+		esb_append(string_out, small_buf);
+		break;
+        case DW_OP_const1s:
+        case DW_OP_const2s:
+        case DW_OP_const4s:
+        case DW_OP_const8s:
+        case DW_OP_consts:
+        case DW_OP_skip:
+        case DW_OP_bra:
+        case DW_OP_fbreg:
+		snprintf(small_buf, sizeof(small_buf),
+			 " %lld", (Dwarf_Signed) opd1);
+		esb_append(string_out, small_buf);
+		break;
+        case DW_OP_const1u:
+        case DW_OP_const2u:
+        case DW_OP_const4u:
+        case DW_OP_const8u:
+        case DW_OP_constu:
+        case DW_OP_pick:
+        case DW_OP_plus_uconst:
+        case DW_OP_regx:
+        case DW_OP_piece:
+        case DW_OP_deref_size:
+        case DW_OP_xderef_size:
+            snprintf(small_buf, sizeof(small_buf), " %llu", opd1);
+            esb_append(string_out, small_buf);
+		break;
+        case DW_OP_bregx:
+            snprintf(small_buf, sizeof(small_buf), "%llu", opd1);
+            esb_append(string_out, small_buf);
+
+
+
+            opd2 = expr->lr_number2;
+            snprintf(small_buf, sizeof(small_buf),
+                "%+lld", (Dwarf_Signed) opd2);
+            esb_append(string_out, small_buf);
+            break;
+        default:
+            break;
+	}
+    }
+    return DW_DLV_OK;
+}
+
+/* Fill buffer with location lists 
+   Buffer esbp expands as needed.
+*/
+ /*ARGSUSED*/ static void
+get_location_list(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Attribute attr,
+		  struct esb_s *esbp)
+{
+    Dwarf_Locdesc *llbuf = 0;
+    Dwarf_Locdesc **llbufarray = 0;
+    Dwarf_Signed no_of_elements;
+    Dwarf_Error err;
+    int i;
+    int lres = 0;
+    int llent = 0;
+    int skip_locdesc_header = 0;
+
+
+    if (use_old_dwarf_loclist) {
+
+	lres = dwarf_loclist(attr, &llbuf, &no_of_elements, &err);
+	if (lres == DW_DLV_ERROR)
+	    print_error(dbg, "dwarf_loclist", lres, err);
+	if (lres == DW_DLV_NO_ENTRY)
+	    return;
+
+	dwarfdump_print_one_locdesc(dbg, llbuf,skip_locdesc_header,esbp);
+	dwarf_dealloc(dbg, llbuf->ld_s, DW_DLA_LOC_BLOCK);
+	dwarf_dealloc(dbg, llbuf, DW_DLA_LOCDESC);
+	return;
+    }
+
+    lres = dwarf_loclist_n(attr, &llbufarray, &no_of_elements, &err);
+    if (lres == DW_DLV_ERROR)
+	print_error(dbg, "dwarf_loclist", lres, err);
+    if (lres == DW_DLV_NO_ENTRY)
+	return;
+
+    for (llent = 0; llent < no_of_elements; ++llent) {
+	char small_buf[100];
+
+	llbuf = llbufarray[llent];
+
+	if (!dense && llbuf->ld_from_loclist) {
+	    if (llent == 0) {
+		snprintf(small_buf, sizeof(small_buf),
+			 "<loclist with %ld entries follows>",
+			 (long) no_of_elements);
+		esb_append(esbp, small_buf);
+	    }
+	    esb_append(esbp, "\n\t\t\t");
+	    snprintf(small_buf, sizeof(small_buf), "[%2d]", llent);
+	    esb_append(esbp, small_buf);
+	}
+	lres = dwarfdump_print_one_locdesc(dbg,
+              llbuf, 
+              skip_locdesc_header,
+              esbp);
+	if (lres == DW_DLV_ERROR) {
+	    return;
+	} else {
+	    /* DW_DLV_OK so we add follow-on at end, else is
+	       DW_DLV_NO_ENTRY (which is impossible, treat like
+	       DW_DLV_OK). */
+	}
+    }
+    for (i = 0; i < no_of_elements; ++i) {
+	dwarf_dealloc(dbg, llbufarray[i]->ld_s, DW_DLA_LOC_BLOCK);
+	dwarf_dealloc(dbg, llbufarray[i], DW_DLA_LOCDESC);
+    }
+    dwarf_dealloc(dbg, llbufarray, DW_DLA_LIST);
+}
+
+static void
+formx_unsigned(Dwarf_Unsigned u, struct esb_s *esbp)
+{
+     char small_buf[40];
+     snprintf(small_buf, sizeof(small_buf),
+      "%llu", (unsigned long long)u);
+     esb_append(esbp, small_buf);
+
+}
+static void
+formx_signed(Dwarf_Signed u, struct esb_s *esbp)
+{
+     char small_buf[40];
+     snprintf(small_buf, sizeof(small_buf),
+      "%lld", (long long)u);
+     esb_append(esbp, small_buf);
+}
+/* We think this is an integer. Figure out how to print it.
+   In case the signedness is ambiguous (such as on 
+   DW_FORM_data1 (ie, unknown signedness) print two ways.
+*/
+static int
+formxdata_print_value(Dwarf_Attribute attrib, struct esb_s *esbp,
+	Dwarf_Error * err)
+{
+    Dwarf_Signed tempsd = 0;
+    Dwarf_Unsigned tempud = 0;
+    int sres = 0;
+    int ures = 0;
+    Dwarf_Error serr = 0;
+    ures = dwarf_formudata(attrib, &tempud, err);
+    sres = dwarf_formsdata(attrib, &tempsd, &serr);
+    if(ures == DW_DLV_OK) {
+      if(sres == DW_DLV_OK) {
+	if(tempud == tempsd) {
+	   /* Data is the same value, so makes no difference which
+		we print. */
+	   formx_unsigned(tempud,esbp);
+	} else {
+	   formx_unsigned(tempud,esbp);
+	   esb_append(esbp,"(as signed = ");
+	   formx_signed(tempsd,esbp);
+	   esb_append(esbp,")");
+        }
+      } else if (sres == DW_DLV_NO_ENTRY) {
+	formx_unsigned(tempud,esbp);
+      } else /* DW_DLV_ERROR */{
+	formx_unsigned(tempud,esbp);
+      }
+      return DW_DLV_OK;
+    } else  if (ures == DW_DLV_NO_ENTRY) {
+      if(sres == DW_DLV_OK) {
+	formx_signed(tempsd,esbp);
+	return sres;
+      } else if (sres == DW_DLV_NO_ENTRY) {
+	return sres;
+      } else /* DW_DLV_ERROR */{
+	*err = serr;
+        return sres;
+      }
+    } 
+    /* else ures ==  DW_DLV_ERROR */ 
+    if(sres == DW_DLV_OK) {
+	formx_signed(tempsd,esbp);
+    } else if (sres == DW_DLV_NO_ENTRY) {
+	return ures;
+    } 
+    /* DW_DLV_ERROR */
+    return ures;
+}
+
+
+/* Fill buffer with attribute value.
+   We pass in tag so we can try to do the right thing with
+   broken compiler DW_TAG_enumerator 
+
+   We append to esbp's buffer.
+
+*/
+static void
+get_attr_value(Dwarf_Debug dbg, Dwarf_Half tag, Dwarf_Attribute attrib,
+	       char **srcfiles, Dwarf_Signed cnt, struct esb_s *esbp)
+{
+    Dwarf_Half theform;
+    string temps;
+    Dwarf_Block *tempb;
+    Dwarf_Signed tempsd = 0;
+    Dwarf_Unsigned tempud = 0;
+    int i;
+    Dwarf_Half attr;
+    Dwarf_Off off;
+    Dwarf_Die die_for_check;
+    Dwarf_Half tag_for_check;
+    Dwarf_Bool tempbool;
+    Dwarf_Addr addr = 0;
+    int fres;
+    int bres;
+    int wres;
+    int dres;
+    Dwarf_Half direct_form = 0;
+    char small_buf[100];
+
+
+    fres = dwarf_whatform(attrib, &theform, &err);
+    /* depending on the form and the attribute, process the form */
+    if (fres == DW_DLV_ERROR) {
+	print_error(dbg, "dwarf_whatform cannot find attr form", fres,
+		    err);
+    } else if (fres == DW_DLV_NO_ENTRY) {
+	return;
+    }
+
+    dwarf_whatform_direct(attrib, &direct_form, &err);
+    /* ignore errors in dwarf_whatform_direct() */
+
+
+    switch (theform) {
+    case DW_FORM_addr:
+	bres = dwarf_formaddr(attrib, &addr, &err);
+	if (bres == DW_DLV_OK) {
+	    snprintf(small_buf, sizeof(small_buf), "%#llx",
+		     (unsigned long long) addr);
+	    esb_append(esbp, small_buf);
+	} else {
+	    print_error(dbg, "addr formwith no addr?!", bres, err);
+	}
+	break;
+    case DW_FORM_ref_addr:
+	/* DW_FORM_ref_addr is not accessed thru formref: ** it is an
+	   address (global section offset) in ** the .debug_info
+	   section. */
+	bres = dwarf_global_formref(attrib, &off, &err);
+	if (bres == DW_DLV_OK) {
+	    snprintf(small_buf, sizeof(small_buf),
+		     "<global die offset %llu>",
+		     (unsigned long long) off);
+	    esb_append(esbp, small_buf);
+	} else {
+	    print_error(dbg,
+			"DW_FORM_ref_addr form with no reference?!",
+			bres, err);
+	}
+	break;
+    case DW_FORM_ref1:
+    case DW_FORM_ref2:
+    case DW_FORM_ref4:
+    case DW_FORM_ref8:
+    case DW_FORM_ref_udata:
+	bres = dwarf_formref(attrib, &off, &err);
+	if (bres != DW_DLV_OK) {
+	    print_error(dbg, "ref formwith no ref?!", bres, err);
+	}
+	/* do references inside <> to distinguish them ** from
+	   constants. In dense form this results in <<>>. Ugly for
+	   dense form, but better than ambiguous. davea 9/94 */
+	snprintf(small_buf, sizeof(small_buf), "<%llu>", off);
+	esb_append(esbp, small_buf);
+	if (check_type_offset) {
+	    wres = dwarf_whatattr(attrib, &attr, &err);
+	    if (wres == DW_DLV_ERROR) {
+
+	    } else if (wres == DW_DLV_NO_ENTRY) {
+	    }
+	    if (attr == DW_AT_type) {
+		dres = dwarf_offdie(dbg, cu_offset + off,
+				    &die_for_check, &err);
+		type_offset_result.checks++;
+		if (dres != DW_DLV_OK) {
+		    type_offset_result.errors++;
+		    DWARF_CHECK_ERROR
+			("DW_AT_type offset does not point to type info")
+		} else {
+		    int tres2;
+
+		    tres2 =
+			dwarf_tag(die_for_check, &tag_for_check, &err);
+		    if (tres2 == DW_DLV_OK) {
+			switch (tag_for_check) {
+			case DW_TAG_array_type:
+			case DW_TAG_class_type:
+			case DW_TAG_enumeration_type:
+			case DW_TAG_pointer_type:
+			case DW_TAG_reference_type:
+			case DW_TAG_string_type:
+			case DW_TAG_structure_type:
+			case DW_TAG_subroutine_type:
+			case DW_TAG_typedef:
+			case DW_TAG_union_type:
+			case DW_TAG_ptr_to_member_type:
+			case DW_TAG_set_type:
+			case DW_TAG_subrange_type:
+			case DW_TAG_base_type:
+			case DW_TAG_const_type:
+			case DW_TAG_file_type:
+			case DW_TAG_packed_type:
+			case DW_TAG_thrown_type:
+			case DW_TAG_volatile_type:
+			    /* OK */
+			    break;
+			default:
+			    type_offset_result.errors++;
+			    DWARF_CHECK_ERROR
+				("DW_AT_type offset does not point to type info")
+				break;
+			}
+			dwarf_dealloc(dbg, die_for_check, DW_DLA_DIE);
+		    } else {
+			type_offset_result.errors++;
+			DWARF_CHECK_ERROR
+			    ("DW_AT_type offset does not exist")
+		    }
+		}
+	    }
+	}
+	break;
+    case DW_FORM_block:
+    case DW_FORM_block1:
+    case DW_FORM_block2:
+    case DW_FORM_block4:
+	fres = dwarf_formblock(attrib, &tempb, &err);
+	if (fres == DW_DLV_OK) {
+	    for (i = 0; i < tempb->bl_len; i++) {
+		snprintf(small_buf, sizeof(small_buf), "%02x",
+			 *(i + (unsigned char *) tempb->bl_data));
+		esb_append(esbp, small_buf);
+	    }
+	    dwarf_dealloc(dbg, tempb, DW_DLA_BLOCK);
+	} else {
+	    print_error(dbg, "DW_FORM_blockn cannot get block\n", fres,
+			err);
+	}
+	break;
+    case DW_FORM_data1:
+    case DW_FORM_data2:
+    case DW_FORM_data4:
+    case DW_FORM_data8:
+	fres = dwarf_whatattr(attrib, &attr, &err);
+	if (fres == DW_DLV_ERROR) {
+	    print_error(dbg, "FORM_datan cannot get attr", fres, err);
+	} else if (fres == DW_DLV_NO_ENTRY) {
+	    print_error(dbg, "FORM_datan cannot get attr", fres, err);
+	} else {
+	    switch (attr) {
+	    case DW_AT_ordering:
+	    case DW_AT_byte_size:
+	    case DW_AT_bit_offset:
+	    case DW_AT_bit_size:
+	    case DW_AT_inline:
+	    case DW_AT_language:
+	    case DW_AT_visibility:
+	    case DW_AT_virtuality:
+	    case DW_AT_accessibility:
+	    case DW_AT_address_class:
+	    case DW_AT_calling_convention:
+	    case DW_AT_discr_list:	/* DWARF3 */
+	    case DW_AT_encoding:
+	    case DW_AT_identifier_case:
+	    case DW_AT_MIPS_loop_unroll_factor:
+	    case DW_AT_MIPS_software_pipeline_depth:
+	    case DW_AT_decl_column:
+	    case DW_AT_decl_file:
+	    case DW_AT_decl_line:
+	    case DW_AT_start_scope:
+	    case DW_AT_byte_stride:
+	    case DW_AT_bit_stride:
+	    case DW_AT_count:
+	    case DW_AT_stmt_list:
+	    case DW_AT_MIPS_fde:
+		wres = get_small_encoding_integer_and_name(dbg,
+							   attrib,
+							   &tempud,
+							   /* attrname */
+		    (char *) NULL,
+							   /* err_string 
+							    */ 
+							   (char **)
+							   NULL,
+							   (encoding_type_func) 0,
+							   &err);
+
+		if (wres == DW_DLV_OK) {
+		    snprintf(small_buf, sizeof(small_buf), "%llu",
+			     tempud);
+		    esb_append(esbp, small_buf);
+		    if (attr == DW_AT_decl_file) {
+			if (srcfiles && tempud > 0 && tempud <= cnt) {
+			    /* added by user request */
+			    /* srcfiles is indexed starting at 0, but
+			       DW_AT_decl_file defines that 0 means no
+			       file, so tempud 1 means the 0th entry in
+			       srcfiles, thus tempud-1 is the correct
+			       index into srcfiles.  */
+			    char *fname = srcfiles[tempud - 1];
+
+			    esb_append(esbp, " ");
+			    esb_append(esbp, fname);
+			}
+		    }
+		} else {
+		    print_error(dbg, "Cannot get encoding attribute ..",
+				wres, err);
+		}
+		break;
+	    case DW_AT_const_value:
+		wres = formxdata_print_value(attrib,esbp, &err);
+		if(wres == DW_DLV_OK){
+		    /* String appended already. */
+		} else if (wres == DW_DLV_NO_ENTRY) {
+		    /* nothing? */
+		} else {
+		   print_error(dbg,"Cannot get DW_AT_const_value ",wres,err);
+		}
+  
+		
+		break;
+	    case DW_AT_upper_bound:
+	    case DW_AT_lower_bound:
+	    default:
+		wres = formxdata_print_value(attrib,esbp, &err);
+		if (wres == DW_DLV_OK) {
+		    /* String appended already. */
+		} else if (wres == DW_DLV_NO_ENTRY) {
+		    /* nothing? */
+		} else {
+		    print_error(dbg, "Cannot get formsdata..", wres,
+				err);
+		}
+		break;
+	    }
+	}
+	if (cu_name_flag) {
+	    if (attr == DW_AT_MIPS_fde) {
+		if (fde_offset_for_cu_low == DW_DLV_BADOFFSET) {
+		    fde_offset_for_cu_low
+			= fde_offset_for_cu_high = tempud;
+		} else if (tempud < fde_offset_for_cu_low) {
+		    fde_offset_for_cu_low = tempud;
+		} else if (tempud > fde_offset_for_cu_high) {
+		    fde_offset_for_cu_high = tempud;
+		}
+	    }
+	}
+	break;
+    case DW_FORM_sdata:
+	wres = dwarf_formsdata(attrib, &tempsd, &err);
+	if (wres == DW_DLV_OK) {
+	    snprintf(small_buf, sizeof(small_buf), "%lld", tempsd);
+	    esb_append(esbp, small_buf);
+	} else if (wres == DW_DLV_NO_ENTRY) {
+	    /* nothing? */
+	} else {
+	    print_error(dbg, "Cannot get formsdata..", wres, err);
+	}
+	break;
+    case DW_FORM_udata:
+	wres = dwarf_formudata(attrib, &tempud, &err);
+	if (wres == DW_DLV_OK) {
+	    snprintf(small_buf, sizeof(small_buf), "%llu", tempud);
+	    esb_append(esbp, small_buf);
+	} else if (wres == DW_DLV_NO_ENTRY) {
+	    /* nothing? */
+	} else {
+	    print_error(dbg, "Cannot get formudata....", wres, err);
+	}
+	break;
+    case DW_FORM_string:
+    case DW_FORM_strp:
+	wres = dwarf_formstring(attrib, &temps, &err);
+	if (wres == DW_DLV_OK) {
+	    esb_append(esbp, temps);
+	} else if (wres == DW_DLV_NO_ENTRY) {
+	    /* nothing? */
+	} else {
+	    print_error(dbg, "Cannot get formstr/p....", wres, err);
+	}
+
+	break;
+    case DW_FORM_flag:
+	wres = dwarf_formflag(attrib, &tempbool, &err);
+	if (wres == DW_DLV_OK) {
+	    if (tempbool) {
+		snprintf(small_buf, sizeof(small_buf), "yes(%d)",
+			 tempbool);
+		esb_append(esbp, small_buf);
+	    } else {
+		snprintf(small_buf, sizeof(small_buf), "no");
+		esb_append(esbp, small_buf);
+	    }
+	} else if (wres == DW_DLV_NO_ENTRY) {
+	    /* nothing? */
+	} else {
+	    print_error(dbg, "Cannot get formflag/p....", wres, err);
+	}
+	break;
+    case DW_FORM_indirect:
+	/* We should not ever get here, since the true form was
+	   determined and direct_form has the DW_FORM_indirect if it is
+	   used here in this attr. */
+	esb_append(esbp, get_FORM_name(dbg, theform));
+	break;
+    default:
+	print_error(dbg, "dwarf_whatform unexpected value", DW_DLV_OK,
+		    err);
+    }
+    if (verbose && direct_form && direct_form == DW_FORM_indirect) {
+	char *form_indir = " (used DW_FORM_indirect) ";
+
+	esb_append(esbp, form_indir);
+    }
+}
+
+/* A cleanup so that when using a memory checker
+   we don't show irrelevant leftovers.
+*/
+void
+clean_up_die_esb()
+{
+   esb_destructor(&esb_base);
+}
+
+#include "_tag_attr_table.c"
+
+static int
+tag_attr_combination(Dwarf_Half tag, Dwarf_Half attr)
+{
+    if (attr > 0 && attr < 0x60) {
+	return ((tag_attr_combination_table[tag][attr / 0x20]
+		 & (1 << (attr % 0x20))) > 0 ? TRUE : FALSE);
+    } else if (attr == DW_AT_MIPS_fde) {
+	/* no check now */
+	return (TRUE);
+    } else
+	return (FALSE);
+}