summaryrefslogtreecommitdiff
path: root/usr/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib')
-rw-r--r--usr/src/lib/Makefile5
-rw-r--r--usr/src/lib/libctf/Makefile.shared.com17
-rw-r--r--usr/src/lib/libctf/Makefile.shared.targ4
-rw-r--r--usr/src/lib/libctf/common/ctf_convert.c210
-rw-r--r--usr/src/lib/libctf/common/ctf_diff.c95
-rw-r--r--usr/src/lib/libctf/common/ctf_dwarf.c2952
-rw-r--r--usr/src/lib/libctf/common/ctf_elfwrite.c198
-rw-r--r--usr/src/lib/libctf/common/ctf_lib.c211
-rw-r--r--usr/src/lib/libctf/common/ctf_merge.c492
-rw-r--r--usr/src/lib/libctf/common/ctf_subr.c28
-rw-r--r--usr/src/lib/libctf/common/libctf.h9
-rw-r--r--usr/src/lib/libctf/common/libctf_impl.h59
-rw-r--r--usr/src/lib/libctf/common/mapfile-vers6
-rw-r--r--usr/src/lib/libdwarf/Makefile40
-rw-r--r--usr/src/lib/libdwarf/Makefile.com92
-rw-r--r--usr/src/lib/libdwarf/THIRDPARTYLICENSE30
-rw-r--r--usr/src/lib/libdwarf/THIRDPARTYLICENSE.descrip1
-rw-r--r--usr/src/lib/libdwarf/amd64/Makefile19
-rw-r--r--usr/src/lib/libdwarf/common/cmplrs/dwarf_addr_finder.h55
-rw-r--r--usr/src/lib/libdwarf/common/config.h143
-rw-r--r--usr/src/lib/libdwarf/common/dwarf.h1078
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_abbrev.c259
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_abbrev.h55
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_addr_finder.c685
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_alloc.c1258
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_alloc.h177
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_arange.c593
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_arange.h71
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_base_types.h123
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_die_deliv.c855
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_die_deliv.h57
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_elf_access.c976
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_elf_access.h55
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_error.c410
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_error.h43
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_form.c963
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_frame.c2442
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_frame.h421
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_frame2.c1540
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_frame3.c290
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_funcs.c130
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_funcs.h42
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_global.c607
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_global.h124
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_harmless.c226
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_harmless.h31
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_incl.h66
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_init_finish.c577
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_leb.c149
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_line.c1951
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_line.h331
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_line2.c110
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_loc.c1073
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_loc.h46
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_macro.c467
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_macro.h44
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_names.c2408
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_names.h34
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_opaque.h339
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_original_elf_init.c209
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_print_lines.c737
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_pubtypes.c138
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_query.c789
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_ranges.c171
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_sort_line.c733
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_string.c79
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_stubs.c50
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_types.c129
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_types.h41
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_util.c547
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_util.h311
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_vars.c133
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_vars.h41
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_weaks.c130
-rw-r--r--usr/src/lib/libdwarf/common/dwarf_weaks.h41
-rw-r--r--usr/src/lib/libdwarf/common/libdwarf.h2736
-rw-r--r--usr/src/lib/libdwarf/common/libdwarfdefs.h91
-rw-r--r--usr/src/lib/libdwarf/common/malloc_check.c339
-rw-r--r--usr/src/lib/libdwarf/common/malloc_check.h62
-rw-r--r--usr/src/lib/libdwarf/common/mapfile-vers302
-rw-r--r--usr/src/lib/libdwarf/common/pro_alloc.c188
-rw-r--r--usr/src/lib/libdwarf/common/pro_alloc.h42
-rw-r--r--usr/src/lib/libdwarf/common/pro_arange.c337
-rw-r--r--usr/src/lib/libdwarf/common/pro_arange.h62
-rw-r--r--usr/src/lib/libdwarf/common/pro_die.c442
-rw-r--r--usr/src/lib/libdwarf/common/pro_die.h68
-rw-r--r--usr/src/lib/libdwarf/common/pro_encode_nm.c123
-rw-r--r--usr/src/lib/libdwarf/common/pro_encode_nm.h48
-rw-r--r--usr/src/lib/libdwarf/common/pro_error.c97
-rw-r--r--usr/src/lib/libdwarf/common/pro_error.h52
-rw-r--r--usr/src/lib/libdwarf/common/pro_expr.c597
-rw-r--r--usr/src/lib/libdwarf/common/pro_expr.h45
-rw-r--r--usr/src/lib/libdwarf/common/pro_finish.c57
-rw-r--r--usr/src/lib/libdwarf/common/pro_forms.c1182
-rw-r--r--usr/src/lib/libdwarf/common/pro_frame.c598
-rw-r--r--usr/src/lib/libdwarf/common/pro_frame.h132
-rw-r--r--usr/src/lib/libdwarf/common/pro_funcs.c62
-rw-r--r--usr/src/lib/libdwarf/common/pro_incl.h92
-rw-r--r--usr/src/lib/libdwarf/common/pro_init.c261
-rw-r--r--usr/src/lib/libdwarf/common/pro_line.c300
-rw-r--r--usr/src/lib/libdwarf/common/pro_line.h116
-rw-r--r--usr/src/lib/libdwarf/common/pro_macinfo.c472
-rw-r--r--usr/src/lib/libdwarf/common/pro_macinfo.h40
-rw-r--r--usr/src/lib/libdwarf/common/pro_opaque.h484
-rw-r--r--usr/src/lib/libdwarf/common/pro_pubnames.c63
-rw-r--r--usr/src/lib/libdwarf/common/pro_reloc.c269
-rw-r--r--usr/src/lib/libdwarf/common/pro_reloc.h47
-rw-r--r--usr/src/lib/libdwarf/common/pro_reloc_stream.c297
-rw-r--r--usr/src/lib/libdwarf/common/pro_reloc_stream.h63
-rw-r--r--usr/src/lib/libdwarf/common/pro_reloc_symbolic.c276
-rw-r--r--usr/src/lib/libdwarf/common/pro_reloc_symbolic.h55
-rw-r--r--usr/src/lib/libdwarf/common/pro_section.c2221
-rw-r--r--usr/src/lib/libdwarf/common/pro_section.h112
-rw-r--r--usr/src/lib/libdwarf/common/pro_types.c296
-rw-r--r--usr/src/lib/libdwarf/common/pro_types.h44
-rw-r--r--usr/src/lib/libdwarf/common/pro_util.h148
-rw-r--r--usr/src/lib/libdwarf/common/pro_vars.c62
-rw-r--r--usr/src/lib/libdwarf/common/pro_weaks.c61
-rw-r--r--usr/src/lib/libdwarf/i386/Makefile18
-rw-r--r--usr/src/lib/libdwarf/sparc/Makefile18
-rw-r--r--usr/src/lib/libdwarf/sparcv9/Makefile19
-rw-r--r--usr/src/lib/mergeq/mergeq.c606
-rw-r--r--usr/src/lib/mergeq/mergeq.h52
-rw-r--r--usr/src/lib/mergeq/workq.c311
-rw-r--r--usr/src/lib/mergeq/workq.h52
125 files changed, 44374 insertions, 194 deletions
diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile
index 3af3ca3ef0..8e8868b08e 100644
--- a/usr/src/lib/Makefile
+++ b/usr/src/lib/Makefile
@@ -166,7 +166,8 @@ SUBDIRS += \
libvnd \
libidspace \
varpd \
- libbunyan
+ libbunyan \
+ libdwarf
SUBDIRS += \
passwdutil \
@@ -391,6 +392,7 @@ HDRSUBDIRS= \
libdevid \
libdevinfo \
libdiskmgt \
+ libdwarf \
libdladm \
libdll \
libdlpi \
@@ -673,6 +675,7 @@ libstmf: libm
libvscan: libm
libidspace: libumem
libbunyan: libnvpair
+libctf: libdwarf
$(INTEL_BUILD)libdiskmgt:libfdisk
diff --git a/usr/src/lib/libctf/Makefile.shared.com b/usr/src/lib/libctf/Makefile.shared.com
index a0370fc944..55f090e7f8 100644
--- a/usr/src/lib/libctf/Makefile.shared.com
+++ b/usr/src/lib/libctf/Makefile.shared.com
@@ -35,6 +35,7 @@ VERS = .1
COMMON_OBJS = \
ctf_create.o \
ctf_decl.o \
+ ctf_dwarf.o \
ctf_error.o \
ctf_hash.o \
ctf_labels.o \
@@ -43,17 +44,22 @@ COMMON_OBJS = \
ctf_types.o \
ctf_util.o
+MERGEQ_OBJS = \
+ mergeq.o \
+ workq.o
+
LIST_OBJS = \
list.o
LIB_OBJS = \
+ ctf_convert.o \
ctf_elfwrite.o \
ctf_diff.o \
ctf_lib.o \
ctf_merge.o \
ctf_subr.o
-OBJECTS = $(COMMON_OBJS) $(LIB_OBJS) $(LIST_OBJS)
+OBJECTS = $(COMMON_OBJS) $(LIB_OBJS) $(LIST_OBJS) $(MERGEQ_OBJS)
MAPFILEDIR = $(SRC)/lib/libctf
include $(SRC)/lib/Makefile.lib
@@ -62,16 +68,21 @@ SRCS = \
$(COMMON_OBJS:%.o=$(SRC)/common/ctf/%.c) \
$(LIB_OBJS:%.o=$(SRC)/lib/libctf/common/%.c) \
$(LIST_OBJS:%.o=$(SRC)/common/list/%.c) \
+ $(MERGEQ_OBJS:%.o=$(SRC)/lib/mergeq/%.c)
LIBS = $(DYNLIB) $(LINTLIB)
-LDLIBS += -lc -lelf
+LDLIBS += -lc -lelf -ldwarf -lavl
C99MODE= -xc99=%all
C99LMODE= -Xc99=%all
SRCDIR = $(SRC)/lib/libctf/common
-CPPFLAGS += -I$(SRC)/lib/libctf/common -I$(SRC)/common/ctf -DCTF_OLD_VERSIONS
+CPPFLAGS += -I$(SRC)/lib/libctf/common \
+ -I$(SRC)/common/ctf \
+ -I$(SRC)/lib/libdwarf/common \
+ -I$(SRC)/lib/mergeq \
+ -DCTF_OLD_VERSIONS
CFLAGS += $(CCVERBOSE)
CERRWARN += -_gcc=-Wno-uninitialized
diff --git a/usr/src/lib/libctf/Makefile.shared.targ b/usr/src/lib/libctf/Makefile.shared.targ
index 282be86075..b6520f2366 100644
--- a/usr/src/lib/libctf/Makefile.shared.targ
+++ b/usr/src/lib/libctf/Makefile.shared.targ
@@ -24,3 +24,7 @@ pics/%.o: $(SRC)/common/ctf/%.c
pics/%.o: $(SRC)/common/list/%.c
$(COMPILE.c) -o $@ $<
$(POST_PROCESS_O)
+
+pics/%.o: $(SRC)/lib/mergeq/%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
diff --git a/usr/src/lib/libctf/common/ctf_convert.c b/usr/src/lib/libctf/common/ctf_convert.c
new file mode 100644
index 0000000000..cbb4d48c76
--- /dev/null
+++ b/usr/src/lib/libctf/common/ctf_convert.c
@@ -0,0 +1,210 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+/*
+ * Main conversion entry points. This has been designed such that there can be
+ * any number of different conversion backends. Currently we only have one that
+ * understands DWARFv2 (and bits of DWARFv4). Each backend should be placed in
+ * the ctf_converters list and each will be tried in turn.
+ */
+
+#include <libctf_impl.h>
+#include <gelf.h>
+
+ctf_convert_f ctf_converters[] = {
+ ctf_dwarf_convert
+};
+
+#define NCONVERTS (sizeof (ctf_converters) / sizeof (ctf_convert_f))
+
+typedef enum ctf_convert_source {
+ CTFCONV_SOURCE_NONE = 0x0,
+ CTFCONV_SOURCE_UNKNOWN = 0x01,
+ CTFCONV_SOURCE_C = 0x02,
+ CTFCONV_SOURCE_S = 0x04
+} ctf_convert_source_t;
+
+static void
+ctf_convert_ftypes(Elf *elf, ctf_convert_source_t *types)
+{
+ int i;
+ Elf_Scn *scn = NULL, *strscn;
+ *types = CTFCONV_SOURCE_NONE;
+ GElf_Shdr shdr;
+ Elf_Data *data, *strdata;
+
+ while ((scn = elf_nextscn(elf, scn)) != NULL) {
+
+ if (gelf_getshdr(scn, &shdr) == NULL)
+ return;
+
+ if (shdr.sh_type == SHT_SYMTAB)
+ break;
+ }
+
+ if (scn == NULL)
+ return;
+
+ if ((strscn = elf_getscn(elf, shdr.sh_link)) == NULL)
+ return;
+
+ if ((data = elf_getdata(scn, NULL)) == NULL)
+ return;
+
+ if ((strdata = elf_getdata(strscn, NULL)) == NULL)
+ return;
+
+ for (i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) {
+ GElf_Sym sym;
+ const char *file;
+ size_t len;
+
+ if (gelf_getsym(data, i, &sym) == NULL)
+ return;
+
+ if (GELF_ST_TYPE(sym.st_info) != STT_FILE)
+ continue;
+
+ file = (const char *)((uintptr_t)strdata->d_buf + sym.st_name);
+ len = strlen(file);
+ if (len < 2 || file[len - 2] != '.') {
+ *types |= CTFCONV_SOURCE_UNKNOWN;
+ continue;
+ }
+
+ switch (file[len - 1]) {
+ case 'c':
+ *types |= CTFCONV_SOURCE_C;
+ break;
+ case 'h':
+ /* We traditionally ignore header files... */
+ break;
+ case 's':
+ *types |= CTFCONV_SOURCE_S;
+ break;
+ default:
+ *types |= CTFCONV_SOURCE_UNKNOWN;
+ break;
+ }
+ }
+}
+
+static ctf_file_t *
+ctf_elfconvert(int fd, Elf *elf, const char *label, uint_t nthrs, uint_t flags,
+ int *errp, char *errbuf, size_t errlen)
+{
+ int err, i;
+ ctf_file_t *fp = NULL;
+ boolean_t notsup = B_TRUE;
+ ctf_convert_source_t type;
+
+ if (errp == NULL)
+ errp = &err;
+
+ if (elf == NULL) {
+ *errp = EINVAL;
+ return (NULL);
+ }
+
+ if (flags & ~CTF_CONVERT_F_IGNNONC) {
+ *errp = EINVAL;
+ return (NULL);
+ }
+
+ if (elf_kind(elf) != ELF_K_ELF) {
+ *errp = ECTF_FMT;
+ return (NULL);
+ }
+
+ ctf_convert_ftypes(elf, &type);
+ ctf_dprintf("got types: %d\n", type);
+ if (flags & CTF_CONVERT_F_IGNNONC) {
+ if (type == CTFCONV_SOURCE_NONE ||
+ (type & CTFCONV_SOURCE_UNKNOWN)) {
+ *errp = ECTF_CONVNOCSRC;
+ return (NULL);
+ }
+ }
+
+ for (i = 0; i < NCONVERTS; i++) {
+ ctf_conv_status_t cs;
+
+ fp = NULL;
+ cs = ctf_converters[i](fd, elf, nthrs, errp, &fp, errbuf,
+ errlen);
+ if (cs == CTF_CONV_SUCCESS) {
+ notsup = B_FALSE;
+ break;
+ }
+ if (cs == CTF_CONV_ERROR) {
+ fp = NULL;
+ notsup = B_FALSE;
+ break;
+ }
+ }
+
+ if (notsup == B_TRUE) {
+ if ((flags & CTF_CONVERT_F_IGNNONC) != 0 &&
+ (type & CTFCONV_SOURCE_C) == 0) {
+ *errp = ECTF_CONVNOCSRC;
+ return (NULL);
+ }
+ *errp = ECTF_NOCONVBKEND;
+ return (NULL);
+ }
+
+ /*
+ * Succsesful conversion.
+ */
+ if (fp != NULL) {
+ if (label == NULL)
+ label = "";
+ if (ctf_add_label(fp, label, fp->ctf_typemax, 0) == CTF_ERR) {
+ *errp = ctf_errno(fp);
+ ctf_close(fp);
+ return (NULL);
+ }
+ if (ctf_update(fp) == CTF_ERR) {
+ *errp = ctf_errno(fp);
+ ctf_close(fp);
+ return (NULL);
+ }
+ }
+
+ return (fp);
+}
+
+ctf_file_t *
+ctf_fdconvert(int fd, const char *label, uint_t nthrs, uint_t flags, int *errp,
+ char *errbuf, size_t errlen)
+{
+ int err;
+ Elf *elf;
+ ctf_file_t *fp;
+
+ if (errp == NULL)
+ errp = &err;
+
+ elf = elf_begin(fd, ELF_C_READ, NULL);
+ if (elf == NULL) {
+ *errp = ECTF_FMT;
+ return (NULL);
+ }
+
+ fp = ctf_elfconvert(fd, elf, label, nthrs, flags, errp, errbuf, errlen);
+
+ (void) elf_end(elf);
+ return (fp);
+}
diff --git a/usr/src/lib/libctf/common/ctf_diff.c b/usr/src/lib/libctf/common/ctf_diff.c
index e819fe02cb..d070488bbb 100644
--- a/usr/src/lib/libctf/common/ctf_diff.c
+++ b/usr/src/lib/libctf/common/ctf_diff.c
@@ -72,6 +72,8 @@ struct ctf_diff {
ctf_file_t *cds_ofp;
ctf_id_t *cds_forward;
ctf_id_t *cds_reverse;
+ size_t cds_fsize;
+ size_t cds_rsize;
ctf_diff_type_f cds_func;
ctf_diff_guess_t *cds_guess;
void *cds_arg;
@@ -147,6 +149,39 @@ ctf_diff_number(ctf_file_t *ifp, ctf_id_t iid, ctf_file_t *ofp, ctf_id_t oid)
}
/*
+ * Two typedefs are equivalent, if after we resolve a chain of typedefs, they
+ * point to equivalent types. This means that if a size_t is defined as follows:
+ *
+ * size_t -> ulong_t -> unsigned long
+ * size_t -> unsigned long
+ *
+ * That we'll ultimately end up treating them the same.
+ */
+static int
+ctf_diff_typedef(ctf_diff_t *cds, ctf_file_t *ifp, ctf_id_t iid,
+ ctf_file_t *ofp, ctf_id_t oid)
+{
+ ctf_id_t iref = CTF_ERR, oref = CTF_ERR;
+
+ while (ctf_type_kind(ifp, iid) == CTF_K_TYPEDEF) {
+ iref = ctf_type_reference(ifp, iid);
+ if (iref == CTF_ERR)
+ return (CTF_ERR);
+ iid = iref;
+ }
+
+ while (ctf_type_kind(ofp, oid) == CTF_K_TYPEDEF) {
+ oref = ctf_type_reference(ofp, oid);
+ if (oref == CTF_ERR)
+ return (CTF_ERR);
+ oid = oref;
+ }
+
+ VERIFY(iref != CTF_ERR && oref != CTF_ERR);
+ return (ctf_diff_type(cds, ifp, iref, ofp, oref));
+}
+
+/*
* Two qualifiers are equivalent iff they point to two equivalent types.
*/
static int
@@ -274,7 +309,8 @@ out:
/*
* Two structures are the same if every member is identical to its corresponding
- * type, at the same offset, and has the same name.
+ * type, at the same offset, and has the same name, as well as them having the
+ * same overall size.
*/
static int
ctf_diff_struct(ctf_diff_t *cds, ctf_file_t *ifp, ctf_id_t iid, ctf_file_t *ofp,
@@ -296,6 +332,9 @@ ctf_diff_struct(ctf_diff_t *cds, ctf_file_t *ifp, ctf_id_t iid, ctf_file_t *ofp,
if ((otp = ctf_lookup_by_id(&ofp, oid)) == NULL)
return (ctf_set_errno(oifp, ctf_errno(ofp)));
+ if (ctf_type_size(ifp, iid) != ctf_type_size(ofp, oid))
+ return (B_TRUE);
+
if (LCTF_INFO_VLEN(ifp, itp->ctt_info) !=
LCTF_INFO_VLEN(ofp, otp->ctt_info))
return (B_TRUE);
@@ -639,8 +678,10 @@ ctf_diff_type(ctf_diff_t *cds, ctf_file_t *ifp, ctf_id_t iid, ctf_file_t *ofp,
case CTF_K_FORWARD:
ret = ctf_diff_forward(ifp, iid, ofp, oid);
break;
- case CTF_K_POINTER:
case CTF_K_TYPEDEF:
+ ret = ctf_diff_typedef(cds, ifp, iid, ofp, oid);
+ break;
+ case CTF_K_POINTER:
case CTF_K_VOLATILE:
case CTF_K_CONST:
case CTF_K_RESTRICT:
@@ -664,9 +705,12 @@ ctf_diff_type(ctf_diff_t *cds, ctf_file_t *ifp, ctf_id_t iid, ctf_file_t *ofp,
/*
* Walk every type in the first container and try to find a match in the second.
* If there is a match, then update both the forward and reverse mapping tables.
+ *
+ * The self variable tells us whether or not we should be comparing the input
+ * ctf container with itself or not.
*/
static int
-ctf_diff_pass1(ctf_diff_t *cds)
+ctf_diff_pass1(ctf_diff_t *cds, boolean_t self)
{
int i, j, diff;
int istart, iend, jstart, jend;
@@ -689,6 +733,17 @@ ctf_diff_pass1(ctf_diff_t *cds)
for (i = istart; i <= iend; i++) {
diff = B_TRUE;
+
+ /*
+ * If we're doing a self diff for dedup purposes, then we want
+ * to ensure that we compare a type i with every type in the
+ * range, [ 1, i ). Yes, this does mean that when i equals 1,
+ * we won't compare anything.
+ */
+ if (self == B_TRUE) {
+ jstart = istart;
+ jend = i - 1;
+ }
for (j = jstart; j <= jend; j++) {
ctf_diff_guess_t *cdg, *tofree;
@@ -788,12 +843,14 @@ ctf_diff_init(ctf_file_t *ifp, ctf_file_t *ofp, ctf_diff_t **cdsp)
ctf_free(cds, sizeof (ctf_diff_t));
return (ctf_set_errno(ifp, ENOMEM));
}
+ cds->cds_fsize = fsize;
cds->cds_reverse = ctf_alloc(rsize);
if (cds->cds_reverse == NULL) {
ctf_free(cds->cds_forward, fsize);
ctf_free(cds, sizeof (ctf_diff_t));
return (ctf_set_errno(ifp, ENOMEM));
}
+ cds->cds_rsize = rsize;
bzero(cds->cds_forward, fsize);
bzero(cds->cds_reverse, rsize);
@@ -811,7 +868,7 @@ ctf_diff_types(ctf_diff_t *cds, ctf_diff_type_f cb, void *arg)
cds->cds_func = cb;
cds->cds_arg = arg;
- ret = ctf_diff_pass1(cds);
+ ret = ctf_diff_pass1(cds, B_FALSE);
if (ret == 0)
ret = ctf_diff_pass2(cds);
@@ -821,12 +878,36 @@ ctf_diff_types(ctf_diff_t *cds, ctf_diff_type_f cb, void *arg)
return (ret);
}
+/*
+ * Do a diff where we're comparing a container with itself. In other words we'd
+ * like to know what types are actually duplicates of existing types in the
+ * container.
+ *
+ * Note this should remain private to libctf and not be exported in the public
+ * mapfile for the time being.
+ */
+int
+ctf_diff_self(ctf_diff_t *cds, ctf_diff_type_f cb, void *arg)
+{
+ if (cds->cds_ifp != cds->cds_ofp)
+ return (EINVAL);
+
+ cds->cds_func = cb;
+ cds->cds_arg = arg;
+
+ return (ctf_diff_pass1(cds, B_TRUE));
+}
+
+
void
ctf_diff_fini(ctf_diff_t *cds)
{
ctf_diff_guess_t *cdg;
size_t fsize, rsize;
+ if (cds == NULL)
+ return;
+
cds->cds_ifp->ctf_refcnt--;
cds->cds_ofp->ctf_refcnt--;
@@ -855,6 +936,10 @@ ctf_diff_fini(ctf_diff_t *cds)
cdg = cdg->cdg_next;
ctf_free(tofree, sizeof (ctf_diff_guess_t));
}
+ if (cds->cds_forward != NULL)
+ ctf_free(cds->cds_forward, cds->cds_fsize);
+ if (cds->cds_reverse != NULL)
+ ctf_free(cds->cds_reverse, cds->cds_rsize);
ctf_free(cds, sizeof (ctf_diff_t));
}
@@ -867,7 +952,7 @@ ctf_diff_getflags(ctf_diff_t *cds)
int
ctf_diff_setflags(ctf_diff_t *cds, uint_t flags)
{
- if ((flags & ~CTF_DIFF_F_MASK) != 0)
+ if ((flags & ~CTF_DIFF_F_IGNORE_INTNAMES) != 0)
return (ctf_set_errno(cds->cds_ifp, EINVAL));
cds->cds_flags = flags;
diff --git a/usr/src/lib/libctf/common/ctf_dwarf.c b/usr/src/lib/libctf/common/ctf_dwarf.c
new file mode 100644
index 0000000000..72e5aa9bd9
--- /dev/null
+++ b/usr/src/lib/libctf/common/ctf_dwarf.c
@@ -0,0 +1,2952 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Copyright 2012 Jason King. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+/*
+ * CTF DWARF conversion theory.
+ *
+ * DWARF data contains a series of compilation units. Each compilation unit
+ * generally refers to an object file or what once was, in the case of linked
+ * binaries and shared objects. Each compilation unit has a series of what DWARF
+ * calls a DIE (Debugging Information Entry). The set of entries that we care
+ * about have type information stored in a series of attributes. Each DIE also
+ * has a tag that identifies the kind of attributes that it has.
+ *
+ * A given DIE may itself have children. For example, a DIE that represents a
+ * structure has children which represent members. Whenever we encounter a DIE
+ * that has children or other values or types associated with it, we recursively
+ * process those children first so that way we can then refer to the generated
+ * CTF type id while processing its parent. This reduces the amount of unknowns
+ * and fixups that we need. It also ensures that we don't accidentally add types
+ * that an overzealous compiler might add to the DWARF data but aren't used by
+ * anything in the system.
+ *
+ * Once we do a conversion, we store a mapping in an AVL tree that goes from the
+ * DWARF's die offset, which is relative to the given compilation unit), to a
+ * ctf_id_t.
+ *
+ * Unfortunately, some compilers actually will emit duplicate entries for a
+ * given type that look similar, but aren't quite. To that end, we go through
+ * and do a variant on a merge once we're done processing a single compilation
+ * unit which deduplicates all of the types that are in the unit.
+ *
+ * Finally, if we encounter an object that has multiple compilation units, then
+ * we'll convert all of the compilation units separately and then do a merge, so
+ * that way we can result in one single ctf_file_t that represents everything
+ * for the object.
+ *
+ * Conversion Steps
+ * ----------------
+ *
+ * Because a given object we've been given to convert may have multiple
+ * compilation units, we break the work into two halves. The first half
+ * processes each compilation unit (potentially in parallel) and then the second
+ * half optionally merges all of the dies in the first half. First, we'll cover
+ * what's involved in converting a single ctf_die_t's dwarf to CTF. This covers
+ * the work done in ctf_dwarf_convert_one().
+ *
+ * An individual ctf_die_t, which represents a compilation unit, is converted to
+ * CTF in a series of multiple passes.
+ *
+ * Pass 1: During the first pass we walk all of the dies and if we find a
+ * function, variable, struct, union, enum or typedef, we recursively transform
+ * all of its types. We don't recurse or process everything, because we don't
+ * want to add some of the types that compilers may add which are effectively
+ * unused.
+ *
+ * During pass 1, if we encounter any structures or unions we mark them for
+ * fixing up later. This is necessary because we may not be able to determine
+ * the full size of a structure at the beginning of time. This will happen if
+ * the DWARF attribute DW_AT_byte_size is not present for a member. Because of
+ * this possibility we defer adding members to structures or even converting
+ * them during pass 1 and save that for pass 2. Adding all of the base
+ * structures without any of their members helps deal with any circular
+ * dependencies that we might encounter.
+ *
+ * Pass 2: This pass is used to do the first half of fixing up structures and
+ * unions. Rather than walk the entire type space again, we actually walk the
+ * list of structures and unions that we marked for later fixing up. Here, we
+ * iterate over every structure and add members to the underlying ctf_file_t,
+ * but not to the structs themselves. One might wonder why we don't, and the
+ * main reason is that libctf requires a ctf_update() be done before adding the
+ * members to structures or unions.
+ *
+ * Pass 3: This pass is used to do the second half of fixing up structures and
+ * unions. During this part we always go through and add members to structures
+ * and unions that we added to the container in the previous pass. In addition,
+ * we set the structure and union's actual size, which may have additional
+ * padding added by the compiler, it isn't simply the last offset. DWARF always
+ * guarantees an attribute exists for this. Importantly no ctf_id_t's change
+ * during pass 2.
+ *
+ * Pass 4: The next phase is to add CTF entries for all of the symbols and
+ * variables that are present in this die. During pass 1 we added entries to a
+ * map for each variable and function. During this pass, we iterate over the
+ * symbol table and when we encounter a symbol that we have in our lists of
+ * translated information which matches, we then add it to the ctf_file_t.
+ *
+ * Pass 5: Here we go and look for any weak symbols and functions and see if
+ * they match anything that we recognize. If so, then we add type information
+ * for them at this point based on the matching type.
+ *
+ * Pass 6: This pass is actually a variant on a merge. The traditional merge
+ * process expects there to be no duplicate types. As such, at the end of
+ * conversion, we do a dedup on all of the types in the system. The
+ * deduplication process is described in lib/libctf/common/ctf_merge.c.
+ *
+ * Once pass 6 is done, we've finished processing the individual compilation
+ * unit.
+ *
+ * The following steps reflect the general process of doing a conversion.
+ *
+ * 1) Walk the dwarf section and determine the number of compilation units
+ * 2) Create a ctf_die_t for each compilation unit
+ * 3) Add all ctf_die_t's to a workq
+ * 4) Have the workq process each die with ctf_dwarf_convert_one. This itself
+ * is comprised of several steps, which were already enumerated.
+ * 5) If we have multiple dies, we do a ctf merge of all the dies. The mechanics
+ * of the merge are discussed in lib/libctf/common/ctf_merge.c.
+ * 6) Free everything up and return a ctf_file_t to the user. If we only had a
+ * single compilation unit, then we give that to the user. Otherwise, we
+ * return the merged ctf_file_t.
+ *
+ * Threading
+ * ---------
+ *
+ * The process has been designed to be amenable to threading. Each compilation
+ * unit has its own type stream, therefore the logical place to divide and
+ * conquer is at the compilation unit. Each ctf_die_t has been built to be able
+ * to be processed independently of the others. It has its own libdwarf handle,
+ * as a given libdwarf handle may only be used by a single thread at a time.
+ * This allows the various ctf_die_t's to be processed in parallel by different
+ * threads.
+ *
+ * All of the ctf_die_t's are loaded into a workq which allows for a number of
+ * threads to be specified and used as a thread pool to process all of the
+ * queued work. We set the number of threads to use in the workq equal to the
+ * number of threads that the user has specified.
+ *
+ * After all of the compilation units have been drained, we use the same number
+ * of threads when performing a merge of multiple compilation units, if they
+ * exist.
+ *
+ * While all of these different parts do support and allow for multiple threads,
+ * it's important that when only a single thread is specified, that it be the
+ * calling thread. This allows the conversion routines to be used in a context
+ * that doesn't allow additional threads, such as rtld.
+ *
+ * Common DWARF Mechanics and Notes
+ * --------------------------------
+ *
+ * At this time, we really only support DWARFv2, though support for DWARFv4 is
+ * mostly there. There is no intent to support DWARFv3.
+ *
+ * Generally types for something are stored in the DW_AT_type attribute. For
+ * example, a function's return type will be stored in the local DW_AT_type
+ * attribute while the arguments will be in child DIEs. There are also various
+ * times when we don't have any DW_AT_type. In that case, the lack of a type
+ * implies, at least for C, that it's C type is void. Because DWARF doesn't emit
+ * one, we have a synthetic void type that we create and manipulate instead and
+ * pass it off to consumers on an as-needed basis. If nothing has a void type,
+ * it will not be emitted.
+ *
+ * Architecture Specific Parts
+ * ---------------------------
+ *
+ * The CTF tooling encodes various information about the various architectures
+ * in the system. Importantly, the tool assumes that every architecture has a
+ * data model where long and pointer are the same size. This is currently the
+ * case, as the two data models illumos supports are ILP32 and LP64.
+ *
+ * In addition, we encode the mapping of various floating point sizes to various
+ * types for each architecture. If a new architecture is being added, it should
+ * be added to the list. The general design of the ctf conversion tools is to be
+ * architecture independent. eg. any of the tools here should be able to convert
+ * any architecture's DWARF into ctf; however, this has not been rigorously
+ * tested and more importantly, the ctf routines don't currently write out the
+ * data in an endian-aware form, they only use that of the currently running
+ * library.
+ */
+
+#include <libctf_impl.h>
+#include <sys/avl.h>
+#include <sys/debug.h>
+#include <gelf.h>
+#include <libdwarf.h>
+#include <dwarf.h>
+#include <libgen.h>
+#include <workq.h>
+#include <errno.h>
+
+#define DWARF_VERSION_TWO 2
+#define DWARF_VARARGS_NAME "..."
+
+/*
+ * Dwarf may refer recursively to other types that we've already processed. To
+ * see if we've already converted them, we look them up in an AVL tree that's
+ * sorted by the DWARF id.
+ */
+typedef struct ctf_dwmap {
+ avl_node_t cdm_avl;
+ Dwarf_Off cdm_off;
+ Dwarf_Die cdm_die;
+ ctf_id_t cdm_id;
+ boolean_t cdm_fix;
+} ctf_dwmap_t;
+
+typedef struct ctf_dwvar {
+ ctf_list_t cdv_list;
+ char *cdv_name;
+ ctf_id_t cdv_type;
+ boolean_t cdv_global;
+} ctf_dwvar_t;
+
+typedef struct ctf_dwfunc {
+ ctf_list_t cdf_list;
+ char *cdf_name;
+ ctf_funcinfo_t cdf_fip;
+ ctf_id_t *cdf_argv;
+ boolean_t cdf_global;
+} ctf_dwfunc_t;
+
+typedef struct ctf_dwbitf {
+ ctf_list_t cdb_list;
+ ctf_id_t cdb_base;
+ uint_t cdb_nbits;
+ ctf_id_t cdb_id;
+} ctf_dwbitf_t;
+
+/*
+ * The ctf_die_t represents a single top-level DWARF die unit. While generally,
+ * the typical object file hs only a single die, if we're asked to convert
+ * something that's been linked from multiple sources, multiple dies will exist.
+ */
+typedef struct ctf_die {
+ Elf *cd_elf; /* shared libelf handle */
+ char *cd_name; /* basename of the DIE */
+ ctf_merge_t *cd_cmh; /* merge handle */
+ ctf_list_t cd_vars; /* List of variables */
+ ctf_list_t cd_funcs; /* List of functions */
+ ctf_list_t cd_bitfields; /* Bit field members */
+ Dwarf_Debug cd_dwarf; /* shared libdwarf handle */
+ Dwarf_Die cd_cu; /* libdwarf compilation unit */
+ Dwarf_Off cd_cuoff; /* cu's offset */
+ Dwarf_Off cd_maxoff; /* maximum offset */
+ ctf_file_t *cd_ctfp; /* output CTF file */
+ avl_tree_t cd_map; /* map die offsets to CTF types */
+ char *cd_errbuf; /* error message buffer */
+ size_t cd_errlen; /* error message buffer length */
+ size_t cd_ptrsz; /* object's pointer size */
+ boolean_t cd_bigend; /* is it big endian */
+ uint_t cd_mach; /* machine type */
+ ctf_id_t cd_voidtid; /* void pointer */
+ ctf_id_t cd_longtid; /* id for a 'long' */
+} ctf_die_t;
+
+static int ctf_dwarf_offset(ctf_die_t *, Dwarf_Die, Dwarf_Off *);
+static int ctf_dwarf_convert_die(ctf_die_t *, Dwarf_Die);
+static int ctf_dwarf_convert_type(ctf_die_t *, Dwarf_Die, ctf_id_t *, int);
+
+static int ctf_dwarf_function_count(ctf_die_t *, Dwarf_Die, ctf_funcinfo_t *,
+ boolean_t);
+static int ctf_dwarf_convert_fargs(ctf_die_t *, Dwarf_Die, ctf_funcinfo_t *,
+ ctf_id_t *);
+
+typedef int (ctf_dwarf_symtab_f)(ctf_die_t *, const GElf_Sym *, ulong_t,
+ const char *, const char *, void *);
+
+/*
+ * This is a generic way to set a CTF Conversion backend error depending on what
+ * we were doing. Unless it was one of a specific set of errors that don't
+ * indicate a programming / translation bug, eg. ENOMEM, then we transform it
+ * into a CTF backend error and fill in the error buffer.
+ */
+static int
+ctf_dwarf_error(ctf_die_t *cdp, ctf_file_t *cfp, int err, const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+ size_t off = 0;
+ ssize_t rem = cdp->cd_errlen;
+ if (cfp != NULL)
+ err = ctf_errno(cfp);
+
+ if (err == ENOMEM)
+ return (err);
+
+ ret = snprintf(cdp->cd_errbuf, rem, "die %s: ", cdp->cd_name);
+ if (ret < 0)
+ goto err;
+ off += ret;
+ rem = MAX(rem - ret, 0);
+
+ va_start(ap, fmt);
+ ret = vsnprintf(cdp->cd_errbuf + off, rem, fmt, ap);
+ va_end(ap);
+ if (ret < 0)
+ goto err;
+
+ off += ret;
+ rem = MAX(rem - ret, 0);
+ if (fmt[strlen(fmt) - 1] != '\n') {
+ (void) snprintf(cdp->cd_errbuf + off, rem,
+ ": %s\n", ctf_errmsg(err));
+ }
+ va_end(ap);
+ return (ECTF_CONVBKERR);
+
+err:
+ cdp->cd_errbuf[0] = '\0';
+ return (ECTF_CONVBKERR);
+}
+
+/*
+ * DWARF often ops to put no explicit type to describe a void type. eg. if we
+ * have a reference type whose DW_AT_type member doesn't exist, then we should
+ * instead assume it points to void. Because this isn't represented, we
+ * instead cause it to come into existence.
+ */
+static ctf_id_t
+ctf_dwarf_void(ctf_die_t *cdp)
+{
+ if (cdp->cd_voidtid == CTF_ERR) {
+ ctf_encoding_t enc = { CTF_INT_SIGNED, 0, 0 };
+ cdp->cd_voidtid = ctf_add_integer(cdp->cd_ctfp, CTF_ADD_ROOT,
+ "void", &enc);
+ if (cdp->cd_voidtid == CTF_ERR) {
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to create void type: %s\n",
+ ctf_errmsg(ctf_errno(cdp->cd_ctfp)));
+ }
+ }
+
+ return (cdp->cd_voidtid);
+}
+
+/*
+ * There are many different forms that an array index may take. However, we just
+ * always force it to be of a type long no matter what. Therefore we use this to
+ * have a single instance of long across everything.
+ */
+static ctf_id_t
+ctf_dwarf_long(ctf_die_t *cdp)
+{
+ if (cdp->cd_longtid == CTF_ERR) {
+ ctf_encoding_t enc;
+
+ enc.cte_format = CTF_INT_SIGNED;
+ enc.cte_offset = 0;
+ /* All illumos systems are LP */
+ enc.cte_bits = cdp->cd_ptrsz * 8;
+ cdp->cd_longtid = ctf_add_integer(cdp->cd_ctfp, CTF_ADD_NONROOT,
+ "long", &enc);
+ if (cdp->cd_longtid == CTF_ERR) {
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to create long type: %s\n",
+ ctf_errmsg(ctf_errno(cdp->cd_ctfp)));
+ }
+
+ }
+
+ return (cdp->cd_longtid);
+}
+
+static int
+ctf_dwmap_comp(const void *a, const void *b)
+{
+ const ctf_dwmap_t *ca = a;
+ const ctf_dwmap_t *cb = b;
+
+ if (ca->cdm_off > cb->cdm_off)
+ return (1);
+ if (ca->cdm_off < cb->cdm_off)
+ return (-1);
+ return (0);
+}
+
+static int
+ctf_dwmap_add(ctf_die_t *cdp, ctf_id_t id, Dwarf_Die die, boolean_t fix)
+{
+ int ret;
+ avl_index_t index;
+ ctf_dwmap_t *dwmap;
+ Dwarf_Off off;
+
+ VERIFY(id > 0 && id < CTF_MAX_TYPE);
+
+ if ((ret = ctf_dwarf_offset(cdp, die, &off)) != 0)
+ return (ret);
+
+ if ((dwmap = ctf_alloc(sizeof (ctf_dwmap_t))) == NULL)
+ return (ENOMEM);
+
+ dwmap->cdm_die = die;
+ dwmap->cdm_off = off;
+ dwmap->cdm_id = id;
+ dwmap->cdm_fix = fix;
+
+ ctf_dprintf("dwmap: %p %x->%d\n", dwmap, (uint32_t)off, id);
+ VERIFY(avl_find(&cdp->cd_map, dwmap, &index) == NULL);
+ avl_insert(&cdp->cd_map, dwmap, index);
+ return (0);
+}
+
+static int
+ctf_dwarf_attribute(ctf_die_t *cdp, Dwarf_Die die, Dwarf_Half name,
+ Dwarf_Attribute *attrp)
+{
+ int ret;
+ Dwarf_Error derr;
+
+ if ((ret = dwarf_attr(die, name, attrp, &derr)) == DW_DLV_OK)
+ return (0);
+ if (ret == DW_DLV_NO_ENTRY) {
+ *attrp = NULL;
+ return (ENOENT);
+ }
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to get attribute for type: %s\n",
+ dwarf_errmsg(derr));
+ return (ECTF_CONVBKERR);
+}
+
+static int
+ctf_dwarf_ref(ctf_die_t *cdp, Dwarf_Die die, Dwarf_Half name, Dwarf_Off *refp)
+{
+ int ret;
+ Dwarf_Attribute attr;
+ Dwarf_Error derr;
+
+ if ((ret = ctf_dwarf_attribute(cdp, die, name, &attr)) != 0)
+ return (ret);
+
+ if (dwarf_formref(attr, refp, &derr) == DW_DLV_OK) {
+ dwarf_dealloc(cdp->cd_dwarf, attr, DW_DLA_ATTR);
+ return (0);
+ }
+
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to get unsigned attribute for type: %s\n",
+ dwarf_errmsg(derr));
+ return (ECTF_CONVBKERR);
+}
+
+static int
+ctf_dwarf_refdie(ctf_die_t *cdp, Dwarf_Die die, Dwarf_Half name,
+ Dwarf_Die *diep)
+{
+ int ret;
+ Dwarf_Off off;
+ Dwarf_Error derr;
+
+ if ((ret = ctf_dwarf_ref(cdp, die, DW_AT_type, &off)) != 0)
+ return (ret);
+
+ off += cdp->cd_cuoff;
+ if ((ret = dwarf_offdie(cdp->cd_dwarf, off, diep, &derr)) !=
+ DW_DLV_OK) {
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to get die from offset %llu: %s\n",
+ off, dwarf_errmsg(derr));
+ return (ECTF_CONVBKERR);
+ }
+
+ return (0);
+}
+
+static int
+ctf_dwarf_signed(ctf_die_t *cdp, Dwarf_Die die, Dwarf_Half name,
+ Dwarf_Signed *valp)
+{
+ int ret;
+ Dwarf_Attribute attr;
+ Dwarf_Error derr;
+
+ if ((ret = ctf_dwarf_attribute(cdp, die, name, &attr)) != 0)
+ return (ret);
+
+ if (dwarf_formsdata(attr, valp, &derr) == DW_DLV_OK) {
+ dwarf_dealloc(cdp->cd_dwarf, attr, DW_DLA_ATTR);
+ return (0);
+ }
+
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to get unsigned attribute for type: %s\n",
+ dwarf_errmsg(derr));
+ return (ECTF_CONVBKERR);
+}
+
+static int
+ctf_dwarf_unsigned(ctf_die_t *cdp, Dwarf_Die die, Dwarf_Half name,
+ Dwarf_Unsigned *valp)
+{
+ int ret;
+ Dwarf_Attribute attr;
+ Dwarf_Error derr;
+
+ if ((ret = ctf_dwarf_attribute(cdp, die, name, &attr)) != 0)
+ return (ret);
+
+ if (dwarf_formudata(attr, valp, &derr) == DW_DLV_OK) {
+ dwarf_dealloc(cdp->cd_dwarf, attr, DW_DLA_ATTR);
+ return (0);
+ }
+
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to get unsigned attribute for type: %s\n",
+ dwarf_errmsg(derr));
+ return (ECTF_CONVBKERR);
+}
+
+static int
+ctf_dwarf_boolean(ctf_die_t *cdp, Dwarf_Die die, Dwarf_Half name,
+ Dwarf_Bool *val)
+{
+ int ret;
+ Dwarf_Attribute attr;
+ Dwarf_Error derr;
+
+ if ((ret = ctf_dwarf_attribute(cdp, die, name, &attr)) != 0)
+ return (ret);
+
+ if (dwarf_formflag(attr, val, &derr) == DW_DLV_OK) {
+ dwarf_dealloc(cdp->cd_dwarf, attr, DW_DLA_ATTR);
+ return (0);
+ }
+
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to get boolean attribute for type: %s\n",
+ dwarf_errmsg(derr));
+
+ return (ECTF_CONVBKERR);
+}
+
+static int
+ctf_dwarf_string(ctf_die_t *cdp, Dwarf_Die die, Dwarf_Half name, char **strp)
+{
+ int ret;
+ char *s;
+ Dwarf_Attribute attr;
+ Dwarf_Error derr;
+
+ *strp = NULL;
+ if ((ret = ctf_dwarf_attribute(cdp, die, name, &attr)) != 0)
+ return (ret);
+
+ if (dwarf_formstring(attr, &s, &derr) == DW_DLV_OK) {
+ if ((*strp = ctf_strdup(s)) == NULL)
+ ret = ENOMEM;
+ else
+ ret = 0;
+ dwarf_dealloc(cdp->cd_dwarf, attr, DW_DLA_ATTR);
+ return (ret);
+ }
+
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to get string attribute for type: %s\n",
+ dwarf_errmsg(derr));
+ return (ECTF_CONVBKERR);
+}
+
+static int
+ctf_dwarf_member_location(ctf_die_t *cdp, Dwarf_Die die, Dwarf_Unsigned *valp)
+{
+ int ret;
+ Dwarf_Error derr;
+ Dwarf_Attribute attr;
+ Dwarf_Locdesc *loc;
+ Dwarf_Signed locnum;
+
+ if ((ret = ctf_dwarf_attribute(cdp, die, DW_AT_data_member_location,
+ &attr)) != 0)
+ return (ret);
+
+ if (dwarf_loclist(attr, &loc, &locnum, &derr) != DW_DLV_OK) {
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to obtain location list for member offset: %s",
+ dwarf_errmsg(derr));
+ dwarf_dealloc(cdp->cd_dwarf, attr, DW_DLA_ATTR);
+ return (ECTF_CONVBKERR);
+ }
+ dwarf_dealloc(cdp->cd_dwarf, attr, DW_DLA_ATTR);
+
+ if (locnum != 1 || loc->ld_s->lr_atom != DW_OP_plus_uconst) {
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to parse location structure for member");
+ dwarf_dealloc(cdp->cd_dwarf, loc->ld_s, DW_DLA_LOC_BLOCK);
+ dwarf_dealloc(cdp->cd_dwarf, loc, DW_DLA_LOCDESC);
+ return (ECTF_CONVBKERR);
+ }
+
+ *valp = loc->ld_s->lr_number;
+
+ dwarf_dealloc(cdp->cd_dwarf, loc->ld_s, DW_DLA_LOC_BLOCK);
+ dwarf_dealloc(cdp->cd_dwarf, loc, DW_DLA_LOCDESC);
+ return (0);
+}
+
+
+static int
+ctf_dwarf_offset(ctf_die_t *cdp, Dwarf_Die die, Dwarf_Off *offsetp)
+{
+ Dwarf_Error derr;
+
+ if (dwarf_dieoffset(die, offsetp, &derr) == DW_DLV_OK)
+ return (0);
+
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to get die offset: %s\n",
+ dwarf_errmsg(derr));
+ return (ECTF_CONVBKERR);
+}
+
+static int
+ctf_dwarf_tag(ctf_die_t *cdp, Dwarf_Die die, Dwarf_Half *tagp)
+{
+ Dwarf_Error derr;
+
+ if (dwarf_tag(die, tagp, &derr) == DW_DLV_OK)
+ return (0);
+
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to get tag type: %s\n",
+ dwarf_errmsg(derr));
+ return (ECTF_CONVBKERR);
+}
+
+static int
+ctf_dwarf_sib(ctf_die_t *cdp, Dwarf_Die base, Dwarf_Die *sibp)
+{
+ Dwarf_Error derr;
+ int ret;
+
+ *sibp = NULL;
+ ret = dwarf_siblingof(cdp->cd_dwarf, base, sibp, &derr);
+ if (ret == DW_DLV_OK || ret == DW_DLV_NO_ENTRY)
+ return (0);
+
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to sibling from die: %s\n",
+ dwarf_errmsg(derr));
+ return (ECTF_CONVBKERR);
+}
+
+static int
+ctf_dwarf_child(ctf_die_t *cdp, Dwarf_Die base, Dwarf_Die *childp)
+{
+ Dwarf_Error derr;
+ int ret;
+
+ *childp = NULL;
+ ret = dwarf_child(base, childp, &derr);
+ if (ret == DW_DLV_OK || ret == DW_DLV_NO_ENTRY)
+ return (0);
+
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to child from die: %s\n",
+ dwarf_errmsg(derr));
+ return (ECTF_CONVBKERR);
+}
+
+/*
+ * Compilers disagree on what to do to determine if something has global
+ * visiblity. Traditionally gcc has used DW_AT_external to indicate this while
+ * Studio has used DW_AT_visibility. We check DW_AT_visibility first and then
+ * fall back to DW_AT_external. Lack of DW_AT_external implies that it is not.
+ */
+static int
+ctf_dwarf_isglobal(ctf_die_t *cdp, Dwarf_Die die, boolean_t *igp)
+{
+ int ret;
+ Dwarf_Signed vis;
+ Dwarf_Bool ext;
+
+ if ((ret = ctf_dwarf_signed(cdp, die, DW_AT_visibility, &vis)) == 0) {
+ *igp = vis == DW_VIS_exported;
+ return (0);
+ } else if (ret != ENOENT) {
+ return (ret);
+ }
+
+ if ((ret = ctf_dwarf_boolean(cdp, die, DW_AT_external, &ext)) != 0) {
+ if (ret == ENOENT) {
+ *igp = B_FALSE;
+ return (0);
+ }
+ return (ret);
+ }
+ *igp = ext != 0 ? B_TRUE : B_FALSE;
+ return (0);
+}
+
+static int
+ctf_dwarf_die_elfenc(Elf *elf, ctf_die_t *cdp, char *errbuf, size_t errlen)
+{
+ GElf_Ehdr ehdr;
+
+ if (gelf_getehdr(elf, &ehdr) == NULL) {
+ (void) snprintf(errbuf, errlen,
+ "failed to get ELF header: %s\n",
+ elf_errmsg(elf_errno()));
+ return (ECTF_CONVBKERR);
+ }
+
+ cdp->cd_mach = ehdr.e_machine;
+
+ if (ehdr.e_ident[EI_CLASS] == ELFCLASS32) {
+ cdp->cd_ptrsz = 4;
+ VERIFY(ctf_setmodel(cdp->cd_ctfp, CTF_MODEL_ILP32) == 0);
+ } else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) {
+ cdp->cd_ptrsz = 8;
+ VERIFY(ctf_setmodel(cdp->cd_ctfp, CTF_MODEL_LP64) == 0);
+ } else {
+ (void) snprintf(errbuf, errlen,
+ "unknown ELF class %d", ehdr.e_ident[EI_CLASS]);
+ return (ECTF_CONVBKERR);
+ }
+
+ if (ehdr.e_ident[EI_DATA] == ELFDATA2LSB) {
+ cdp->cd_bigend = B_FALSE;
+ } else if (ehdr.e_ident[EI_DATA] == ELFDATA2MSB) {
+ cdp->cd_bigend = B_TRUE;
+ } else {
+ (void) snprintf(errbuf, errlen,
+ "unknown ELF data encoding: %d", ehdr.e_ident[EI_DATA]);
+ return (ECTF_CONVBKERR);
+ }
+
+ return (0);
+}
+
+typedef struct ctf_dwarf_fpent {
+ size_t cdfe_size;
+ uint_t cdfe_enc[3];
+} ctf_dwarf_fpent_t;
+
+typedef struct ctf_dwarf_fpmap {
+ uint_t cdf_mach;
+ ctf_dwarf_fpent_t cdf_ents[4];
+} ctf_dwarf_fpmap_t;
+
+static const ctf_dwarf_fpmap_t ctf_dwarf_fpmaps[] = {
+ { EM_SPARC, {
+ { 4, { CTF_FP_SINGLE, CTF_FP_CPLX, CTF_FP_IMAGRY } },
+ { 8, { CTF_FP_DOUBLE, CTF_FP_DCPLX, CTF_FP_DIMAGRY } },
+ { 16, { CTF_FP_LDOUBLE, CTF_FP_LDCPLX, CTF_FP_LDIMAGRY } },
+ { 0, { 0 } }
+ } },
+ { EM_SPARC32PLUS, {
+ { 4, { CTF_FP_SINGLE, CTF_FP_CPLX, CTF_FP_IMAGRY } },
+ { 8, { CTF_FP_DOUBLE, CTF_FP_DCPLX, CTF_FP_DIMAGRY } },
+ { 16, { CTF_FP_LDOUBLE, CTF_FP_LDCPLX, CTF_FP_LDIMAGRY } },
+ { 0, { 0 } }
+ } },
+ { EM_SPARCV9, {
+ { 4, { CTF_FP_SINGLE, CTF_FP_CPLX, CTF_FP_IMAGRY } },
+ { 8, { CTF_FP_DOUBLE, CTF_FP_DCPLX, CTF_FP_DIMAGRY } },
+ { 16, { CTF_FP_LDOUBLE, CTF_FP_LDCPLX, CTF_FP_LDIMAGRY } },
+ { 0, { 0 } }
+ } },
+ { EM_386, {
+ { 4, { CTF_FP_SINGLE, CTF_FP_CPLX, CTF_FP_IMAGRY } },
+ { 8, { CTF_FP_DOUBLE, CTF_FP_DCPLX, CTF_FP_DIMAGRY } },
+ { 12, { CTF_FP_LDOUBLE, CTF_FP_LDCPLX, CTF_FP_LDIMAGRY } },
+ { 0, { 0 } }
+ } },
+ { EM_X86_64, {
+ { 4, { CTF_FP_SINGLE, CTF_FP_CPLX, CTF_FP_IMAGRY } },
+ { 8, { CTF_FP_DOUBLE, CTF_FP_DCPLX, CTF_FP_DIMAGRY } },
+ { 16, { CTF_FP_LDOUBLE, CTF_FP_LDCPLX, CTF_FP_LDIMAGRY } },
+ { 0, { 0 } }
+ } },
+ { EM_NONE }
+};
+
+static int
+ctf_dwarf_float_base(ctf_die_t *cdp, Dwarf_Signed type, ctf_encoding_t *enc)
+{
+ const ctf_dwarf_fpmap_t *map = &ctf_dwarf_fpmaps[0];
+ const ctf_dwarf_fpent_t *ent;
+ uint_t col = 0, mult = 1;
+
+ for (map = &ctf_dwarf_fpmaps[0]; map->cdf_mach != EM_NONE; map++) {
+ if (map->cdf_mach == cdp->cd_mach)
+ break;
+ }
+
+ if (map->cdf_mach == EM_NONE) {
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "Unsupported machine type: %d\n", cdp->cd_mach);
+ return (ENOTSUP);
+ }
+
+ if (type == DW_ATE_complex_float) {
+ mult = 2;
+ col = 1;
+ } else if (type == DW_ATE_imaginary_float ||
+ type == DW_ATE_SUN_imaginary_float) {
+ col = 2;
+ }
+
+ ent = &map->cdf_ents[0];
+ for (ent = &map->cdf_ents[0]; ent->cdfe_size != 0; ent++) {
+ if (ent->cdfe_size * mult * 8 == enc->cte_bits) {
+ enc->cte_format = ent->cdfe_enc[col];
+ return (0);
+ }
+ }
+
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to find valid fp mapping for encoding %d, size %d bits\n",
+ type, enc->cte_bits);
+ return (EINVAL);
+}
+
+static int
+ctf_dwarf_dwarf_base(ctf_die_t *cdp, Dwarf_Die die, int *kindp,
+ ctf_encoding_t *enc)
+{
+ int ret;
+ Dwarf_Signed type;
+
+ if ((ret = ctf_dwarf_signed(cdp, die, DW_AT_encoding, &type)) != 0)
+ return (ret);
+
+ switch (type) {
+ case DW_ATE_unsigned:
+ case DW_ATE_address:
+ *kindp = CTF_K_INTEGER;
+ enc->cte_format = 0;
+ break;
+ case DW_ATE_unsigned_char:
+ *kindp = CTF_K_INTEGER;
+ enc->cte_format = CTF_INT_CHAR;
+ break;
+ case DW_ATE_signed:
+ *kindp = CTF_K_INTEGER;
+ enc->cte_format = CTF_INT_SIGNED;
+ break;
+ case DW_ATE_signed_char:
+ *kindp = CTF_K_INTEGER;
+ enc->cte_format = CTF_INT_SIGNED | CTF_INT_CHAR;
+ break;
+ case DW_ATE_boolean:
+ *kindp = CTF_K_INTEGER;
+ enc->cte_format = CTF_INT_SIGNED | CTF_INT_BOOL;
+ break;
+ case DW_ATE_float:
+ case DW_ATE_complex_float:
+ case DW_ATE_imaginary_float:
+ case DW_ATE_SUN_imaginary_float:
+ case DW_ATE_SUN_interval_float:
+ *kindp = CTF_K_FLOAT;
+ if ((ret = ctf_dwarf_float_base(cdp, type, enc)) != 0)
+ return (ret);
+ break;
+ default:
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "encountered unkown DWARF encoding: %d", type);
+ return (ECTF_CONVBKERR);
+ }
+
+ return (0);
+}
+
+/*
+ * Different compilers (at least GCC and Studio) use different names for types.
+ * This parses the types and attempts to unify them. If this fails, we just fall
+ * back to using the DWARF itself.
+ */
+static int
+ctf_dwarf_parse_base(const char *name, int *kindp, ctf_encoding_t *enc,
+ char **newnamep)
+{
+ char buf[256];
+ char *base, *c;
+ int nlong = 0, nshort = 0, nchar = 0, nint = 0;
+ int sign = 1;
+
+ if (strlen(name) + 1 > sizeof (buf))
+ return (EINVAL);
+
+ (void) strlcpy(buf, name, sizeof (buf));
+ for (c = strtok(buf, " "); c != NULL; c = strtok(NULL, " ")) {
+ if (strcmp(c, "signed") == 0) {
+ sign = 1;
+ } else if (strcmp(c, "unsigned") == 0) {
+ sign = 0;
+ } else if (strcmp(c, "long") == 0) {
+ nlong++;
+ } else if (strcmp(c, "char") == 0) {
+ nchar++;
+ } else if (strcmp(c, "short") == 0) {
+ nshort++;
+ } else if (strcmp(c, "int") == 0) {
+ nint++;
+ } else {
+ /*
+ * If we don't recognize any of the tokens, we'll tell
+ * the caller to fall back to the dwarf-provided
+ * encoding information.
+ */
+ return (EINVAL);
+ }
+ }
+
+ if (nchar > 1 || nshort > 1 || nint > 1 || nlong > 2)
+ return (EINVAL);
+
+ if (nchar > 0) {
+ if (nlong > 0 || nshort > 0 || nint > 0)
+ return (EINVAL);
+ base = "char";
+ } else if (nshort > 0) {
+ if (nlong > 0)
+ return (EINVAL);
+ base = "short";
+ } else if (nlong > 0) {
+ base = "long";
+ } else {
+ base = "int";
+ }
+
+ if (nchar > 0)
+ enc->cte_format = CTF_INT_CHAR;
+ else
+ enc->cte_format = 0;
+
+ if (sign > 0)
+ enc->cte_format |= CTF_INT_SIGNED;
+
+ (void) snprintf(buf, sizeof (buf), "%s%s%s",
+ (sign ? "" : "unsigned "),
+ (nlong > 1 ? "long " : ""),
+ base);
+
+ *newnamep = ctf_strdup(buf);
+ if (*newnamep == NULL)
+ return (ENOMEM);
+ *kindp = CTF_K_INTEGER;
+ return (0);
+}
+
+static int
+ctf_dwarf_create_base(ctf_die_t *cdp, Dwarf_Die die, ctf_id_t *idp, int isroot,
+ Dwarf_Off off)
+{
+ int ret;
+ char *name, *nname;
+ Dwarf_Unsigned sz;
+ int kind;
+ ctf_encoding_t enc;
+ ctf_id_t id;
+
+ if ((ret = ctf_dwarf_string(cdp, die, DW_AT_name, &name)) != 0)
+ return (ret);
+ if ((ret = ctf_dwarf_unsigned(cdp, die, DW_AT_byte_size, &sz)) != 0) {
+ goto out;
+ }
+ ctf_dprintf("Creating base type %s from off %llu, size: %d\n", name,
+ off, sz);
+
+ bzero(&enc, sizeof (ctf_encoding_t));
+ enc.cte_bits = sz * 8;
+ if ((ret = ctf_dwarf_parse_base(name, &kind, &enc, &nname)) == 0) {
+ ctf_free(name, strlen(name) + 1);
+ name = nname;
+ } else {
+ if (ret != EINVAL)
+ return (ret);
+ ctf_dprintf("falling back to dwarf for base type %s\n", name);
+ if ((ret = ctf_dwarf_dwarf_base(cdp, die, &kind, &enc)) != 0)
+ return (ret);
+ }
+
+ id = ctf_add_encoded(cdp->cd_ctfp, isroot, name, &enc, kind);
+ if (id == CTF_ERR) {
+ ret = ctf_errno(cdp->cd_ctfp);
+ } else {
+ *idp = id;
+ ret = ctf_dwmap_add(cdp, id, die, B_FALSE);
+ }
+out:
+ ctf_free(name, strlen(name) + 1);
+ return (ret);
+}
+
+/*
+ * Getting a member's offset is a surprisingly intricate dance. It works as
+ * follows:
+ *
+ * 1) If we're in DWARFv4, then we either have a DW_AT_data_bit_offset or we
+ * have a DW_AT_data_member_location. We won't have both. Thus we check first
+ * for DW_AT_data_bit_offset, and if it exists, we're set.
+ *
+ * Next, if we have a bitfield and we don't ahve a DW_AT_data_bit_offset, then
+ * we have to grab the data location and use the following dance:
+ *
+ * 2) Gather the set of DW_AT_byte_size, DW_AT_bit_offset, and DW_AT_bit_size.
+ * Of course, the DW_AT_byte_size may be omitted, even though it isn't always.
+ * When it's been omitted, we then have to say that the size is that of the
+ * underlying type, which forces that to be after a ctf_update(). Here, we have
+ * to do different things based on whether or not we're using big endian or
+ * little endian to obtain the proper offset.
+ */
+static int
+ctf_dwarf_member_offset(ctf_die_t *cdp, Dwarf_Die die, ctf_id_t mid,
+ ulong_t *offp)
+{
+ int ret;
+ Dwarf_Unsigned loc, bitsz, bytesz, bitoff;
+ size_t off, tsz;
+
+ if ((ret = ctf_dwarf_unsigned(cdp, die, DW_AT_data_bit_offset,
+ &loc)) == 0) {
+ *offp = loc;
+ return (0);
+ } else if (ret != ENOENT) {
+ return (ret);
+ }
+
+ if ((ret = ctf_dwarf_member_location(cdp, die, &loc)) != 0)
+ return (ret);
+ off = loc * 8;
+
+ if ((ret = ctf_dwarf_unsigned(cdp, die, DW_AT_bit_offset,
+ &bitoff)) != 0) {
+ if (ret != ENOENT)
+ return (ret);
+ *offp = off;
+ return (0);
+ }
+
+ /* At this point we have to have DW_AT_bit_size */
+ if ((ret = ctf_dwarf_unsigned(cdp, die, DW_AT_bit_size, &bitsz)) != 0)
+ return (ret);
+
+ if ((ret = ctf_dwarf_unsigned(cdp, die, DW_AT_byte_size,
+ &bytesz)) != 0) {
+ if (ret != ENOENT)
+ return (ret);
+ if ((tsz = ctf_type_size(cdp->cd_ctfp, mid)) == CTF_ERR) {
+ int e = ctf_errno(cdp->cd_ctfp);
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to get type size: %s", ctf_errmsg(e));
+ return (ECTF_CONVBKERR);
+ }
+ } else {
+ tsz = bytesz;
+ }
+ tsz *= 8;
+ if (cdp->cd_bigend == B_TRUE) {
+ *offp = off + bitoff;
+ } else {
+ *offp = off + tsz - bitoff - bitsz;
+ }
+
+ return (0);
+}
+
+/*
+ * We need to determine if the member in question is a bitfield. If it is, then
+ * we need to go through and create a new type that's based on the actual base
+ * type, but has a different size. We also rename the type as a result to help
+ * deal with future collisions.
+ *
+ * Here we need to look and see if we have a DW_AT_bit_size value. If we have a
+ * bit size member and it does not equal the byte size member, then we need to
+ * create a bitfield type based on this.
+ *
+ * Note: When we support DWARFv4, there may be a chance that we ned to also
+ * search for the DW_AT_byte_size if we don't have a DW_AT_bit_size member.
+ */
+static int
+ctf_dwarf_member_bitfield(ctf_die_t *cdp, Dwarf_Die die, ctf_id_t *idp)
+{
+ int ret;
+ Dwarf_Unsigned bitsz;
+ ctf_encoding_t e;
+ ctf_dwbitf_t *cdb;
+ ctf_dtdef_t *dtd;
+ ctf_id_t base = *idp;
+ int kind;
+
+ if ((ret = ctf_dwarf_unsigned(cdp, die, DW_AT_bit_size, &bitsz)) != 0) {
+ if (ret == ENOENT)
+ return (0);
+ return (ret);
+ }
+
+ ctf_dprintf("Trying to deal with bitfields on %d:%d\n", base, bitsz);
+ /*
+ * Given that we now have a bitsize, time to go do something about it.
+ * We're going to create a new type based on the current one, but first
+ * we need to find the base type. This means we need to traverse any
+ * typedef's, consts, and volatiles until we get to what should be
+ * something of type integer or enumeration.
+ */
+ VERIFY(bitsz < UINT32_MAX);
+ dtd = ctf_dtd_lookup(cdp->cd_ctfp, base);
+ VERIFY(dtd != NULL);
+ kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info);
+ while (kind == CTF_K_TYPEDEF || kind == CTF_K_CONST ||
+ kind == CTF_K_VOLATILE) {
+ dtd = ctf_dtd_lookup(cdp->cd_ctfp, dtd->dtd_data.ctt_type);
+ VERIFY(dtd != NULL);
+ kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info);
+ }
+ ctf_dprintf("got kind %d\n", kind);
+ VERIFY(kind == CTF_K_INTEGER || kind == CTF_K_ENUM);
+
+ /*
+ * As surprising as it may be, it is strictly possible to create a
+ * bitfield that is based on an enum. Of course, the C standard leaves
+ * enums sizing as an ABI concern more or less. To that effect, today on
+ * all illumos platforms the size of an enum is generally that of an
+ * int as our supported data models and ABIs all agree on that. So what
+ * we'll do is fake up a CTF enconding here to use. In this case, we'll
+ * treat it as an unsigned value of whatever size the underlying enum
+ * currently has (which is in the ctt_size member of its dynamic type
+ * data).
+ */
+ if (kind == CTF_K_INTEGER) {
+ e = dtd->dtd_u.dtu_enc;
+ } else {
+ bzero(&e, sizeof (ctf_encoding_t));
+ e.cte_bits = dtd->dtd_data.ctt_size * NBBY;
+ }
+
+ for (cdb = ctf_list_next(&cdp->cd_bitfields); cdb != NULL;
+ cdb = ctf_list_next(cdb)) {
+ if (cdb->cdb_base == base && cdb->cdb_nbits == bitsz)
+ break;
+ }
+
+ /*
+ * Create a new type if none exists. We name all types in a way that is
+ * guaranteed not to conflict with the corresponding C type. We do this
+ * by using the ':' operator.
+ */
+ if (cdb == NULL) {
+ size_t namesz;
+ char *name;
+
+ e.cte_bits = bitsz;
+ namesz = snprintf(NULL, 0, "%s:%d", dtd->dtd_name,
+ (uint32_t)bitsz);
+ name = ctf_alloc(namesz + 1);
+ if (name == NULL)
+ return (ENOMEM);
+ cdb = ctf_alloc(sizeof (ctf_dwbitf_t));
+ if (cdb == NULL) {
+ ctf_free(name, namesz + 1);
+ return (ENOMEM);
+ }
+ (void) snprintf(name, namesz + 1, "%s:%d", dtd->dtd_name,
+ (uint32_t)bitsz);
+
+ cdb->cdb_base = base;
+ cdb->cdb_nbits = bitsz;
+ cdb->cdb_id = ctf_add_integer(cdp->cd_ctfp, CTF_ADD_NONROOT,
+ name, &e);
+ if (cdb->cdb_id == CTF_ERR) {
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to get add bitfield type %s: %s", name,
+ ctf_errmsg(ctf_errno(cdp->cd_ctfp)));
+ ctf_free(name, namesz + 1);
+ ctf_free(cdb, sizeof (ctf_dwbitf_t));
+ return (ECTF_CONVBKERR);
+ }
+ ctf_free(name, namesz + 1);
+ ctf_list_append(&cdp->cd_bitfields, cdb);
+ }
+
+ *idp = cdb->cdb_id;
+
+ return (0);
+}
+
+static int
+ctf_dwarf_fixup_sou(ctf_die_t *cdp, Dwarf_Die die, ctf_id_t base, boolean_t add)
+{
+ int ret, kind;
+ Dwarf_Die child, memb;
+ Dwarf_Unsigned size;
+ ulong_t nsz;
+
+ kind = ctf_type_kind(cdp->cd_ctfp, base);
+ VERIFY(kind != CTF_ERR);
+ VERIFY(kind == CTF_K_STRUCT || kind == CTF_K_UNION);
+
+ /*
+ * Members are in children. However, gcc also allows empty ones.
+ */
+ if ((ret = ctf_dwarf_child(cdp, die, &child)) != 0)
+ return (ret);
+ if (child == NULL)
+ return (0);
+
+ memb = child;
+ while (memb != NULL) {
+ Dwarf_Die sib, tdie;
+ Dwarf_Half tag;
+ ctf_id_t mid;
+ char *mname;
+ ulong_t memboff = 0;
+
+ if ((ret = ctf_dwarf_tag(cdp, memb, &tag)) != 0)
+ return (ret);
+
+ if (tag != DW_TAG_member)
+ continue;
+
+ if ((ret = ctf_dwarf_refdie(cdp, memb, DW_AT_type, &tdie)) != 0)
+ return (ret);
+
+ if ((ret = ctf_dwarf_convert_type(cdp, tdie, &mid,
+ CTF_ADD_NONROOT)) != 0)
+ return (ret);
+ ctf_dprintf("Got back type id: %d\n", mid);
+
+ /*
+ * If we're not adding a member, just go ahead and return.
+ */
+ if (add == B_FALSE) {
+ if ((ret = ctf_dwarf_member_bitfield(cdp, memb,
+ &mid)) != 0)
+ return (ret);
+ goto next;
+ }
+
+ if ((ret = ctf_dwarf_string(cdp, memb, DW_AT_name,
+ &mname)) != 0 && ret != ENOENT)
+ return (ret);
+ if (ret == ENOENT)
+ mname = NULL;
+
+ if (kind == CTF_K_UNION) {
+ memboff = 0;
+ } else if ((ret = ctf_dwarf_member_offset(cdp, memb, mid,
+ &memboff)) != 0) {
+ if (mname != NULL)
+ ctf_free(mname, strlen(mname) + 1);
+ return (ret);
+ }
+
+ if ((ret = ctf_dwarf_member_bitfield(cdp, memb, &mid)) != 0)
+ return (ret);
+
+ ret = ctf_add_member(cdp->cd_ctfp, base, mname, mid, memboff);
+ if (ret == CTF_ERR) {
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to add member %s: %s",
+ mname, ctf_errmsg(ctf_errno(cdp->cd_ctfp)));
+ if (mname != NULL)
+ ctf_free(mname, strlen(mname) + 1);
+ return (ECTF_CONVBKERR);
+ }
+
+ if (mname != NULL)
+ ctf_free(mname, strlen(mname) + 1);
+
+next:
+ if ((ret = ctf_dwarf_sib(cdp, memb, &sib)) != 0)
+ return (ret);
+ memb = sib;
+ }
+
+ /*
+ * If we're not adding members, then we don't know the final size of the
+ * structure, so end here.
+ */
+ if (add == B_FALSE)
+ return (0);
+
+ /* Finally set the size of the structure to the actual byte size */
+ if ((ret = ctf_dwarf_unsigned(cdp, die, DW_AT_byte_size, &size)) != 0)
+ return (ret);
+ nsz = size;
+ if ((ctf_set_size(cdp->cd_ctfp, base, nsz)) == CTF_ERR) {
+ int e = ctf_errno(cdp->cd_ctfp);
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to set type size for %d to 0x%x: %s", base,
+ (uint32_t)size, ctf_errmsg(e));
+ return (ECTF_CONVBKERR);
+ }
+
+ return (0);
+}
+
+static int
+ctf_dwarf_create_sou(ctf_die_t *cdp, Dwarf_Die die, ctf_id_t *idp,
+ int kind, int isroot)
+{
+ int ret;
+ char *name;
+ ctf_id_t base;
+ Dwarf_Die child;
+ Dwarf_Bool decl;
+
+ /*
+ * Deal with the terribly annoying case of anonymous structs and unions.
+ * If they don't have a name, set the name to the empty string.
+ */
+ if ((ret = ctf_dwarf_string(cdp, die, DW_AT_name, &name)) != 0 &&
+ ret != ENOENT)
+ return (ret);
+ if (ret == ENOENT)
+ name = NULL;
+
+ /*
+ * We need to check if we just have a declaration here. If we do, then
+ * instead of creating an actual structure or union, we're just going to
+ * go ahead and create a forward. During a dedup or merge, the forward
+ * will be replaced with the real thing.
+ */
+ if ((ret = ctf_dwarf_boolean(cdp, die, DW_AT_declaration,
+ &decl)) != 0) {
+ if (ret != ENOENT)
+ return (ret);
+ decl = 0;
+ }
+
+ if (decl != 0) {
+ base = ctf_add_forward(cdp->cd_ctfp, isroot, name, kind);
+ } else if (kind == CTF_K_STRUCT) {
+ base = ctf_add_struct(cdp->cd_ctfp, isroot, name);
+ } else {
+ base = ctf_add_union(cdp->cd_ctfp, isroot, name);
+ }
+ ctf_dprintf("added sou %s (%d) (%d)\n", name, kind, base);
+ if (name != NULL)
+ ctf_free(name, strlen(name) + 1);
+ if (base == CTF_ERR)
+ return (ctf_errno(cdp->cd_ctfp));
+ *idp = base;
+
+ /*
+ * If it's just a declaration, we're not going to mark it for fix up or
+ * do anything else.
+ */
+ if (decl == B_TRUE)
+ return (ctf_dwmap_add(cdp, base, die, B_FALSE));
+ if ((ret = ctf_dwmap_add(cdp, base, die, B_TRUE)) != 0)
+ return (ret);
+
+ /*
+ * Members are in children. However, gcc also allows empty ones.
+ */
+ if ((ret = ctf_dwarf_child(cdp, die, &child)) != 0)
+ return (ret);
+ if (child == NULL)
+ return (0);
+
+ return (0);
+}
+
+static int
+ctf_dwarf_create_array_range(ctf_die_t *cdp, Dwarf_Die range, ctf_id_t *idp,
+ ctf_id_t base, int isroot)
+{
+ int ret;
+ Dwarf_Die sib;
+ Dwarf_Unsigned val;
+ Dwarf_Signed sval;
+ ctf_arinfo_t ar;
+
+ ctf_dprintf("creating array range\n");
+
+ if ((ret = ctf_dwarf_sib(cdp, range, &sib)) != 0)
+ return (ret);
+ if (sib != NULL) {
+ ctf_id_t id;
+ if ((ret = ctf_dwarf_create_array_range(cdp, sib, &id,
+ base, CTF_ADD_NONROOT)) != 0)
+ return (ret);
+ ar.ctr_contents = id;
+ } else {
+ ar.ctr_contents = base;
+ }
+
+ if ((ar.ctr_index = ctf_dwarf_long(cdp)) == CTF_ERR)
+ return (ctf_errno(cdp->cd_ctfp));
+
+ /*
+ * Array bounds can be signed or unsigned, but there are several kinds
+ * of signless forms (data1, data2, etc) that take their sign from the
+ * routine that is trying to interpret them. That is, data1 can be
+ * either signed or unsigned, depending on whether you use the signed or
+ * unsigned accessor function. GCC will use the signless forms to store
+ * unsigned values which have their high bit set, so we need to try to
+ * read them first as unsigned to get positive values. We could also
+ * try signed first, falling back to unsigned if we got a negative
+ * value.
+ */
+ if ((ret = ctf_dwarf_unsigned(cdp, range, DW_AT_upper_bound,
+ &val)) == 0) {
+ ar.ctr_nelems = val + 1;
+ } else if (ret != ENOENT) {
+ return (ret);
+ } else if ((ret = ctf_dwarf_signed(cdp, range, DW_AT_upper_bound,
+ &sval)) == 0) {
+ ar.ctr_nelems = sval + 1;
+ } else if (ret != ENOENT) {
+ return (ret);
+ } else {
+ ar.ctr_nelems = 0;
+ }
+
+ if ((*idp = ctf_add_array(cdp->cd_ctfp, isroot, &ar)) == CTF_ERR)
+ return (ctf_errno(cdp->cd_ctfp));
+
+ return (0);
+}
+
+/*
+ * Try and create an array type. First, the kind of the array is specified in
+ * the DW_AT_type entry. Next, the number of entries is stored in a more
+ * complicated form, we should have a child that has the DW_TAG_subrange type.
+ */
+static int
+ctf_dwarf_create_array(ctf_die_t *cdp, Dwarf_Die die, ctf_id_t *idp, int isroot)
+{
+ int ret;
+ Dwarf_Die tdie, rdie;
+ ctf_id_t tid;
+ Dwarf_Half rtag;
+ ctf_arinfo_t ar;
+
+ if ((ret = ctf_dwarf_refdie(cdp, die, DW_AT_type, &tdie)) != 0)
+ return (ret);
+ if ((ret = ctf_dwarf_convert_type(cdp, tdie, &tid,
+ CTF_ADD_NONROOT)) != 0)
+ return (ret);
+
+ ar.ctr_contents = tid;
+
+ if ((ret = ctf_dwarf_child(cdp, die, &rdie)) != 0)
+ return (ret);
+ if ((ret = ctf_dwarf_tag(cdp, rdie, &rtag)) != 0)
+ return (ret);
+ if (rtag != DW_TAG_subrange_type) {
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "encountered array without DW_TAG_subrange_type child\n");
+ return (ECTF_CONVBKERR);
+ }
+
+ /*
+ * The compiler may opt to describe a multi-dimensional array as one
+ * giant array or it may opt to instead encode it as a series of
+ * subranges. If it's the latter, then for each subrange we introduce a
+ * type. We can always use the base type.
+ */
+ if ((ret = ctf_dwarf_create_array_range(cdp, rdie, idp, tid,
+ isroot)) != 0)
+ return (ret);
+ ctf_dprintf("Got back id %d\n", *idp);
+ return (ctf_dwmap_add(cdp, *idp, die, B_FALSE));
+}
+
+static int
+ctf_dwarf_create_reference(ctf_die_t *cdp, Dwarf_Die die, ctf_id_t *idp,
+ int kind, int isroot)
+{
+ int ret;
+ ctf_id_t id;
+ Dwarf_Die tdie;
+ char *name;
+ size_t namelen;
+
+ if ((ret = ctf_dwarf_string(cdp, die, DW_AT_name, &name)) != 0 &&
+ ret != ENOENT)
+ return (ret);
+ if (ret == ENOENT) {
+ name = NULL;
+ namelen = 0;
+ } else {
+ namelen = strlen(name);
+ }
+
+ ctf_dprintf("reference kind %d %s\n", kind, name != NULL ? name : "<>");
+
+ if ((ret = ctf_dwarf_refdie(cdp, die, DW_AT_type, &tdie)) != 0) {
+ if (ret != ENOENT) {
+ ctf_free(name, namelen);
+ return (ret);
+ }
+ if ((id = ctf_dwarf_void(cdp)) == CTF_ERR) {
+ ctf_free(name, namelen);
+ return (ctf_errno(cdp->cd_ctfp));
+ }
+ } else {
+ if ((ret = ctf_dwarf_convert_type(cdp, tdie, &id,
+ CTF_ADD_NONROOT)) != 0) {
+ ctf_free(name, namelen);
+ return (ret);
+ }
+ }
+
+ if ((*idp = ctf_add_reftype(cdp->cd_ctfp, isroot, name, id, kind)) ==
+ CTF_ERR) {
+ ctf_free(name, namelen);
+ return (ctf_errno(cdp->cd_ctfp));
+ }
+
+ ctf_free(name, namelen);
+ return (ctf_dwmap_add(cdp, *idp, die, B_FALSE));
+}
+
+static int
+ctf_dwarf_create_enum(ctf_die_t *cdp, Dwarf_Die die, ctf_id_t *idp, int isroot)
+{
+ int ret;
+ ctf_id_t id;
+ Dwarf_Die child;
+ char *name;
+
+ if ((ret = ctf_dwarf_string(cdp, die, DW_AT_name, &name)) != 0 &&
+ ret != ENOENT)
+ return (ret);
+ if (ret == ENOENT)
+ name = NULL;
+ id = ctf_add_enum(cdp->cd_ctfp, isroot, name);
+ ctf_dprintf("added enum %s (%d)\n", name, id);
+ if (name != NULL)
+ ctf_free(name, strlen(name) + 1);
+ if (id == CTF_ERR)
+ return (ctf_errno(cdp->cd_ctfp));
+ *idp = id;
+ if ((ret = ctf_dwmap_add(cdp, id, die, B_FALSE)) != 0)
+ return (ret);
+
+
+ if ((ret = ctf_dwarf_child(cdp, die, &child)) != 0) {
+ if (ret == ENOENT)
+ ret = 0;
+ return (ret);
+ }
+
+ while (child != NULL) {
+ Dwarf_Half tag;
+ Dwarf_Signed sval;
+ Dwarf_Unsigned uval;
+ Dwarf_Die arg = child;
+ int eval;
+
+ if ((ret = ctf_dwarf_sib(cdp, arg, &child)) != 0)
+ return (ret);
+
+ if ((ret = ctf_dwarf_tag(cdp, arg, &tag)) != 0)
+ return (ret);
+
+ if (tag != DW_TAG_enumerator) {
+ if ((ret = ctf_dwarf_convert_type(cdp, arg, NULL,
+ CTF_ADD_NONROOT)) != 0)
+ return (ret);
+ continue;
+ }
+
+ if ((ret = ctf_dwarf_signed(cdp, arg, DW_AT_const_value,
+ &sval)) == 0) {
+ eval = sval;
+ } else if (ret != ENOENT) {
+ return (ret);
+ } else if ((ret = ctf_dwarf_unsigned(cdp, arg,
+ DW_AT_const_value, &uval)) == 0) {
+ eval = (int)uval;
+ } else {
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "encountered enumration without constant value\n");
+ return (ECTF_CONVBKERR);
+ }
+
+ /*
+ * DWARF v4 section 5.7 tells us we'll always have names.
+ */
+ if ((ret = ctf_dwarf_string(cdp, arg, DW_AT_name,
+ &name)) != 0)
+ return (ret);
+
+ ret = ctf_add_enumerator(cdp->cd_ctfp, id, name, eval);
+ if (ret == CTF_ERR) {
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "failed to add enumarator %s (%d) to %d\n",
+ name, eval, id);
+ ctf_free(name, strlen(name) + 1);
+ return (ctf_errno(cdp->cd_ctfp));
+ }
+ ctf_free(name, strlen(name) + 1);
+ }
+
+ return (0);
+}
+
+/*
+ * For a function pointer, walk over and process all of its children, unless we
+ * encounter one that's just a declaration. In which case, we error on it.
+ */
+static int
+ctf_dwarf_create_fptr(ctf_die_t *cdp, Dwarf_Die die, ctf_id_t *idp, int isroot)
+{
+ int ret;
+ Dwarf_Bool b;
+ ctf_funcinfo_t fi;
+ Dwarf_Die retdie;
+ ctf_id_t *argv = NULL;
+
+ bzero(&fi, sizeof (ctf_funcinfo_t));
+
+ if ((ret = ctf_dwarf_boolean(cdp, die, DW_AT_declaration, &b)) != 0) {
+ if (ret != ENOENT)
+ return (ret);
+ } else {
+ if (b != 0)
+ return (EPROTOTYPE);
+ }
+
+ /*
+ * Return type is in DW_AT_type, if none, it returns void.
+ */
+ if ((ret = ctf_dwarf_refdie(cdp, die, DW_AT_type, &retdie)) != 0) {
+ if (ret != ENOENT)
+ return (ret);
+ if ((fi.ctc_return = ctf_dwarf_void(cdp)) == CTF_ERR)
+ return (ctf_errno(cdp->cd_ctfp));
+ } else {
+ if ((ret = ctf_dwarf_convert_type(cdp, retdie, &fi.ctc_return,
+ CTF_ADD_NONROOT)) != 0)
+ return (ret);
+ }
+
+ if ((ret = ctf_dwarf_function_count(cdp, die, &fi, B_TRUE)) != 0) {
+ return (ret);
+ }
+
+ if (fi.ctc_argc != 0) {
+ argv = ctf_alloc(sizeof (ctf_id_t) * fi.ctc_argc);
+ if (argv == NULL)
+ return (ENOMEM);
+
+ if ((ret = ctf_dwarf_convert_fargs(cdp, die, &fi, argv)) != 0) {
+ ctf_free(argv, sizeof (ctf_id_t) * fi.ctc_argc);
+ return (ret);
+ }
+ }
+
+ if ((*idp = ctf_add_funcptr(cdp->cd_ctfp, isroot, &fi, argv)) ==
+ CTF_ERR) {
+ ctf_free(argv, sizeof (ctf_id_t) * fi.ctc_argc);
+ return (ctf_errno(cdp->cd_ctfp));
+ }
+
+ ctf_free(argv, sizeof (ctf_id_t) * fi.ctc_argc);
+ return (ctf_dwmap_add(cdp, *idp, die, B_FALSE));
+}
+
+static int
+ctf_dwarf_convert_type(ctf_die_t *cdp, Dwarf_Die die, ctf_id_t *idp,
+ int isroot)
+{
+ int ret;
+ Dwarf_Off offset;
+ Dwarf_Half tag;
+ ctf_dwmap_t lookup, *map;
+ ctf_id_t id;
+
+ if (idp == NULL)
+ idp = &id;
+
+ if ((ret = ctf_dwarf_offset(cdp, die, &offset)) != 0)
+ return (ret);
+
+ if (offset > cdp->cd_maxoff) {
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "die offset %llu beyond maximum for header %llu\n",
+ offset, cdp->cd_maxoff);
+ return (ECTF_CONVBKERR);
+ }
+
+ /*
+ * If we've already added an entry for this offset, then we're done.
+ */
+ lookup.cdm_off = offset;
+ if ((map = avl_find(&cdp->cd_map, &lookup, NULL)) != NULL) {
+ *idp = map->cdm_id;
+ return (0);
+ }
+
+ if ((ret = ctf_dwarf_tag(cdp, die, &tag)) != 0)
+ return (ret);
+
+ ret = ENOTSUP;
+ switch (tag) {
+ case DW_TAG_base_type:
+ ctf_dprintf("base\n");
+ ret = ctf_dwarf_create_base(cdp, die, idp, isroot, offset);
+ break;
+ case DW_TAG_array_type:
+ ctf_dprintf("array\n");
+ ret = ctf_dwarf_create_array(cdp, die, idp, isroot);
+ break;
+ case DW_TAG_enumeration_type:
+ ctf_dprintf("enum\n");
+ ret = ctf_dwarf_create_enum(cdp, die, idp, isroot);
+ break;
+ case DW_TAG_pointer_type:
+ ctf_dprintf("pointer\n");
+ ret = ctf_dwarf_create_reference(cdp, die, idp, CTF_K_POINTER,
+ isroot);
+ break;
+ case DW_TAG_structure_type:
+ ctf_dprintf("struct\n");
+ ret = ctf_dwarf_create_sou(cdp, die, idp, CTF_K_STRUCT,
+ isroot);
+ break;
+ case DW_TAG_subroutine_type:
+ ctf_dprintf("fptr\n");
+ ret = ctf_dwarf_create_fptr(cdp, die, idp, isroot);
+ break;
+ case DW_TAG_typedef:
+ ctf_dprintf("typedef\n");
+ ret = ctf_dwarf_create_reference(cdp, die, idp, CTF_K_TYPEDEF,
+ isroot);
+ break;
+ case DW_TAG_union_type:
+ ctf_dprintf("union\n");
+ ret = ctf_dwarf_create_sou(cdp, die, idp, CTF_K_UNION,
+ isroot);
+ break;
+ case DW_TAG_const_type:
+ ctf_dprintf("const\n");
+ ret = ctf_dwarf_create_reference(cdp, die, idp, CTF_K_CONST,
+ isroot);
+ break;
+ case DW_TAG_volatile_type:
+ ctf_dprintf("volatile\n");
+ ret = ctf_dwarf_create_reference(cdp, die, idp, CTF_K_VOLATILE,
+ isroot);
+ break;
+ case DW_TAG_restrict_type:
+ ctf_dprintf("restrict\n");
+ ret = ctf_dwarf_create_reference(cdp, die, idp, CTF_K_RESTRICT,
+ isroot);
+ break;
+ default:
+ ctf_dprintf("ignoring tag type %x\n", tag);
+ ret = 0;
+ break;
+ }
+ ctf_dprintf("ctf_dwarf_convert_type tag specific handler returned %d\n",
+ ret);
+
+ return (ret);
+}
+
+static int
+ctf_dwarf_walk_lexical(ctf_die_t *cdp, Dwarf_Die die)
+{
+ int ret;
+ Dwarf_Die child;
+
+ if ((ret = ctf_dwarf_child(cdp, die, &child)) != 0)
+ return (ret);
+
+ if (child == NULL)
+ return (0);
+
+ return (ctf_dwarf_convert_die(cdp, die));
+}
+
+static int
+ctf_dwarf_function_count(ctf_die_t *cdp, Dwarf_Die die, ctf_funcinfo_t *fip,
+ boolean_t fptr)
+{
+ int ret;
+ Dwarf_Die child, sib, arg;
+
+ if ((ret = ctf_dwarf_child(cdp, die, &child)) != 0)
+ return (ret);
+
+ arg = child;
+ while (arg != NULL) {
+ Dwarf_Half tag;
+
+ if ((ret = ctf_dwarf_tag(cdp, arg, &tag)) != 0)
+ return (ret);
+
+ /*
+ * We have to check for a varargs type decleration. This will
+ * happen in one of two ways. If we have a function pointer
+ * type, then it'll be done with a tag of type
+ * DW_TAG_unspecified_parameters. However, it only means we have
+ * a variable number of arguments, if we have more than one
+ * argument found so far. Otherwise, when we have a function
+ * type, it instead uses a formal parameter whose name is '...'
+ * to indicate a variable arguments member.
+ *
+ * Also, if we have a function pointer, then we have to expect
+ * that we might not get a name at all.
+ */
+ if (tag == DW_TAG_formal_parameter && fptr == B_FALSE) {
+ char *name;
+ if ((ret = ctf_dwarf_string(cdp, die, DW_AT_name,
+ &name)) != 0)
+ return (ret);
+ if (strcmp(name, DWARF_VARARGS_NAME) == 0)
+ fip->ctc_flags |= CTF_FUNC_VARARG;
+ else
+ fip->ctc_argc++;
+ ctf_free(name, strlen(name) + 1);
+ } else if (tag == DW_TAG_formal_parameter) {
+ fip->ctc_argc++;
+ } else if (tag == DW_TAG_unspecified_parameters &&
+ fip->ctc_argc > 0) {
+ fip->ctc_flags |= CTF_FUNC_VARARG;
+ }
+ if ((ret = ctf_dwarf_sib(cdp, arg, &sib)) != 0)
+ return (ret);
+ arg = sib;
+ }
+
+ return (0);
+}
+
+static int
+ctf_dwarf_convert_fargs(ctf_die_t *cdp, Dwarf_Die die, ctf_funcinfo_t *fip,
+ ctf_id_t *argv)
+{
+ int ret;
+ int i = 0;
+ Dwarf_Die child, sib, arg;
+
+ if ((ret = ctf_dwarf_child(cdp, die, &child)) != 0)
+ return (ret);
+
+ arg = child;
+ while (arg != NULL) {
+ Dwarf_Half tag;
+
+ if ((ret = ctf_dwarf_tag(cdp, arg, &tag)) != 0)
+ return (ret);
+ if (tag == DW_TAG_formal_parameter) {
+ Dwarf_Die tdie;
+
+ if ((ret = ctf_dwarf_refdie(cdp, arg, DW_AT_type,
+ &tdie)) != 0)
+ return (ret);
+
+ if ((ret = ctf_dwarf_convert_type(cdp, tdie, &argv[i],
+ CTF_ADD_ROOT)) != 0)
+ return (ret);
+ i++;
+
+ /*
+ * Once we hit argc entries, we're done. This ensures we
+ * don't accidentally hit a varargs which should be the
+ * least entry.
+ */
+ if (i == fip->ctc_argc)
+ break;
+ }
+
+ if ((ret = ctf_dwarf_sib(cdp, arg, &sib)) != 0)
+ return (ret);
+ arg = sib;
+ }
+
+ return (0);
+}
+
+static int
+ctf_dwarf_convert_function(ctf_die_t *cdp, Dwarf_Die die)
+{
+ int ret;
+ char *name;
+ ctf_dwfunc_t *cdf;
+ Dwarf_Die tdie;
+
+ /*
+ * Functions that don't have a name are generally functions that have
+ * been inlined and thus most information about them has been lost. If
+ * we can't get a name, then instead of returning ENOENT, we silently
+ * swallow the error.
+ */
+ if ((ret = ctf_dwarf_string(cdp, die, DW_AT_name, &name)) != 0) {
+ if (ret == ENOENT)
+ return (0);
+ return (ret);
+ }
+
+ ctf_dprintf("beginning work on function %s\n", name);
+ if ((cdf = ctf_alloc(sizeof (ctf_dwfunc_t))) == NULL) {
+ ctf_free(name, strlen(name) + 1);
+ return (ENOMEM);
+ }
+ bzero(cdf, sizeof (ctf_dwfunc_t));
+ cdf->cdf_name = name;
+
+ if ((ret = ctf_dwarf_refdie(cdp, die, DW_AT_type, &tdie)) == 0) {
+ if ((ret = ctf_dwarf_convert_type(cdp, tdie,
+ &(cdf->cdf_fip.ctc_return), CTF_ADD_ROOT)) != 0) {
+ ctf_free(name, strlen(name) + 1);
+ ctf_free(cdf, sizeof (ctf_dwfunc_t));
+ return (ret);
+ }
+ } else if (ret != ENOENT) {
+ ctf_free(name, strlen(name) + 1);
+ ctf_free(cdf, sizeof (ctf_dwfunc_t));
+ return (ret);
+ } else {
+ if ((cdf->cdf_fip.ctc_return = ctf_dwarf_void(cdp)) ==
+ CTF_ERR) {
+ ctf_free(name, strlen(name) + 1);
+ ctf_free(cdf, sizeof (ctf_dwfunc_t));
+ return (ctf_errno(cdp->cd_ctfp));
+ }
+ }
+
+ /*
+ * A function has a number of children, some of which may not be ones we
+ * care about. Children that we care about have a type of
+ * DW_TAG_formal_parameter. We're going to do two passes, the first to
+ * count the arguments, the second to process them. Afterwards, we
+ * should be good to go ahead and add this function.
+ *
+ * Note, we already got the return type by going in and grabbing it out
+ * of the DW_AT_type.
+ */
+ if ((ret = ctf_dwarf_function_count(cdp, die, &cdf->cdf_fip,
+ B_FALSE)) != 0) {
+ ctf_free(name, strlen(name) + 1);
+ ctf_free(cdf, sizeof (ctf_dwfunc_t));
+ return (ret);
+ }
+
+ ctf_dprintf("beginning to convert function arguments %s\n", name);
+ if (cdf->cdf_fip.ctc_argc != 0) {
+ uint_t argc = cdf->cdf_fip.ctc_argc;
+ cdf->cdf_argv = ctf_alloc(sizeof (ctf_id_t) * argc);
+ if (cdf->cdf_argv == NULL) {
+ ctf_free(name, strlen(name) + 1);
+ ctf_free(cdf, sizeof (ctf_dwfunc_t));
+ return (ENOMEM);
+ }
+ if ((ret = ctf_dwarf_convert_fargs(cdp, die,
+ &cdf->cdf_fip, cdf->cdf_argv)) != 0) {
+ ctf_free(cdf->cdf_argv, sizeof (ctf_id_t) * argc);
+ ctf_free(name, strlen(name) + 1);
+ ctf_free(cdf, sizeof (ctf_dwfunc_t));
+ return (ret);
+ }
+ } else {
+ cdf->cdf_argv = NULL;
+ }
+
+ if ((ret = ctf_dwarf_isglobal(cdp, die, &cdf->cdf_global)) != 0) {
+ ctf_free(cdf->cdf_argv, sizeof (ctf_id_t) *
+ cdf->cdf_fip.ctc_argc);
+ ctf_free(name, strlen(name) + 1);
+ ctf_free(cdf, sizeof (ctf_dwfunc_t));
+ return (ret);
+ }
+
+ ctf_list_append(&cdp->cd_funcs, cdf);
+ return (ret);
+}
+
+/*
+ * Convert variables, but only if they're not prototypes and have names.
+ */
+static int
+ctf_dwarf_convert_variable(ctf_die_t *cdp, Dwarf_Die die)
+{
+ int ret;
+ char *name;
+ Dwarf_Bool b;
+ Dwarf_Die tdie;
+ ctf_id_t id;
+ ctf_dwvar_t *cdv;
+
+ if ((ret = ctf_dwarf_boolean(cdp, die, DW_AT_declaration, &b)) != 0) {
+ if (ret != ENOENT)
+ return (ret);
+ } else if (b != 0) {
+ return (0);
+ }
+
+ if ((ret = ctf_dwarf_string(cdp, die, DW_AT_name, &name)) != 0 &&
+ ret != ENOENT)
+ return (ret);
+ if (ret == ENOENT)
+ return (0);
+
+ if ((ret = ctf_dwarf_refdie(cdp, die, DW_AT_type, &tdie)) != 0) {
+ ctf_free(name, strlen(name) + 1);
+ return (ret);
+ }
+
+ if ((ret = ctf_dwarf_convert_type(cdp, tdie, &id,
+ CTF_ADD_ROOT)) != 0)
+ return (ret);
+
+ if ((cdv = ctf_alloc(sizeof (ctf_dwvar_t))) == NULL) {
+ ctf_free(name, strlen(name) + 1);
+ return (ENOMEM);
+ }
+
+ cdv->cdv_name = name;
+ cdv->cdv_type = id;
+
+ if ((ret = ctf_dwarf_isglobal(cdp, die, &cdv->cdv_global)) != 0) {
+ ctf_free(cdv, sizeof (ctf_dwvar_t));
+ ctf_free(name, strlen(name) + 1);
+ return (ret);
+ }
+
+ ctf_list_append(&cdp->cd_vars, cdv);
+ return (0);
+}
+
+/*
+ * Walk through our set of top-level types and process them.
+ */
+static int
+ctf_dwarf_walk_toplevel(ctf_die_t *cdp, Dwarf_Die die)
+{
+ int ret;
+ Dwarf_Off offset;
+ Dwarf_Half tag;
+
+ if ((ret = ctf_dwarf_offset(cdp, die, &offset)) != 0)
+ return (ret);
+
+ if (offset > cdp->cd_maxoff) {
+ (void) snprintf(cdp->cd_errbuf, cdp->cd_errlen,
+ "die offset %llu beyond maximum for header %llu\n",
+ offset, cdp->cd_maxoff);
+ return (ECTF_CONVBKERR);
+ }
+
+ if ((ret = ctf_dwarf_tag(cdp, die, &tag)) != 0)
+ return (ret);
+
+ ret = 0;
+ switch (tag) {
+ case DW_TAG_subprogram:
+ ctf_dprintf("top level func\n");
+ ret = ctf_dwarf_convert_function(cdp, die);
+ break;
+ case DW_TAG_variable:
+ ctf_dprintf("top level var\n");
+ ret = ctf_dwarf_convert_variable(cdp, die);
+ break;
+ case DW_TAG_lexical_block:
+ ctf_dprintf("top level block\n");
+ ret = ctf_dwarf_walk_lexical(cdp, die);
+ break;
+ case DW_TAG_enumeration_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_typedef:
+ case DW_TAG_union_type:
+ ctf_dprintf("top level type\n");
+ ret = ctf_dwarf_convert_type(cdp, die, NULL, B_TRUE);
+ break;
+ default:
+ break;
+ }
+
+ return (ret);
+}
+
+
+/*
+ * We're given a node. At this node we need to convert it and then proceed to
+ * convert any siblings that are associaed with this die.
+ */
+static int
+ctf_dwarf_convert_die(ctf_die_t *cdp, Dwarf_Die die)
+{
+ while (die != NULL) {
+ int ret;
+ Dwarf_Die sib;
+
+ if ((ret = ctf_dwarf_walk_toplevel(cdp, die)) != 0)
+ return (ret);
+
+ if ((ret = ctf_dwarf_sib(cdp, die, &sib)) != 0)
+ return (ret);
+ die = sib;
+ }
+ return (0);
+}
+
+static int
+ctf_dwarf_fixup_die(ctf_die_t *cdp, boolean_t addpass)
+{
+ ctf_dwmap_t *map;
+
+ for (map = avl_first(&cdp->cd_map); map != NULL;
+ map = AVL_NEXT(&cdp->cd_map, map)) {
+ int ret;
+ if (map->cdm_fix == B_FALSE)
+ continue;
+ if ((ret = ctf_dwarf_fixup_sou(cdp, map->cdm_die, map->cdm_id,
+ addpass)) != 0)
+ return (ret);
+ }
+
+ return (0);
+}
+
+static ctf_dwfunc_t *
+ctf_dwarf_match_func(ctf_die_t *cdp, const char *file, const char *name,
+ int bind)
+{
+ ctf_dwfunc_t *cdf;
+
+ if (bind == STB_WEAK)
+ return (NULL);
+
+ /* Nothing we can do if we can't find a name to compare it to. */
+ if (bind == STB_LOCAL && (file == NULL || cdp->cd_name == NULL))
+ return (NULL);
+
+ for (cdf = ctf_list_next(&cdp->cd_funcs); cdf != NULL;
+ cdf = ctf_list_next(cdf)) {
+ if (bind == STB_GLOBAL && cdf->cdf_global == B_FALSE)
+ continue;
+ if (bind == STB_LOCAL && cdf->cdf_global == B_TRUE)
+ continue;
+ if (strcmp(name, cdf->cdf_name) != 0)
+ continue;
+ if (bind == STB_LOCAL && strcmp(file, cdp->cd_name) != 0)
+ continue;
+ return (cdf);
+ }
+
+ return (NULL);
+}
+static ctf_dwvar_t *
+ctf_dwarf_match_var(ctf_die_t *cdp, const char *file, const char *name,
+ int bind)
+{
+ ctf_dwvar_t *cdv;
+
+ /* Nothing we can do if we can't find a name to compare it to. */
+ if (bind == STB_LOCAL && (file == NULL || cdp->cd_name == NULL))
+ return (NULL);
+ ctf_dprintf("Still considering %s\n", name);
+
+ for (cdv = ctf_list_next(&cdp->cd_vars); cdv != NULL;
+ cdv = ctf_list_next(cdv)) {
+ if (bind == STB_GLOBAL && cdv->cdv_global == B_FALSE)
+ continue;
+ if (bind == STB_LOCAL && cdv->cdv_global == B_TRUE)
+ continue;
+ if (strcmp(name, cdv->cdv_name) != 0)
+ continue;
+ if (bind == STB_LOCAL && strcmp(file, cdp->cd_name) != 0)
+ continue;
+ return (cdv);
+ }
+
+ return (NULL);
+}
+
+static int
+ctf_dwarf_symtab_iter(ctf_die_t *cdp, ctf_dwarf_symtab_f *func, void *arg)
+{
+ int ret;
+ ulong_t i;
+ ctf_file_t *fp = cdp->cd_ctfp;
+ const char *file = NULL;
+ uintptr_t symbase = (uintptr_t)fp->ctf_symtab.cts_data;
+ uintptr_t strbase = (uintptr_t)fp->ctf_strtab.cts_data;
+
+ for (i = 0; i < fp->ctf_nsyms; i++) {
+ const char *name;
+ int type;
+ GElf_Sym gsym;
+ const GElf_Sym *gsymp;
+
+ if (fp->ctf_symtab.cts_entsize == sizeof (Elf32_Sym)) {
+ const Elf32_Sym *symp = (Elf32_Sym *)symbase + i;
+ type = ELF32_ST_TYPE(symp->st_info);
+ if (type == STT_FILE) {
+ file = (char *)(strbase + symp->st_name);
+ continue;
+ }
+ if (type != STT_OBJECT && type != STT_FUNC)
+ continue;
+ if (ctf_sym_valid(strbase, type, symp->st_shndx,
+ symp->st_value, symp->st_name) == B_FALSE)
+ continue;
+ name = (char *)(strbase + symp->st_name);
+ gsym.st_name = symp->st_name;
+ gsym.st_value = symp->st_value;
+ gsym.st_size = symp->st_size;
+ gsym.st_info = symp->st_info;
+ gsym.st_other = symp->st_other;
+ gsym.st_shndx = symp->st_shndx;
+ gsymp = &gsym;
+ } else {
+ const Elf64_Sym *symp = (Elf64_Sym *)symbase + i;
+ type = ELF64_ST_TYPE(symp->st_info);
+ if (type == STT_FILE) {
+ file = (char *)(strbase + symp->st_name);
+ continue;
+ }
+ if (type != STT_OBJECT && type != STT_FUNC)
+ continue;
+ if (ctf_sym_valid(strbase, type, symp->st_shndx,
+ symp->st_value, symp->st_name) == B_FALSE)
+ continue;
+ name = (char *)(strbase + symp->st_name);
+ gsymp = symp;
+ }
+
+ ret = func(cdp, gsymp, i, file, name, arg);
+ if (ret != 0)
+ return (ret);
+ }
+
+ return (0);
+}
+
+static int
+ctf_dwarf_conv_funcvars_cb(ctf_die_t *cdp, const GElf_Sym *symp, ulong_t idx,
+ const char *file, const char *name, void *arg)
+{
+ int ret, bind, type;
+
+ bind = GELF_ST_BIND(symp->st_info);
+ type = GELF_ST_TYPE(symp->st_info);
+
+ /*
+ * Come back to weak symbols in another pass
+ */
+ if (bind == STB_WEAK)
+ return (0);
+
+ if (type == STT_OBJECT) {
+ ctf_dwvar_t *cdv = ctf_dwarf_match_var(cdp, file, name,
+ bind);
+ ctf_dprintf("match for %s (%d): %p\n", name, idx, cdv);
+ if (cdv == NULL)
+ return (0);
+ ret = ctf_add_object(cdp->cd_ctfp, idx, cdv->cdv_type);
+ ctf_dprintf("added object %s\n", name);
+ } else {
+ ctf_dwfunc_t *cdf = ctf_dwarf_match_func(cdp, file, name,
+ bind);
+ if (cdf == NULL)
+ return (0);
+ ret = ctf_add_function(cdp->cd_ctfp, idx, &cdf->cdf_fip,
+ cdf->cdf_argv);
+ }
+
+ if (ret == CTF_ERR) {
+ return (ctf_errno(cdp->cd_ctfp));
+ }
+
+ return (0);
+}
+
+static int
+ctf_dwarf_conv_funcvars(ctf_die_t *cdp)
+{
+ return (ctf_dwarf_symtab_iter(cdp, ctf_dwarf_conv_funcvars_cb, NULL));
+}
+
+/*
+ * Note, this comment comes from the original version of the CTF tools.
+ *
+ * If we have a weak symbol, attempt to find the strong symbol it will
+ * resolve to. Note: the code where this actually happens is in
+ * sym_process() in cmd/sgs/libld/common/syms.c
+ *
+ * Finding the matching symbol is unfortunately not trivial. For a
+ * symbol to be a candidate, it must:
+ *
+ * - have the same type (function, object)
+ * - have the same value (address)
+ * - have the same size
+ * - not be another weak symbol
+ * - belong to the same section (checked via section index)
+ *
+ * If such a candidate is global, then we assume we've found it. The
+ * linker generates the symbol table such that the curfile might be
+ * incorrect; this is OK for global symbols, since find_iidesc() doesn't
+ * need to check for the source file for the symbol.
+ *
+ * We might have found a strong local symbol, where the curfile is
+ * accurate and matches that of the weak symbol. We assume this is a
+ * reasonable match.
+ *
+ * If we've got a local symbol with a non-matching curfile, there are
+ * two possibilities. Either this is a completely different symbol, or
+ * it's a once-global symbol that was scoped to local via a mapfile. In
+ * the latter case, curfile is likely inaccurate since the linker does
+ * not preserve the needed curfile in the order of the symbol table (see
+ * the comments about locally scoped symbols in libld's update_osym()).
+ * As we can't tell this case from the former one, we use this symbol
+ * iff no other matching symbol is found.
+ *
+ * What we really need here is a SUNW section containing weak<->strong
+ * mappings that we can consume.
+ */
+typedef struct ctf_dwarf_weak_arg {
+ const GElf_Sym *cweak_symp;
+ const char *cweak_file;
+ boolean_t cweak_candidate;
+ ulong_t cweak_idx;
+} ctf_dwarf_weak_arg_t;
+
+static int
+ctf_dwarf_conv_check_weak(ctf_die_t *cdp, const GElf_Sym *symp,
+ ulong_t idx, const char *file, const char *name, void *arg)
+{
+ ctf_dwarf_weak_arg_t *cweak = arg;
+ const GElf_Sym *wsymp = cweak->cweak_symp;
+
+ ctf_dprintf("comparing weak to %s\n", name);
+
+ if (GELF_ST_BIND(symp->st_info) == STB_WEAK) {
+ return (0);
+ }
+
+ if (GELF_ST_TYPE(wsymp->st_info) != GELF_ST_TYPE(symp->st_info)) {
+ return (0);
+ }
+
+ if (wsymp->st_value != symp->st_value) {
+ return (0);
+ }
+
+ if (wsymp->st_size != symp->st_size) {
+ return (0);
+ }
+
+ if (wsymp->st_shndx != symp->st_shndx) {
+ return (0);
+ }
+
+ /*
+ * Check if it's a weak candidate.
+ */
+ if (GELF_ST_BIND(symp->st_info) == STB_LOCAL &&
+ (file == NULL || cweak->cweak_file == NULL ||
+ strcmp(file, cweak->cweak_file) != 0)) {
+ cweak->cweak_candidate = B_TRUE;
+ cweak->cweak_idx = idx;
+ return (0);
+ }
+
+ /*
+ * Found a match, break.
+ */
+ cweak->cweak_idx = idx;
+ return (1);
+}
+
+static int
+ctf_dwarf_duplicate_sym(ctf_die_t *cdp, ulong_t idx, ulong_t matchidx)
+{
+ ctf_id_t id = ctf_lookup_by_symbol(cdp->cd_ctfp, matchidx);
+
+ /*
+ * If we matched something that for some reason didn't have type data,
+ * we don't consider that a fatal error and silently swallow it.
+ */
+ if (id == CTF_ERR) {
+ if (ctf_errno(cdp->cd_ctfp) == ECTF_NOTYPEDAT)
+ return (0);
+ else
+ return (ctf_errno(cdp->cd_ctfp));
+ }
+
+ if (ctf_add_object(cdp->cd_ctfp, idx, id) == CTF_ERR)
+ return (ctf_errno(cdp->cd_ctfp));
+
+ return (0);
+}
+
+static int
+ctf_dwarf_duplicate_func(ctf_die_t *cdp, ulong_t idx, ulong_t matchidx)
+{
+ int ret;
+ ctf_funcinfo_t fip;
+ ctf_id_t *args = NULL;
+
+ if (ctf_func_info(cdp->cd_ctfp, matchidx, &fip) == CTF_ERR) {
+ if (ctf_errno(cdp->cd_ctfp) == ECTF_NOFUNCDAT)
+ return (0);
+ else
+ return (ctf_errno(cdp->cd_ctfp));
+ }
+
+ if (fip.ctc_argc != 0) {
+ args = ctf_alloc(sizeof (ctf_id_t) * fip.ctc_argc);
+ if (args == NULL)
+ return (ENOMEM);
+
+ if (ctf_func_args(cdp->cd_ctfp, matchidx, fip.ctc_argc, args) ==
+ CTF_ERR) {
+ ctf_free(args, sizeof (ctf_id_t) * fip.ctc_argc);
+ return (ctf_errno(cdp->cd_ctfp));
+ }
+ }
+
+ ret = ctf_add_function(cdp->cd_ctfp, idx, &fip, args);
+ if (args != NULL)
+ ctf_free(args, sizeof (ctf_id_t) * fip.ctc_argc);
+ if (ret == CTF_ERR)
+ return (ctf_errno(cdp->cd_ctfp));
+
+ return (0);
+}
+
+static int
+ctf_dwarf_conv_weaks_cb(ctf_die_t *cdp, const GElf_Sym *symp,
+ ulong_t idx, const char *file, const char *name, void *arg)
+{
+ int ret, type;
+ ctf_dwarf_weak_arg_t cweak;
+
+ /*
+ * We only care about weak symbols.
+ */
+ if (GELF_ST_BIND(symp->st_info) != STB_WEAK)
+ return (0);
+
+ type = GELF_ST_TYPE(symp->st_info);
+ ASSERT(type == STT_OBJECT || type == STT_FUNC);
+
+ /*
+ * For each weak symbol we encounter, we need to do a second iteration
+ * to try and find a match. We should probably think about other
+ * techniques to try and save us time in the future.
+ */
+ cweak.cweak_symp = symp;
+ cweak.cweak_file = file;
+ cweak.cweak_candidate = B_FALSE;
+ cweak.cweak_idx = 0;
+
+ ctf_dprintf("Trying to find weak equiv for %s\n", name);
+
+ ret = ctf_dwarf_symtab_iter(cdp, ctf_dwarf_conv_check_weak, &cweak);
+ VERIFY(ret == 0 || ret == 1);
+
+ /*
+ * Nothing was ever found, we're not going to add anything for this
+ * entry.
+ */
+ if (ret == 0 && cweak.cweak_candidate == B_FALSE) {
+ ctf_dprintf("found no weak match for %s\n", name);
+ return (0);
+ }
+
+ /*
+ * Now, finally go and add the type based on the match.
+ */
+ if (type == STT_OBJECT) {
+ ret = ctf_dwarf_duplicate_sym(cdp, idx, cweak.cweak_idx);
+ } else {
+ ret = ctf_dwarf_duplicate_func(cdp, idx, cweak.cweak_idx);
+ }
+
+ return (ret);
+}
+
+static int
+ctf_dwarf_conv_weaks(ctf_die_t *cdp)
+{
+ return (ctf_dwarf_symtab_iter(cdp, ctf_dwarf_conv_weaks_cb, NULL));
+}
+
+/* ARGSUSED */
+static int
+ctf_dwarf_convert_one(void *arg, void *unused)
+{
+ int ret;
+ ctf_file_t *dedup;
+ ctf_die_t *cdp = arg;
+
+ ctf_dprintf("converting die: %s\n", cdp->cd_name);
+ ctf_dprintf("max offset: %x\n", cdp->cd_maxoff);
+ VERIFY(cdp != NULL);
+
+ ret = ctf_dwarf_convert_die(cdp, cdp->cd_cu);
+ ctf_dprintf("ctf_dwarf_convert_die (%s) returned %d\n", cdp->cd_name,
+ ret);
+ if (ret != 0) {
+ return (ret);
+ }
+ if (ctf_update(cdp->cd_ctfp) != 0) {
+ return (ctf_dwarf_error(cdp, cdp->cd_ctfp, 0,
+ "failed to update output ctf container"));
+ }
+
+ ret = ctf_dwarf_fixup_die(cdp, B_FALSE);
+ ctf_dprintf("ctf_dwarf_fixup_die (%s) returned %d\n", cdp->cd_name,
+ ret);
+ if (ret != 0) {
+ return (ret);
+ }
+ if (ctf_update(cdp->cd_ctfp) != 0) {
+ return (ctf_dwarf_error(cdp, cdp->cd_ctfp, 0,
+ "failed to update output ctf container"));
+ }
+
+ ret = ctf_dwarf_fixup_die(cdp, B_TRUE);
+ ctf_dprintf("ctf_dwarf_fixup_die (%s) returned %d\n", cdp->cd_name,
+ ret);
+ if (ret != 0) {
+ return (ret);
+ }
+ if (ctf_update(cdp->cd_ctfp) != 0) {
+ return (ctf_dwarf_error(cdp, cdp->cd_ctfp, 0,
+ "failed to update output ctf container"));
+ }
+
+
+ if ((ret = ctf_dwarf_conv_funcvars(cdp)) != 0) {
+ return (ctf_dwarf_error(cdp, NULL, ret,
+ "failed to convert strong functions and variables"));
+ }
+
+ if (ctf_update(cdp->cd_ctfp) != 0) {
+ return (ctf_dwarf_error(cdp, cdp->cd_ctfp, 0,
+ "failed to update output ctf container"));
+ }
+
+ if ((ret = ctf_dwarf_conv_weaks(cdp)) != 0) {
+ return (ctf_dwarf_error(cdp, NULL, ret,
+ "failed to convert weak functions and variables"));
+ }
+
+ if (ctf_update(cdp->cd_ctfp) != 0) {
+ return (ctf_dwarf_error(cdp, cdp->cd_ctfp, 0,
+ "failed to update output ctf container"));
+ }
+
+ ctf_phase_dump(cdp->cd_ctfp, "pre-dedup");
+ ctf_dprintf("adding inputs for dedup\n");
+ if ((ret = ctf_merge_add(cdp->cd_cmh, cdp->cd_ctfp)) != 0) {
+ return (ctf_dwarf_error(cdp, NULL, ret,
+ "failed to add inputs for merge"));
+ }
+
+ ctf_dprintf("starting merge\n");
+ if ((ret = ctf_merge_dedup(cdp->cd_cmh, &dedup)) != 0) {
+ return (ctf_dwarf_error(cdp, NULL, ret,
+ "failed to deduplicate die"));
+ }
+ ctf_close(cdp->cd_ctfp);
+ cdp->cd_ctfp = dedup;
+
+ return (0);
+}
+
+/*
+ * Note, we expect that if we're returning a ctf_file_t from one of the dies,
+ * say in the single node case, it's been saved and the entry here has been set
+ * to NULL, which ctf_close happily ignores.
+ */
+static void
+ctf_dwarf_free_die(ctf_die_t *cdp)
+{
+ ctf_dwfunc_t *cdf, *ndf;
+ ctf_dwvar_t *cdv, *ndv;
+ ctf_dwbitf_t *cdb, *ndb;
+ ctf_dwmap_t *map;
+ void *cookie;
+ Dwarf_Error derr;
+
+ ctf_dprintf("Beginning to free die: %p\n", cdp);
+ cdp->cd_elf = NULL;
+ ctf_dprintf("Trying to free name: %p\n", cdp->cd_name);
+ if (cdp->cd_name != NULL)
+ ctf_free(cdp->cd_name, strlen(cdp->cd_name) + 1);
+ ctf_dprintf("Trying to free merge handle: %p\n", cdp->cd_cmh);
+ if (cdp->cd_cmh != NULL) {
+ ctf_merge_fini(cdp->cd_cmh);
+ cdp->cd_cmh = NULL;
+ }
+
+ ctf_dprintf("Trying to free functions\n");
+ for (cdf = ctf_list_next(&cdp->cd_funcs); cdf != NULL; cdf = ndf) {
+ ndf = ctf_list_next(cdf);
+ ctf_free(cdf->cdf_name, strlen(cdf->cdf_name) + 1);
+ if (cdf->cdf_fip.ctc_argc != 0) {
+ ctf_free(cdf->cdf_argv,
+ sizeof (ctf_id_t) * cdf->cdf_fip.ctc_argc);
+ }
+ ctf_free(cdf, sizeof (ctf_dwfunc_t));
+ }
+
+ ctf_dprintf("Trying to free variables\n");
+ for (cdv = ctf_list_next(&cdp->cd_vars); cdv != NULL; cdv = ndv) {
+ ndv = ctf_list_next(cdv);
+ ctf_free(cdv->cdv_name, strlen(cdv->cdv_name) + 1);
+ ctf_free(cdv, sizeof (ctf_dwvar_t));
+ }
+
+ ctf_dprintf("Trying to free bitfields\n");
+ for (cdb = ctf_list_next(&cdp->cd_bitfields); cdb != NULL; cdb = ndb) {
+ ndb = ctf_list_next(cdb);
+ ctf_free(cdb, sizeof (ctf_dwbitf_t));
+ }
+
+ /* How do we clean up die usage? */
+ ctf_dprintf("Trying to clean up dwarf_t: %p\n", cdp->cd_dwarf);
+ (void) dwarf_finish(cdp->cd_dwarf, &derr);
+ cdp->cd_dwarf = NULL;
+ ctf_close(cdp->cd_ctfp);
+
+ cookie = NULL;
+ while ((map = avl_destroy_nodes(&cdp->cd_map, &cookie)) != NULL) {
+ ctf_free(map, sizeof (ctf_dwmap_t));
+ }
+ avl_destroy(&cdp->cd_map);
+ cdp->cd_errbuf = NULL;
+}
+
+static void
+ctf_dwarf_free_dies(ctf_die_t *cdies, int ndies)
+{
+ int i;
+
+ ctf_dprintf("Beginning to free dies\n");
+ for (i = 0; i < ndies; i++) {
+ ctf_dwarf_free_die(&cdies[i]);
+ }
+
+ ctf_free(cdies, sizeof (ctf_die_t) * ndies);
+}
+
+static int
+ctf_dwarf_count_dies(Dwarf_Debug dw, Dwarf_Error *derr, int *ndies,
+ char *errbuf, size_t errlen)
+{
+ int ret;
+ Dwarf_Half vers;
+ Dwarf_Unsigned nexthdr;
+
+ while ((ret = dwarf_next_cu_header(dw, NULL, &vers, NULL, NULL,
+ &nexthdr, derr)) != DW_DLV_NO_ENTRY) {
+ if (ret != DW_DLV_OK) {
+ (void) snprintf(errbuf, errlen,
+ "file does not contain valid DWARF data: %s\n",
+ dwarf_errmsg(*derr));
+ return (ECTF_CONVBKERR);
+ }
+
+ if (vers != DWARF_VERSION_TWO) {
+ (void) snprintf(errbuf, errlen,
+ "unsupported DWARF version: %d\n", vers);
+ return (ECTF_CONVBKERR);
+ }
+ *ndies = *ndies + 1;
+ }
+
+ if (*ndies == 0) {
+ (void) snprintf(errbuf, errlen,
+ "file does not contain valid DWARF data: %s\n",
+ dwarf_errmsg(*derr));
+ return (ECTF_CONVBKERR);
+ }
+
+ return (0);
+}
+
+/*
+ * Iterate over all of the dies and create a ctf_die_t for each of them. This is
+ * used to determine if we have zero, one, or multiple dies to convert. If we
+ * have zero, that's an error. If there's only one die, that's the simple case.
+ * No merge needed and only a single Dwarf_Debug as well.
+ */
+static int
+ctf_dwarf_init_die(int fd, Elf *elf, ctf_die_t *cdp, int ndie, char *errbuf,
+ size_t errlen)
+{
+ int ret;
+ Dwarf_Unsigned hdrlen, abboff, nexthdr;
+ Dwarf_Half addrsz;
+ Dwarf_Unsigned offset = 0;
+ Dwarf_Error derr;
+
+ while ((ret = dwarf_next_cu_header(cdp->cd_dwarf, &hdrlen, NULL,
+ &abboff, &addrsz, &nexthdr, &derr)) != DW_DLV_NO_ENTRY) {
+ char *name;
+ Dwarf_Die cu, child;
+
+ /* Based on the counting above, we should be good to go */
+ VERIFY(ret == DW_DLV_OK);
+ if (ndie > 0) {
+ ndie--;
+ offset = nexthdr;
+ continue;
+ }
+
+ /*
+ * Compilers are apparently inconsistent. Some emit no DWARF for
+ * empty files and others emit empty compilation unit.
+ */
+ cdp->cd_voidtid = CTF_ERR;
+ cdp->cd_longtid = CTF_ERR;
+ cdp->cd_elf = elf;
+ cdp->cd_maxoff = nexthdr - 1;
+ cdp->cd_ctfp = ctf_fdcreate(fd, &ret);
+ if (cdp->cd_ctfp == NULL) {
+ ctf_free(cdp, sizeof (ctf_die_t));
+ return (ret);
+ }
+ avl_create(&cdp->cd_map, ctf_dwmap_comp, sizeof (ctf_dwmap_t),
+ offsetof(ctf_dwmap_t, cdm_avl));
+ cdp->cd_errbuf = errbuf;
+ cdp->cd_errlen = errlen;
+ bzero(&cdp->cd_vars, sizeof (ctf_list_t));
+ bzero(&cdp->cd_funcs, sizeof (ctf_list_t));
+ bzero(&cdp->cd_bitfields, sizeof (ctf_list_t));
+
+ if ((ret = ctf_dwarf_die_elfenc(elf, cdp, errbuf,
+ errlen)) != 0) {
+ avl_destroy(&cdp->cd_map);
+ ctf_free(cdp, sizeof (ctf_die_t));
+ return (ret);
+ }
+
+ if ((ret = ctf_dwarf_sib(cdp, NULL, &cu)) != 0) {
+ avl_destroy(&cdp->cd_map);
+ ctf_free(cdp, sizeof (ctf_die_t));
+ return (ret);
+ }
+ if (cu == NULL) {
+ (void) snprintf(errbuf, errlen,
+ "file does not contain DWARF data\n");
+ avl_destroy(&cdp->cd_map);
+ ctf_free(cdp, sizeof (ctf_die_t));
+ return (ECTF_CONVBKERR);
+ }
+
+ if ((ret = ctf_dwarf_child(cdp, cu, &child)) != 0) {
+ avl_destroy(&cdp->cd_map);
+ ctf_free(cdp, sizeof (ctf_die_t));
+ return (ret);
+ }
+ if (child == NULL) {
+ (void) snprintf(errbuf, errlen,
+ "file does not contain DWARF data\n");
+ avl_destroy(&cdp->cd_map);
+ ctf_free(cdp, sizeof (ctf_die_t));
+ return (ECTF_CONVBKERR);
+ }
+
+ cdp->cd_cuoff = offset;
+ cdp->cd_cu = child;
+
+ if ((cdp->cd_cmh = ctf_merge_init(fd, &ret)) == NULL) {
+ avl_destroy(&cdp->cd_map);
+ ctf_free(cdp, sizeof (ctf_die_t));
+ return (ret);
+ }
+
+ if (ctf_dwarf_string(cdp, cu, DW_AT_name, &name) == 0) {
+ size_t len = strlen(name) + 1;
+ char *b = basename(name);
+ cdp->cd_name = strdup(b);
+ ctf_free(name, len);
+ }
+ break;
+ }
+
+ return (0);
+}
+
+
+ctf_conv_status_t
+ctf_dwarf_convert(int fd, Elf *elf, uint_t nthrs, int *errp, ctf_file_t **fpp,
+ char *errmsg, size_t errlen)
+{
+ int err, ret, ndies, i;
+ Dwarf_Debug dw;
+ Dwarf_Error derr;
+ ctf_die_t *cdies = NULL, *cdp;
+ workq_t *wqp = NULL;
+
+ if (errp == NULL)
+ errp = &err;
+ *errp = 0;
+ *fpp = NULL;
+
+ ret = dwarf_elf_init(elf, DW_DLC_READ, NULL, NULL, &dw, &derr);
+ if (ret != DW_DLV_OK) {
+ /*
+ * The old CTF tools used to check if we expected DWARF data
+ * here. In this case, if we actually have some amount of DWARF,
+ * but no section, for now, just go ahead and create an empty
+ * CTF file.
+ */
+ if (ret == DW_DLV_NO_ENTRY ||
+ dwarf_errno(derr) == DW_DLE_DEBUG_INFO_NULL) {
+ *fpp = ctf_create(errp);
+ return (*fpp != NULL ? CTF_CONV_SUCCESS :
+ CTF_CONV_ERROR);
+ }
+ (void) snprintf(errmsg, errlen,
+ "failed to initialize DWARF: %s\n",
+ dwarf_errmsg(derr));
+ *errp = ECTF_CONVBKERR;
+ return (CTF_CONV_ERROR);
+ }
+
+ ndies = 0;
+ ret = ctf_dwarf_count_dies(dw, &derr, &ndies, errmsg, errlen);
+ if (ret != 0) {
+ *errp = ret;
+ goto out;
+ }
+
+ (void) dwarf_finish(dw, &derr);
+ cdies = ctf_alloc(sizeof (ctf_die_t) * ndies);
+ if (cdies == NULL) {
+ *errp = ENOMEM;
+ return (CTF_CONV_ERROR);
+ }
+
+ for (i = 0; i < ndies; i++) {
+ cdp = &cdies[i];
+ ret = dwarf_elf_init(elf, DW_DLC_READ, NULL, NULL,
+ &cdp->cd_dwarf, &derr);
+ if (ret != 0) {
+ ctf_free(cdies, sizeof (ctf_die_t) * ndies);
+ (void) snprintf(errmsg, errlen,
+ "failed to initialize DWARF: %s\n",
+ dwarf_errmsg(derr));
+ *errp = ECTF_CONVBKERR;
+ return (CTF_CONV_ERROR);
+ }
+
+ ret = ctf_dwarf_init_die(fd, elf, &cdies[i], i, errmsg, errlen);
+ if (ret != 0) {
+ *errp = ret;
+ goto out;
+ }
+ }
+
+ ctf_dprintf("found %d DWARF die(s)\n", ndies);
+
+ /*
+ * If we only have one die, there's no reason to use multiple threads,
+ * even if the user requested them. After all, they just gave us an
+ * upper bound.
+ */
+ if (ndies == 1)
+ nthrs = 1;
+
+ if (workq_init(&wqp, nthrs) == -1) {
+ *errp = errno;
+ goto out;
+ }
+
+ for (i = 0; i < ndies; i++) {
+ cdp = &cdies[i];
+ ctf_dprintf("adding die %s: %p, %x %x\n", cdp->cd_name,
+ cdp->cd_cu, cdp->cd_cuoff, cdp->cd_maxoff);
+ if (workq_add(wqp, cdp) == -1) {
+ *errp = errno;
+ goto out;
+ }
+ }
+
+ ret = workq_work(wqp, ctf_dwarf_convert_one, NULL, errp);
+ if (ret == WORKQ_ERROR) {
+ *errp = errno;
+ goto out;
+ } else if (ret == WORKQ_UERROR) {
+ ctf_dprintf("internal convert failed: %s\n",
+ ctf_errmsg(*errp));
+ goto out;
+ }
+
+ ctf_dprintf("Determining next phase: have %d dies\n", ndies);
+ if (ndies != 1) {
+ ctf_merge_t *cmp;
+
+ cmp = ctf_merge_init(fd, &ret);
+ if (cmp == NULL) {
+ *errp = ret;
+ goto out;
+ }
+
+ ctf_dprintf("setting threads\n");
+ if ((ret = ctf_merge_set_nthreads(cmp, nthrs)) != 0) {
+ ctf_merge_fini(cmp);
+ *errp = ret;
+ goto out;
+ }
+
+ ctf_dprintf("adding dies\n");
+ for (i = 0; i < ndies; i++) {
+ cdp = &cdies[i];
+ if ((ret = ctf_merge_add(cmp, cdp->cd_ctfp)) != 0) {
+ ctf_merge_fini(cmp);
+ *errp = ret;
+ goto out;
+ }
+ }
+
+ ctf_dprintf("performing merge\n");
+ ret = ctf_merge_merge(cmp, fpp);
+ if (ret != 0) {
+ ctf_dprintf("failed merge!\n");
+ *fpp = NULL;
+ ctf_merge_fini(cmp);
+ *errp = ret;
+ goto out;
+ }
+ ctf_merge_fini(cmp);
+ *errp = 0;
+ ctf_dprintf("successfully converted!\n");
+ } else {
+ *errp = 0;
+ *fpp = cdies->cd_ctfp;
+ cdies->cd_ctfp = NULL;
+ ctf_dprintf("successfully converted!\n");
+ }
+
+out:
+ workq_fini(wqp);
+ ctf_dwarf_free_dies(cdies, ndies);
+ return (*fpp != NULL ? CTF_CONV_SUCCESS : CTF_CONV_ERROR);
+}
diff --git a/usr/src/lib/libctf/common/ctf_elfwrite.c b/usr/src/lib/libctf/common/ctf_elfwrite.c
index c8a4d22cf7..4d7c10aeec 100644
--- a/usr/src/lib/libctf/common/ctf_elfwrite.c
+++ b/usr/src/lib/libctf/common/ctf_elfwrite.c
@@ -30,7 +30,7 @@
* Routines for writing ctf data to elf files, originally from the ctf tools.
*/
-#include <ctf_impl.h>
+#include <libctf_impl.h>
#include <libctf.h>
#include <gelf.h>
#include <sys/stat.h>
@@ -39,7 +39,6 @@
#include <errno.h>
#include <unistd.h>
#include <libelf.h>
-#include <sys/zmod.h>
static int
ctf_write_elf(ctf_file_t *fp, Elf *src, Elf *dst, int flags)
@@ -52,37 +51,54 @@ ctf_write_elf(ctf_file_t *fp, Elf *src, Elf *dst, int flags)
off_t new_offset = 0;
off_t ctfnameoff = 0;
int compress = (flags & CTF_ELFWRITE_F_COMPRESS);
- int *secxlate;
+ int *secxlate = NULL;
int srcidx, dstidx, pad, i;
int curnmoff = 0;
int changing = 0;
+ int ret;
size_t nshdr, nphdr, strndx;
+ void *strdatabuf = NULL, *symdatabuf = NULL;
+ size_t strdatasz = 0, symdatasz = 0;
void *cdata = NULL;
+ size_t elfsize, asize;
- if ((flags & ~(CTF_ELFWRITE_F_COMPRESS)) != 0)
- return (ctf_set_errno(fp, EINVAL));
-
- if (gelf_newehdr(dst, gelf_getclass(src)) == NULL)
- return (ctf_set_errno(fp, ECTF_ELF));
+ if ((flags & ~(CTF_ELFWRITE_F_COMPRESS)) != 0) {
+ ret = ctf_set_errno(fp, EINVAL);
+ goto out;
+ }
- if (gelf_getehdr(src, &sehdr) == NULL)
- return (ctf_set_errno(fp, ECTF_ELF));
+ if (gelf_newehdr(dst, gelf_getclass(src)) == NULL) {
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
+ }
+ if (gelf_getehdr(src, &sehdr) == NULL) {
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
+ }
(void) memcpy(&dehdr, &sehdr, sizeof (GElf_Ehdr));
- if (gelf_update_ehdr(dst, &dehdr) == 0)
- return (ctf_set_errno(fp, ECTF_ELF));
+ if (gelf_update_ehdr(dst, &dehdr) == 0) {
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
+ }
/*
* Use libelf to get the number of sections and the string section to
* deal with ELF files that may have a large number of sections. We just
* always use this to make our live easier.
*/
- if (elf_getphdrnum(src, &nphdr) != 0)
- return (ctf_set_errno(fp, ECTF_ELF));
- if (elf_getshdrnum(src, &nshdr) != 0)
- return (ctf_set_errno(fp, ECTF_ELF));
- if (elf_getshdrstrndx(src, &strndx) != 0)
- return (ctf_set_errno(fp, ECTF_ELF));
+ if (elf_getphdrnum(src, &nphdr) != 0) {
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
+ }
+ if (elf_getshdrnum(src, &nshdr) != 0) {
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
+ }
+ if (elf_getshdrstrndx(src, &strndx) != 0) {
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
+ }
/*
* Neither the existing debug sections nor the SUNW_ctf sections (new or
@@ -92,16 +108,22 @@ ctf_write_elf(ctf_file_t *fp, Elf *src, Elf *dst, int flags)
*/
if (nphdr != 0) {
(void) elf_flagelf(dst, ELF_C_SET, ELF_F_LAYOUT);
- if (gelf_newphdr(dst, nphdr) == NULL)
- return (ctf_set_errno(fp, ECTF_ELF));
+ if (gelf_newphdr(dst, nphdr) == NULL) {
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
+ }
for (i = 0; i < nphdr; i++) {
GElf_Phdr phdr;
- if (gelf_getphdr(src, i, &phdr) == NULL)
- return (ctf_set_errno(fp, ECTF_ELF));
- if (gelf_update_phdr(dst, i, &phdr) == 0)
- return (ctf_set_errno(fp, ECTF_ELF));
+ if (gelf_getphdr(src, i, &phdr) == NULL) {
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
+ }
+ if (gelf_update_phdr(dst, i, &phdr) == 0) {
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
+ }
}
}
@@ -112,13 +134,13 @@ ctf_write_elf(ctf_file_t *fp, Elf *src, Elf *dst, int flags)
char *sname;
if (gelf_getshdr(scn, &shdr) == NULL) {
- ctf_free(secxlate, sizeof (int) * nshdr);
- return (ctf_set_errno(fp, ECTF_ELF));
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
}
sname = elf_strptr(src, strndx, shdr.sh_name);
if (sname == NULL) {
- ctf_free(secxlate, sizeof (int) * nshdr);
- return (ctf_set_errno(fp, ECTF_ELF));
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
}
if (strcmp(sname, CTF_ELF_SCN_NAME) == 0) {
@@ -136,8 +158,8 @@ ctf_write_elf(ctf_file_t *fp, Elf *src, Elf *dst, int flags)
sscn = elf_getscn(src, srcidx);
if (gelf_getshdr(sscn, &shdr) == NULL) {
- ctf_free(secxlate, sizeof (int) * nshdr);
- return (ctf_set_errno(fp, ECTF_ELF));
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
}
if (secxlate[srcidx] == -1) {
@@ -147,8 +169,8 @@ ctf_write_elf(ctf_file_t *fp, Elf *src, Elf *dst, int flags)
dscn = elf_newscn(dst);
if (dscn == NULL) {
- ctf_free(secxlate, sizeof (int) * nshdr);
- return (ctf_set_errno(fp, ECTF_ELF));
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
}
/*
@@ -173,28 +195,28 @@ ctf_write_elf(ctf_file_t *fp, Elf *src, Elf *dst, int flags)
sname = elf_strptr(src, strndx, shdr.sh_name);
if (sname == NULL) {
- ctf_free(secxlate, sizeof (int) * nshdr);
- return (ctf_set_errno(fp, ECTF_ELF));
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
}
if ((sdata = elf_getdata(sscn, NULL)) == NULL) {
- ctf_free(secxlate, sizeof (int) * nshdr);
- return (ctf_set_errno(fp, ECTF_ELF));
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
}
if ((ddata = elf_newdata(dscn)) == NULL) {
- ctf_free(secxlate, sizeof (int) * nshdr);
- return (ctf_set_errno(fp, ECTF_ELF));
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
}
bcopy(sdata, ddata, sizeof (Elf_Data));
if (srcidx == strndx) {
char seclen = strlen(CTF_ELF_SCN_NAME);
- ddata->d_buf = ctf_alloc(ddata->d_size + shdr.sh_size +
- seclen + 1);
+ strdatasz = ddata->d_size + shdr.sh_size +
+ seclen + 1;
+ ddata->d_buf = strdatabuf = ctf_alloc(strdatasz);
if (ddata->d_buf == NULL) {
- ctf_free(secxlate,
- sizeof (int) * nshdr);
- return (ctf_set_errno(fp, ECTF_ELF));
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
}
bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size);
(void) strcpy((caddr_t)ddata->d_buf + shdr.sh_size,
@@ -212,11 +234,11 @@ ctf_write_elf(ctf_file_t *fp, Elf *src, Elf *dst, int flags)
symtab_idx = secxlate[srcidx];
- ddata->d_buf = ctf_alloc(shdr.sh_size);
+ symdatasz = shdr.sh_size;
+ ddata->d_buf = symdatabuf = ctf_alloc(symdatasz);
if (ddata->d_buf == NULL) {
- ctf_free(secxlate,
- sizeof (int) * nshdr);
- return (ctf_set_errno(fp, ECTF_ELF));
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
}
(void) bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size);
@@ -236,19 +258,17 @@ ctf_write_elf(ctf_file_t *fp, Elf *src, Elf *dst, int flags)
if (gelf_update_sym(ddata, i, &sym) ==
0) {
- ctf_free(secxlate,
- sizeof (int) *
- nshdr);
- return (ctf_set_errno(fp,
- ECTF_ELF));
+ ret = ctf_set_errno(fp,
+ ECTF_ELF);
+ goto out;
}
}
}
}
if (gelf_update_shdr(dscn, &shdr) == NULL) {
- ctf_free(secxlate, sizeof (int) * nshdr);
- return (ctf_set_errno(fp, ECTF_ELF));
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
}
new_offset = (off_t)shdr.sh_offset;
@@ -257,18 +277,18 @@ ctf_write_elf(ctf_file_t *fp, Elf *src, Elf *dst, int flags)
}
if (symtab_idx == -1) {
- ctf_free(secxlate, sizeof (int) * nshdr);
- return (ctf_set_errno(fp, ECTF_ELF));
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
}
/* Add the ctf section */
if ((dscn = elf_newscn(dst)) == NULL) {
- ctf_free(secxlate, sizeof (int) * nshdr);
- return (ctf_set_errno(fp, ECTF_ELF));
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
}
if (gelf_getshdr(dscn, &shdr) == NULL) {
- ctf_free(secxlate, sizeof (int) * nshdr);
- return (ctf_set_errno(fp, ECTF_ELF));
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
}
shdr.sh_name = ctfnameoff;
shdr.sh_type = SHT_PROGBITS;
@@ -286,36 +306,24 @@ ctf_write_elf(ctf_file_t *fp, Elf *src, Elf *dst, int flags)
}
if ((ddata = elf_newdata(dscn)) == NULL) {
- ctf_free(secxlate, sizeof (int) * nshdr);
- return (ctf_set_errno(fp, ECTF_ELF));
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
}
if (compress != 0) {
- size_t dlen;
- ctf_header_t *cthp;
int err;
if (ctf_zopen(&err) == NULL) {
- ctf_free(secxlate, sizeof (int) * nshdr);
- return (ctf_set_errno(fp, err));
+ ret = ctf_set_errno(fp, err);
+ goto out;
}
- dlen = fp->ctf_size;
- cdata = ctf_data_alloc(dlen);
- bcopy(fp->ctf_base, cdata, sizeof (ctf_header_t));
- cthp = cdata;
- cthp->cth_flags |= CTF_F_COMPRESS;
- dlen -= sizeof (ctf_header_t);
- if (z_compress((void *)((uintptr_t)cdata +
- sizeof (ctf_header_t)), &dlen,
- fp->ctf_base + sizeof (ctf_header_t),
- fp->ctf_size - sizeof (ctf_header_t)) != Z_OK) {
- ctf_data_free(cdata, fp->ctf_size);
- ctf_free(secxlate, sizeof (int) * nshdr);
- return (ctf_set_errno(fp, ECTF_ZLIB));
+ if ((err = ctf_compress(fp, &cdata, &asize, &elfsize)) != 0) {
+ ret = ctf_set_errno(fp, err);
+ goto out;
}
ddata->d_buf = cdata;
- ddata->d_size = dlen + sizeof (ctf_header_t);
+ ddata->d_size = elfsize;
} else {
ddata->d_buf = (void *)fp->ctf_base;
ddata->d_size = fp->ctf_size;
@@ -323,10 +331,8 @@ ctf_write_elf(ctf_file_t *fp, Elf *src, Elf *dst, int flags)
ddata->d_align = shdr.sh_addralign;
if (gelf_update_shdr(dscn, &shdr) == 0) {
- if (cdata != NULL)
- ctf_data_free(cdata, fp->ctf_size);
- ctf_free(secxlate, sizeof (int) * nshdr);
- return (ctf_set_errno(fp, ECTF_ELF));
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
}
/* update the section header location */
@@ -346,23 +352,27 @@ ctf_write_elf(ctf_file_t *fp, Elf *src, Elf *dst, int flags)
else
dehdr.e_shstrndx = secxlate[sehdr.e_shstrndx];
if (gelf_update_ehdr(dst, &dehdr) == NULL) {
- if (cdata != NULL)
- ctf_data_free(cdata, fp->ctf_size);
- ctf_free(secxlate, sizeof (int) * nshdr);
- return (ctf_set_errno(fp, ECTF_ELF));
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
}
if (elf_update(dst, ELF_C_WRITE) < 0) {
- if (cdata != NULL)
- ctf_data_free(cdata, fp->ctf_size);
- ctf_free(secxlate, sizeof (int) * nshdr);
- return (ctf_set_errno(fp, ECTF_ELF));
+ ret = ctf_set_errno(fp, ECTF_ELF);
+ goto out;
}
+ ret = 0;
+
+out:
+ if (strdatabuf != NULL)
+ ctf_free(strdatabuf, strdatasz);
+ if (symdatabuf != NULL)
+ ctf_free(symdatabuf, symdatasz);
if (cdata != NULL)
ctf_data_free(cdata, fp->ctf_size);
- ctf_free(secxlate, sizeof (int) * nshdr);
+ if (secxlate != NULL)
+ ctf_free(secxlate, sizeof (int) * nshdr);
- return (0);
+ return (ret);
}
int
diff --git a/usr/src/lib/libctf/common/ctf_lib.c b/usr/src/lib/libctf/common/ctf_lib.c
index 4658fc8ddc..6b637ba663 100644
--- a/usr/src/lib/libctf/common/ctf_lib.c
+++ b/usr/src/lib/libctf/common/ctf_lib.c
@@ -38,6 +38,7 @@
#include <gelf.h>
#include <zlib.h>
#include <zone.h>
+#include <sys/debug.h>
#ifdef _LP64
static const char *_libctf_zlib = "/usr/lib/64/libz.so.1";
@@ -57,6 +58,18 @@ static struct {
static size_t _PAGESIZE;
static size_t _PAGEMASK;
+static uint64_t ctf_phase = 0;
+
+#define CTF_COMPRESS_CHUNK (64*1024)
+
+typedef struct ctf_zdata {
+ void *czd_buf;
+ void *czd_next;
+ ctf_file_t *czd_ctfp;
+ size_t czd_allocsz;
+ z_stream czd_zstr;
+} ctf_zdata_t;
+
#pragma init(_libctf_init)
void
_libctf_init(void)
@@ -145,6 +158,182 @@ z_strerror(int err)
return (zlib.z_error(err));
}
+static int
+ctf_zdata_init(ctf_zdata_t *czd, ctf_file_t *fp)
+{
+ int err;
+ ctf_header_t *cthp;
+
+ bzero(czd, sizeof (ctf_zdata_t));
+
+ czd->czd_allocsz = fp->ctf_size;
+ czd->czd_buf = ctf_data_alloc(czd->czd_allocsz);
+ if (czd->czd_buf == MAP_FAILED)
+ return (ctf_set_errno(fp, ENOMEM));
+
+ bcopy(fp->ctf_base, czd->czd_buf, sizeof (ctf_header_t));
+ czd->czd_ctfp = fp;
+ cthp = czd->czd_buf;
+ cthp->cth_flags |= CTF_F_COMPRESS;
+ czd->czd_next = (void *)((uintptr_t)czd->czd_buf +
+ sizeof (ctf_header_t));
+
+ if ((err = zlib.z_initcomp(&czd->czd_zstr, Z_BEST_COMPRESSION,
+ ZLIB_VERSION, sizeof (z_stream))) != Z_OK)
+ return (ctf_set_errno(fp, ECTF_ZLIB));
+
+ return (0);
+}
+
+static int
+ctf_zdata_grow(ctf_zdata_t *czd)
+{
+ size_t off;
+ size_t newsz;
+ void *ndata;
+
+ off = (uintptr_t)czd->czd_next - (uintptr_t)czd->czd_buf;
+ newsz = czd->czd_allocsz + CTF_COMPRESS_CHUNK;
+ ndata = ctf_data_alloc(newsz);
+ if (ndata == MAP_FAILED) {
+ return (ctf_set_errno(czd->czd_ctfp, ENOMEM));
+ }
+
+ bcopy(czd->czd_buf, ndata, off);
+ ctf_data_free(czd->czd_buf, czd->czd_allocsz);
+ czd->czd_allocsz = newsz;
+ czd->czd_buf = ndata;
+ czd->czd_next = (void *)((uintptr_t)ndata + off);
+
+ czd->czd_zstr.next_out = (Bytef *)czd->czd_next;
+ czd->czd_zstr.avail_out = CTF_COMPRESS_CHUNK;
+ return (0);
+}
+
+static int
+ctf_zdata_compress_buffer(ctf_zdata_t *czd, const void *buf, size_t bufsize)
+{
+ int err;
+
+ czd->czd_zstr.next_out = czd->czd_next;
+ czd->czd_zstr.avail_out = czd->czd_allocsz -
+ (czd->czd_next - czd->czd_buf);
+ czd->czd_zstr.next_in = (Bytef *)buf;
+ czd->czd_zstr.avail_in = bufsize;
+
+ while (czd->czd_zstr.avail_in != 0) {
+ if (czd->czd_zstr.avail_out == 0) {
+ czd->czd_next = czd->czd_zstr.next_out;
+ if ((err = ctf_zdata_grow(czd)) != 0) {
+ return (err);
+ }
+ }
+
+ if ((err = zlib.z_compress(&czd->czd_zstr, Z_NO_FLUSH)) != Z_OK)
+ return (ctf_set_errno(czd->czd_ctfp, ECTF_ZLIB));
+ }
+ czd->czd_next = czd->czd_zstr.next_out;
+
+ return (0);
+}
+
+static int
+ctf_zdata_flush(ctf_zdata_t *czd, boolean_t finish)
+{
+ int err;
+ int flag = finish == B_TRUE ? Z_FINISH : Z_FULL_FLUSH;
+ int bret = finish == B_TRUE ? Z_STREAM_END : Z_BUF_ERROR;
+
+ for (;;) {
+ if (czd->czd_zstr.avail_out == 0) {
+ czd->czd_next = czd->czd_zstr.next_out;
+ if ((err = ctf_zdata_grow(czd)) != 0) {
+ return (err);
+ }
+ }
+
+ err = zlib.z_compress(&czd->czd_zstr, flag);
+ if (err == bret) {
+ break;
+ }
+ if (err != Z_OK)
+ return (ctf_set_errno(czd->czd_ctfp, ECTF_ZLIB));
+
+ }
+
+ czd->czd_next = czd->czd_zstr.next_out;
+
+ return (0);
+}
+
+static int
+ctf_zdata_end(ctf_zdata_t *czd)
+{
+ int ret;
+
+ if ((ret = ctf_zdata_flush(czd, B_TRUE)) != 0)
+ return (ret);
+
+ if ((ret = zlib.z_finicomp(&czd->czd_zstr)) != 0)
+ return (ctf_set_errno(czd->czd_ctfp, ECTF_ZLIB));
+
+ return (0);
+}
+
+static void
+ctf_zdata_cleanup(ctf_zdata_t *czd)
+{
+ ctf_data_free(czd->czd_buf, czd->czd_allocsz);
+ (void) zlib.z_finicomp(&czd->czd_zstr);
+}
+
+/*
+ * Compress our CTF data and return both the size of the compressed data and the
+ * size of the allocation. These may be different due to the nature of
+ * compression.
+ *
+ * In addition, we flush the compression inbetween our two phases such that we
+ * maintain a different dictionary bbetween the CTF data and the string section.
+ */
+int
+ctf_compress(ctf_file_t *fp, void **buf, size_t *allocsz, size_t *elfsize)
+{
+ int err;
+ ctf_zdata_t czd;
+ ctf_header_t *cthp = (ctf_header_t *)fp->ctf_base;
+
+ if ((err = ctf_zdata_init(&czd, fp)) != 0)
+ return (err);
+
+ if ((err = ctf_zdata_compress_buffer(&czd, fp->ctf_buf,
+ cthp->cth_stroff)) != 0) {
+ ctf_zdata_cleanup(&czd);
+ return (err);
+ }
+
+ if ((err = ctf_zdata_flush(&czd, B_FALSE)) != 0) {
+ ctf_zdata_cleanup(&czd);
+ return (err);
+ }
+
+ if ((err = ctf_zdata_compress_buffer(&czd,
+ fp->ctf_buf + cthp->cth_stroff, cthp->cth_strlen)) != 0) {
+ ctf_zdata_cleanup(&czd);
+ return (err);
+ }
+
+ if ((err = ctf_zdata_end(&czd)) != 0) {
+ ctf_zdata_cleanup(&czd);
+ return (err);
+ }
+
+ *buf = czd.czd_buf;
+ *allocsz = czd.czd_allocsz;
+ *elfsize = (uintptr_t)(czd.czd_next - czd.czd_buf);
+
+ return (0);
+}
+
int
z_compress(void *dst, size_t *dstlen, const void *src, size_t srclen)
{
@@ -576,3 +765,25 @@ ctf_version(int version)
return (_libctf_version);
}
+
+/*
+ * A utility function for folks debugging CTF conversion and merging.
+ */
+void
+ctf_phase_dump(ctf_file_t *fp, const char *phase)
+{
+ int fd;
+ static char *base;
+ char path[MAXPATHLEN];
+
+ if (base == NULL && (base = getenv("LIBCTF_WRITE_PHASES")) == NULL)
+ return;
+
+ (void) snprintf(path, sizeof (path), "%s/libctf.%s.%d.ctf", base,
+ phase != NULL ? phase : "",
+ ctf_phase);
+ if ((fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0777)) < 0)
+ return;
+ (void) ctf_write(fp, fd);
+ (void) close(fd);
+}
diff --git a/usr/src/lib/libctf/common/ctf_merge.c b/usr/src/lib/libctf/common/ctf_merge.c
index 70676bb0fd..9611c50acc 100644
--- a/usr/src/lib/libctf/common/ctf_merge.c
+++ b/usr/src/lib/libctf/common/ctf_merge.c
@@ -31,16 +31,15 @@
* we should take care to do the merge in the same way every time.
*/
-#include <ctf_impl.h>
-#include <libctf.h>
+#include <libctf_impl.h>
#include <sys/debug.h>
#include <sys/list.h>
#include <stddef.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
-
-#include <stdio.h>
+#include <mergeq.h>
+#include <errno.h>
typedef struct ctf_merge_tinfo {
uint16_t cmt_map; /* Map to the type in out */
@@ -56,6 +55,7 @@ typedef struct ctf_merge_types {
ctf_file_t *cm_out; /* Output CTF file */
ctf_file_t *cm_src; /* Input CTF file */
ctf_merge_tinfo_t *cm_tmap; /* Type state information */
+ boolean_t cm_dedup; /* Are we doing a dedup? */
} ctf_merge_types_t;
typedef struct ctf_merge_objmap {
@@ -80,11 +80,13 @@ typedef struct ctf_merge_input {
ctf_file_t *cmi_input;
list_t cmi_omap;
list_t cmi_fmap;
+ boolean_t cmi_created;
} ctf_merge_input_t;
struct ctf_merge_handle {
- ctf_file_t *cmh_output; /* Final output */
list_t cmh_inputs; /* Input list */
+ uint_t cmh_ninputs; /* Number of inputs */
+ uint_t cmh_nthreads; /* Number of threads to use */
ctf_file_t *cmh_unique; /* ctf to uniquify against */
boolean_t cmh_msyms; /* Should we merge symbols/funcs? */
int cmh_ofd; /* FD for output file */
@@ -95,6 +97,22 @@ struct ctf_merge_handle {
static int ctf_merge_add_type(ctf_merge_types_t *, ctf_id_t);
+static ctf_id_t
+ctf_merge_gettype(ctf_merge_types_t *cmp, ctf_id_t id)
+{
+ if (cmp->cm_dedup == B_FALSE) {
+ VERIFY(cmp->cm_tmap[id].cmt_map != 0);
+ return (cmp->cm_tmap[id].cmt_map);
+ }
+
+ while (cmp->cm_tmap[id].cmt_missing == B_FALSE) {
+ VERIFY(cmp->cm_tmap[id].cmt_map != 0);
+ id = cmp->cm_tmap[id].cmt_map;
+ }
+ VERIFY(cmp->cm_tmap[id].cmt_map != 0);
+ return (cmp->cm_tmap[id].cmt_map);
+}
+
static void
ctf_merge_diffcb(ctf_file_t *ifp, ctf_id_t iid, boolean_t same, ctf_file_t *ofp,
ctf_id_t oid, void *arg)
@@ -108,6 +126,8 @@ ctf_merge_diffcb(ctf_file_t *ifp, ctf_id_t iid, boolean_t same, ctf_file_t *ofp,
VERIFY(cmt[oid].cmt_map == 0);
cmt[oid].cmt_map = iid;
cmt[oid].cmt_forward = B_TRUE;
+ ctf_dprintf("merge diff forward mapped %d->%d\n", oid,
+ iid);
return;
}
@@ -119,9 +139,11 @@ ctf_merge_diffcb(ctf_file_t *ifp, ctf_id_t iid, boolean_t same, ctf_file_t *ofp,
if (cmt[oid].cmt_map != 0)
return;
cmt[oid].cmt_map = iid;
+ ctf_dprintf("merge diff mapped %d->%d\n", oid, iid);
} else if (ifp == cmp->cm_src) {
VERIFY(cmt[iid].cmt_map == 0);
cmt[iid].cmt_missing = B_TRUE;
+ ctf_dprintf("merge diff said %d is missing\n", iid);
}
}
@@ -176,7 +198,7 @@ ctf_merge_add_array(ctf_merge_types_t *cmp, ctf_id_t id)
return (ret);
ASSERT(cmp->cm_tmap[ar.ctr_contents].cmt_map != 0);
}
- ar.ctr_contents = cmp->cm_tmap[ar.ctr_contents].cmt_map;
+ ar.ctr_contents = ctf_merge_gettype(cmp, ar.ctr_contents);
if (cmp->cm_tmap[ar.ctr_index].cmt_map == 0) {
ret = ctf_merge_add_type(cmp, ar.ctr_index);
@@ -184,7 +206,7 @@ ctf_merge_add_array(ctf_merge_types_t *cmp, ctf_id_t id)
return (ret);
ASSERT(cmp->cm_tmap[ar.ctr_index].cmt_map != 0);
}
- ar.ctr_index = cmp->cm_tmap[ar.ctr_index].cmt_map;
+ ar.ctr_index = ctf_merge_gettype(cmp, ar.ctr_index);
ret = ctf_add_array(cmp->cm_out, flags, &ar);
if (ret == CTF_ERR)
@@ -221,7 +243,7 @@ ctf_merge_add_reftype(ctf_merge_types_t *cmp, ctf_id_t id)
return (ret);
ASSERT(cmp->cm_tmap[reftype].cmt_map != 0);
}
- reftype = cmp->cm_tmap[reftype].cmt_map;
+ reftype = ctf_merge_gettype(cmp, reftype);
ret = ctf_add_reftype(cmp->cm_out, flags, name, reftype,
ctf_type_kind(cmp->cm_src, id));
@@ -258,7 +280,7 @@ ctf_merge_add_typedef(ctf_merge_types_t *cmp, ctf_id_t id)
return (ret);
ASSERT(cmp->cm_tmap[reftype].cmt_map != 0);
}
- reftype = cmp->cm_tmap[reftype].cmt_map;
+ reftype = ctf_merge_gettype(cmp, reftype);
ret = ctf_add_typedef(cmp->cm_out, flags, name, reftype);
if (ret == CTF_ERR)
@@ -346,7 +368,7 @@ ctf_merge_add_func(ctf_merge_types_t *cmp, ctf_id_t id)
return (ret);
ASSERT(cmp->cm_tmap[ctc.ctc_return].cmt_map != 0);
}
- ctc.ctc_return = cmp->cm_tmap[ctc.ctc_return].cmt_map;
+ ctc.ctc_return = ctf_merge_gettype(cmp, ctc.ctc_return);
for (i = 0; i < ctc.ctc_argc; i++) {
if (cmp->cm_tmap[argv[i]].cmt_map == 0) {
@@ -355,7 +377,7 @@ ctf_merge_add_func(ctf_merge_types_t *cmp, ctf_id_t id)
return (ret);
ASSERT(cmp->cm_tmap[argv[i]].cmt_map != 0);
}
- argv[i] = cmp->cm_tmap[argv[i]].cmt_map;
+ argv[i] = ctf_merge_gettype(cmp, argv[i]);
}
ret = ctf_add_funcptr(cmp->cm_out, flags, &ctc, argv);
@@ -411,6 +433,7 @@ ctf_merge_add_member(const char *name, ctf_id_t type, ulong_t offset, void *arg)
VERIFY(cms->cms_cm->cm_tmap[type].cmt_map != 0);
type = cms->cms_cm->cm_tmap[type].cmt_map;
+ ctf_dprintf("Trying to add member %s to %d\n", name, cms->cms_id);
return (ctf_add_member(cms->cms_cm->cm_out, cms->cms_id, name,
type, offset) == CTF_ERR);
}
@@ -421,7 +444,7 @@ ctf_merge_add_member(const char *name, ctf_id_t type, ulong_t offset, void *arg)
* mark all structures and unions as needing to be fixed up.
*/
static int
-ctf_merge_add_su(ctf_merge_types_t *cmp, ctf_id_t id, boolean_t forward)
+ctf_merge_add_sou(ctf_merge_types_t *cmp, ctf_id_t id, boolean_t forward)
{
int flags, kind;
const ctf_type_t *tp;
@@ -451,6 +474,8 @@ ctf_merge_add_su(ctf_merge_types_t *cmp, ctf_id_t id, boolean_t forward)
if (forward == B_FALSE) {
VERIFY(cmp->cm_tmap[id].cmt_map == 0);
cmp->cm_tmap[id].cmt_map = suid;
+ ctf_dprintf("added sou \"%s\" as (%d) %d->%d\n", name, kind, id,
+ suid);
} else {
VERIFY(cmp->cm_tmap[id].cmt_map == suid);
}
@@ -501,7 +526,7 @@ ctf_merge_add_type(ctf_merge_types_t *cmp, ctf_id_t id)
break;
case CTF_K_STRUCT:
case CTF_K_UNION:
- ret = ctf_merge_add_su(cmp, id, B_FALSE);
+ ret = ctf_merge_add_sou(cmp, id, B_FALSE);
break;
case CTF_K_UNKNOWN:
/*
@@ -517,22 +542,29 @@ ctf_merge_add_type(ctf_merge_types_t *cmp, ctf_id_t id)
}
static int
-ctf_merge_fixup_su(ctf_merge_types_t *cmp, ctf_id_t id)
+ctf_merge_fixup_sou(ctf_merge_types_t *cmp, ctf_id_t id)
{
ctf_dtdef_t *dtd;
ctf_merge_su_t cms;
ctf_id_t mapid;
+ ssize_t size;
mapid = cmp->cm_tmap[id].cmt_map;
VERIFY(mapid != 0);
dtd = ctf_dtd_lookup(cmp->cm_out, mapid);
VERIFY(dtd != NULL);
+ ctf_dprintf("Trying to fix up sou %d\n", id);
cms.cms_cm = cmp;
cms.cms_id = mapid;
if (ctf_member_iter(cmp->cm_src, id, ctf_merge_add_member, &cms) != 0)
return (CTF_ERR);
+ if ((size = ctf_type_size(cmp->cm_src, id)) == CTF_ERR)
+ return (CTF_ERR);
+ if (ctf_set_size(cmp->cm_out, mapid, size) == CTF_ERR)
+ return (CTF_ERR);
+
return (0);
}
@@ -545,7 +577,7 @@ ctf_merge_fixup_type(ctf_merge_types_t *cmp, ctf_id_t id)
switch (kind) {
case CTF_K_STRUCT:
case CTF_K_UNION:
- ret = ctf_merge_fixup_su(cmp, id);
+ ret = ctf_merge_fixup_sou(cmp, id);
break;
default:
VERIFY(0);
@@ -555,6 +587,41 @@ ctf_merge_fixup_type(ctf_merge_types_t *cmp, ctf_id_t id)
return (ret);
}
+/*
+ * Now that we've successfully merged everything, we're going to clean
+ * up the merge type table. Traditionally if we had just two different
+ * files that we were working between, the types would be fully
+ * resolved. However, because we were comparing with ourself every step
+ * of the way and not our reduced self, we need to go through and update
+ * every mapped entry to what it now points to in the deduped file.
+ */
+static void
+ctf_merge_fixup_dedup_map(ctf_merge_types_t *cmp)
+{
+ int i;
+
+ for (i = 1; i < cmp->cm_src->ctf_typemax + 1; i++) {
+ ctf_id_t tid;
+
+ /*
+ * Missing types always have their id updated to exactly what it
+ * should be.
+ */
+ if (cmp->cm_tmap[i].cmt_missing == B_TRUE) {
+ VERIFY(cmp->cm_tmap[i].cmt_map != 0);
+ continue;
+ }
+
+ tid = i;
+ while (cmp->cm_tmap[tid].cmt_missing == B_FALSE) {
+ VERIFY(cmp->cm_tmap[tid].cmt_map != 0);
+ tid = cmp->cm_tmap[tid].cmt_map;
+ }
+ VERIFY(cmp->cm_tmap[tid].cmt_map != 0);
+ cmp->cm_tmap[i].cmt_map = cmp->cm_tmap[tid].cmt_map;
+ }
+}
+
/*
* We're going to do three passes over the containers.
@@ -571,19 +638,23 @@ ctf_merge_fixup_type(ctf_merge_types_t *cmp, ctf_id_t id)
*
* Importantly, we *must* call ctf_update between the second and third pass,
* otherwise several of the libctf functions will not properly find the data in
- * the container.
+ * the container. If we're doing a dedup we also fix up the type mapping.
*/
static int
ctf_merge_common(ctf_merge_types_t *cmp)
{
int ret, i;
+ ctf_phase_dump(cmp->cm_src, "merge-common-src");
+ ctf_phase_dump(cmp->cm_out, "merge-common-dest");
+
/* Pass 1 */
for (i = 1; i <= cmp->cm_src->ctf_typemax; i++) {
if (cmp->cm_tmap[i].cmt_forward == B_TRUE) {
- ret = ctf_merge_add_su(cmp, i, B_TRUE);
- if (ret != 0)
+ ret = ctf_merge_add_sou(cmp, i, B_TRUE);
+ if (ret != 0) {
return (ret);
+ }
}
}
@@ -591,8 +662,10 @@ ctf_merge_common(ctf_merge_types_t *cmp)
for (i = 1; i <= cmp->cm_src->ctf_typemax; i++) {
if (cmp->cm_tmap[i].cmt_missing == B_TRUE) {
ret = ctf_merge_add_type(cmp, i);
- if (ret != 0)
+ if (ret != 0) {
+ ctf_dprintf("Failed to merge type %d\n", i);
return (ret);
+ }
}
}
@@ -600,6 +673,11 @@ ctf_merge_common(ctf_merge_types_t *cmp)
if (ret != 0)
return (ret);
+ if (cmp->cm_dedup == B_TRUE) {
+ ctf_merge_fixup_dedup_map(cmp);
+ }
+
+ ctf_dprintf("Beginning merge pass 3\n");
/* Pass 3 */
for (i = 1; i <= cmp->cm_src->ctf_typemax; i++) {
if (cmp->cm_tmap[i].cmt_fixup == B_TRUE) {
@@ -609,6 +687,10 @@ ctf_merge_common(ctf_merge_types_t *cmp)
}
}
+ if (cmp->cm_dedup == B_TRUE) {
+ ctf_merge_fixup_dedup_map(cmp);
+ }
+
return (0);
}
@@ -666,18 +748,24 @@ ctf_merge_types_fini(ctf_merge_types_t *cmp)
}
/*
- * Merge types from targ into dest.
+ * Merge the types contained inside of two input files. The second input file is
+ * always going to be the destination. We're guaranteed that it's always
+ * writeable.
*/
static int
-ctf_merge(ctf_file_t **outp, ctf_merge_input_t *cmi)
+ctf_merge_types(void *arg, void *arg2, void **outp, void *unsued)
{
int ret;
ctf_merge_types_t cm;
ctf_diff_t *cdp;
ctf_merge_objmap_t *cmo;
ctf_merge_funcmap_t *cmf;
- ctf_file_t *out = *outp;
- ctf_file_t *source = cmi->cmi_input;
+ ctf_merge_input_t *scmi = arg;
+ ctf_merge_input_t *dcmi = arg2;
+ ctf_file_t *out = dcmi->cmi_input;
+ ctf_file_t *source = scmi->cmi_input;
+
+ ctf_dprintf("merging %p->%p\n", source, out);
if (!(out->ctf_flags & LCTF_RDWR))
return (ctf_set_errno(out, ECTF_RDONLY));
@@ -690,6 +778,7 @@ ctf_merge(ctf_file_t **outp, ctf_merge_input_t *cmi)
cm.cm_out = out;
cm.cm_src = source;
+ cm.cm_dedup = B_FALSE;
ret = ctf_merge_types_init(&cm);
if (ret != 0) {
ctf_diff_fini(cdp);
@@ -700,24 +789,27 @@ ctf_merge(ctf_file_t **outp, ctf_merge_input_t *cmi)
if (ret != 0)
goto cleanup;
ret = ctf_merge_common(&cm);
- if (ret == 0)
+ ctf_dprintf("merge common returned with %d\n", ret);
+ if (ret == 0) {
ret = ctf_update(out);
- else
+ ctf_dprintf("update returned with %d\n", ret);
+ } else {
goto cleanup;
+ }
/*
* Now we need to fix up the object and function maps.
*/
- for (cmo = list_head(&cmi->cmi_omap); cmo != NULL;
- cmo = list_next(&cmi->cmi_omap, cmo)) {
+ for (cmo = list_head(&scmi->cmi_omap); cmo != NULL;
+ cmo = list_next(&scmi->cmi_omap, cmo)) {
if (cmo->cmo_tid == 0)
continue;
VERIFY(cm.cm_tmap[cmo->cmo_tid].cmt_map != 0);
cmo->cmo_tid = cm.cm_tmap[cmo->cmo_tid].cmt_map;
}
- for (cmf = list_head(&cmi->cmi_fmap); cmf != NULL;
- cmf = list_next(&cmi->cmi_fmap, cmf)) {
+ for (cmf = list_head(&scmi->cmi_fmap); cmf != NULL;
+ cmf = list_next(&scmi->cmi_fmap, cmf)) {
int i;
VERIFY(cm.cm_tmap[cmf->cmf_rtid].cmt_map != 0);
@@ -728,28 +820,36 @@ ctf_merge(ctf_file_t **outp, ctf_merge_input_t *cmi)
}
}
+ /*
+ * Now that we've fixed things up, we need to give our function and
+ * object maps to the destination, such that it can continue to update
+ * them going forward.
+ */
+ list_move_tail(&dcmi->cmi_fmap, &scmi->cmi_fmap);
+ list_move_tail(&dcmi->cmi_omap, &scmi->cmi_omap);
+
cleanup:
+ if (ret == 0)
+ *outp = dcmi;
ctf_merge_types_fini(&cm);
ctf_diff_fini(cdp);
- return (ret);
+ if (ret != 0)
+ return (ctf_errno(out));
+ return (0);
}
static int
-ctf_uniquify_types(ctf_merge_t *cmh, ctf_file_t **outp)
+ctf_uniquify_types(ctf_merge_t *cmh, ctf_file_t *src, ctf_file_t **outp)
{
int err, ret;
ctf_file_t *out;
ctf_merge_types_t cm;
ctf_diff_t *cdp;
ctf_merge_input_t *cmi;
- ctf_file_t *src = cmh->cmh_output;
ctf_file_t *parent = cmh->cmh_unique;
*outp = NULL;
- if (cmh->cmh_ofd == -1)
- out = ctf_create(&err);
- else
- out = ctf_fdcreate(cmh->cmh_ofd, &err);
+ out = ctf_fdcreate(cmh->cmh_ofd, &err);
if (out == NULL)
return (ctf_set_errno(src, err));
@@ -773,6 +873,7 @@ ctf_uniquify_types(ctf_merge_t *cmh, ctf_file_t **outp)
cm.cm_out = parent;
cm.cm_src = src;
+ cm.cm_dedup = B_FALSE;
ret = ctf_merge_types_init(&cm);
if (ret != 0) {
ctf_close(out);
@@ -841,6 +942,9 @@ ctf_merge_fini_input(ctf_merge_input_t *cmi)
ctf_free(cmf, sizeof (ctf_merge_funcmap_t) +
sizeof (ctf_id_t) * cmf->cmf_argc);
+ if (cmi->cmi_created == B_TRUE && cmi->cmi_input != NULL)
+ ctf_close(cmi->cmi_input);
+
ctf_free(cmi, sizeof (ctf_merge_input_t));
}
@@ -850,9 +954,6 @@ ctf_merge_fini(ctf_merge_t *cmh)
size_t len;
ctf_merge_input_t *cmi;
- if (cmh->cmh_output != NULL)
- ctf_close(cmh->cmh_output);
-
if (cmh->cmh_label != NULL) {
len = strlen(cmh->cmh_label) + 1;
ctf_free(cmh->cmh_label, len);
@@ -891,22 +992,18 @@ ctf_merge_init(int fd, int *errp)
}
if (fd == -1) {
- out->cmh_output = ctf_create(errp);
out->cmh_msyms = B_FALSE;
} else {
- out->cmh_output = ctf_fdcreate(fd, errp);
out->cmh_msyms = B_TRUE;
}
- if (out->cmh_output == NULL) {
- ctf_free(out, sizeof (ctf_merge_t));
- return (NULL);
- }
-
list_create(&out->cmh_inputs, sizeof (ctf_merge_input_t),
offsetof(ctf_merge_input_t, cmi_node));
+ out->cmh_ninputs = 0;
+ out->cmh_nthreads = 1;
out->cmh_unique = NULL;
out->cmh_ofd = fd;
+ out->cmh_flags = 0;
out->cmh_label = NULL;
out->cmh_pname = NULL;
@@ -918,9 +1015,6 @@ ctf_merge_label(ctf_merge_t *cmh, const char *label)
{
char *dup;
- if (cmh->cmh_output == NULL)
- return (EINVAL);
-
if (label == NULL)
return (EINVAL);
@@ -983,14 +1077,17 @@ ctf_merge_add_objs(const char *name, ctf_id_t id, ulong_t idx, void *arg)
return (0);
}
+/*
+ * Whenever we create an entry to merge, we then go and add a second empty
+ * ctf_file_t which we use for the purposes of our merging. It's not the best,
+ * but it's the best that we've got at the moment.
+ */
int
ctf_merge_add(ctf_merge_t *cmh, ctf_file_t *input)
{
int ret;
ctf_merge_input_t *cmi;
-
- if (cmh->cmh_output == NULL)
- return (EINVAL);
+ ctf_file_t *empty;
if (input->ctf_flags & LCTF_CHILD)
return (ECTF_MCHILD);
@@ -999,6 +1096,7 @@ ctf_merge_add(ctf_merge_t *cmh, ctf_file_t *input)
if (cmi == NULL)
return (ENOMEM);
+ cmi->cmi_created = B_FALSE;
cmi->cmi_input = input;
list_create(&cmi->cmi_fmap, sizeof (ctf_merge_funcmap_t),
offsetof(ctf_merge_funcmap_t, cmf_node));
@@ -1020,6 +1118,30 @@ ctf_merge_add(ctf_merge_t *cmh, ctf_file_t *input)
}
list_insert_tail(&cmh->cmh_inputs, cmi);
+ cmh->cmh_ninputs++;
+
+ /* And now the empty one to merge into this */
+ cmi = ctf_alloc(sizeof (ctf_merge_input_t));
+ if (cmi == NULL)
+ return (ENOMEM);
+ list_create(&cmi->cmi_fmap, sizeof (ctf_merge_funcmap_t),
+ offsetof(ctf_merge_funcmap_t, cmf_node));
+ list_create(&cmi->cmi_omap, sizeof (ctf_merge_funcmap_t),
+ offsetof(ctf_merge_objmap_t, cmo_node));
+
+ empty = ctf_fdcreate(cmh->cmh_ofd, &ret);
+ if (empty == NULL)
+ return (ret);
+ cmi->cmi_input = empty;
+ cmi->cmi_created = B_TRUE;
+
+ if (ctf_setmodel(empty, ctf_getmodel(input)) == CTF_ERR) {
+ return (ctf_errno(empty));
+ }
+
+ list_insert_tail(&cmh->cmh_inputs, cmi);
+ cmh->cmh_ninputs++;
+ ctf_dprintf("added containers %p and %p\n", input, empty);
return (0);
}
@@ -1028,8 +1150,6 @@ ctf_merge_uniquify(ctf_merge_t *cmh, ctf_file_t *u, const char *pname)
{
char *dup;
- if (cmh->cmh_output == NULL)
- return (EINVAL);
if (u->ctf_flags & LCTF_CHILD)
return (ECTF_MCHILD);
if (pname == NULL)
@@ -1093,8 +1213,12 @@ found:
if (cmo != NULL) {
if (cmo->cmo_tid == 0)
continue;
- if ((err = ctf_add_object(fp, i, cmo->cmo_tid)) != 0)
+ if ((err = ctf_add_object(fp, i, cmo->cmo_tid)) != 0) {
+ ctf_dprintf("Failed to add symbol %s->%d: %s\n",
+ name, cmo->cmo_tid,
+ ctf_errmsg(ctf_errno(fp)));
return (err);
+ }
}
}
@@ -1161,12 +1285,14 @@ found:
}
int
-ctf_merge_merge(ctf_merge_t *cmh, ctf_file_t **out)
+ctf_merge_merge(ctf_merge_t *cmh, ctf_file_t **outp)
{
- int err;
+ int err, merr;
ctf_merge_input_t *cmi;
- boolean_t mset = B_FALSE;
ctf_id_t ltype;
+ mergeq_t *mqp;
+ ctf_merge_input_t *final;
+ ctf_file_t *out;
if (cmh->cmh_label != NULL && cmh->cmh_unique != NULL) {
const char *label = ctf_label_topmost(cmh->cmh_unique);
@@ -1176,56 +1302,248 @@ ctf_merge_merge(ctf_merge_t *cmh, ctf_file_t **out)
return (ECTF_LCONFLICT);
}
+ if (mergeq_init(&mqp, cmh->cmh_nthreads) == -1) {
+ return (errno);
+ }
+
/*
* We should consider doing a divide and conquer and parallel merge
* here. If we did, we'd want to use some number of threads to perform
* this operation.
*/
+ VERIFY(cmh->cmh_ninputs % 2 == 0);
for (cmi = list_head(&cmh->cmh_inputs); cmi != NULL;
cmi = list_next(&cmh->cmh_inputs, cmi)) {
- if (mset == B_FALSE) {
- if (ctf_setmodel(cmh->cmh_output,
- ctf_getmodel(cmi->cmi_input)) != 0) {
- return (ctf_errno(cmh->cmh_output));
- }
- mset = B_TRUE;
+ if (mergeq_add(mqp, cmi) == -1) {
+ err = errno;
+ mergeq_fini(mqp);
}
- err = ctf_merge(&cmh->cmh_output, cmi);
- if (err != 0)
- return (ctf_errno(cmh->cmh_output));
}
+ err = mergeq_merge(mqp, ctf_merge_types, NULL, (void **)&final, &merr);
+ mergeq_fini(mqp);
+
+ if (err == MERGEQ_ERROR) {
+ return (errno);
+ } else if (err == MERGEQ_UERROR) {
+ return (merr);
+ }
+
+ /*
+ * Disassociate the generated ctf_file_t from the original input. That
+ * way when the input gets cleaned up, we don't accidentally kill the
+ * final reference to the ctf_file_t. If it gets uniquified then we'll
+ * kill it.
+ */
+ VERIFY(final->cmi_input != NULL);
+ out = final->cmi_input;
+ final->cmi_input = NULL;
+
+ ctf_dprintf("preparing to uniquify against: %p\n", cmh->cmh_unique);
if (cmh->cmh_unique != NULL) {
- err = ctf_uniquify_types(cmh, out);
- if (err != 0)
- return (ctf_errno(cmh->cmh_output));
- ctf_close(cmh->cmh_output);
- } else {
- *out = cmh->cmh_output;
+ ctf_file_t *u;
+ err = ctf_uniquify_types(cmh, out, &u);
+ if (err != 0) {
+ err = ctf_errno(out);
+ ctf_close(out);
+ return (err);
+ }
+ ctf_close(out);
+ out = u;
}
- ltype = (*out)->ctf_typemax;
- if (((*out)->ctf_flags & LCTF_CHILD) && ltype != 0)
+ ltype = out->ctf_typemax;
+ if ((out->ctf_flags & LCTF_CHILD) && ltype != 0)
ltype += 0x8000;
- if (ctf_add_label(*out, cmh->cmh_label, ltype, 0) != 0) {
- return (ctf_errno(*out));
+ ctf_dprintf("trying to add the label\n");
+ if (cmh->cmh_label != NULL &&
+ ctf_add_label(out, cmh->cmh_label, ltype, 0) != 0) {
+ ctf_close(out);
+ return (ctf_errno(out));
}
+ ctf_dprintf("merging symbols and the like\n");
if (cmh->cmh_msyms == B_TRUE) {
- err = ctf_merge_symbols(cmh, *out);
- if (err != 0)
- return (ctf_errno(*out));
+ err = ctf_merge_symbols(cmh, out);
+ if (err != 0) {
+ ctf_close(out);
+ return (ctf_errno(out));
+ }
+
+ err = ctf_merge_functions(cmh, out);
+ if (err != 0) {
+ ctf_close(out);
+ return (ctf_errno(out));
+ }
+ }
+
+ err = ctf_update(out);
+ if (err != 0) {
+ ctf_close(out);
+ return (ctf_errno(out));
+ }
+
+ *outp = out;
+ return (0);
+}
+
+/*
+ * When we get told that something is unique, eg. same is B_FALSE, then that
+ * tells us that we need to add it to the output. If same is B_TRUE, then we'll
+ * want to record it in the mapping table so that we know how to redirect types
+ * to the extant ones.
+ */
+static void
+ctf_dedup_cb(ctf_file_t *ifp, ctf_id_t iid, boolean_t same, ctf_file_t *ofp,
+ ctf_id_t oid, void *arg)
+{
+ ctf_merge_types_t *cmp = arg;
+ ctf_merge_tinfo_t *cmt = cmp->cm_tmap;
- err = ctf_merge_functions(cmh, *out);
- if (err != 0)
- return (ctf_errno(*out));
+ if (same == B_TRUE) {
+ /*
+ * The output id here may itself map to something else.
+ * Therefore, we need to basically walk a chain and see what it
+ * points to until it itself points to a base type, eg. -1.
+ * Otherwise we'll dedup to something which no longer exists.
+ */
+ while (cmt[oid].cmt_missing == B_FALSE)
+ oid = cmt[oid].cmt_map;
+ cmt[iid].cmt_map = oid;
+ ctf_dprintf("%d->%d \n", iid, oid);
+ } else {
+ VERIFY(cmt[iid].cmt_map == 0);
+ cmt[iid].cmt_missing = B_TRUE;
+ ctf_dprintf("%d is missing\n", iid);
}
+}
- err = ctf_update(*out);
- if (err != 0)
- return (ctf_errno(*out));
+/*
+ * Dedup a CTF container.
+ *
+ * DWARF and other encoding formats that we use to create CTF data may create
+ * multiple copies of a given type. However, after doing a conversion, and
+ * before doing a merge, we'd prefer, if possible, to have every input container
+ * to be unique.
+ *
+ * Doing a deduplication is like a normal merge. However, when we diff the types
+ * in the container, rather than doing a normal diff, we instead want to diff
+ * against any already processed types. eg, for a given type i in a container,
+ * we want to diff it from 0 to i - 1.
+ */
+int
+ctf_merge_dedup(ctf_merge_t *cmp, ctf_file_t **outp)
+{
+ int ret;
+ ctf_diff_t *cdp = NULL;
+ ctf_merge_input_t *cmi, *cmc;
+ ctf_file_t *ifp, *ofp;
+ ctf_merge_objmap_t *cmo;
+ ctf_merge_funcmap_t *cmf;
+ ctf_merge_types_t cm;
- cmh->cmh_output = NULL;
+ if (cmp == NULL || outp == NULL)
+ return (EINVAL);
+
+ ctf_dprintf("encountered %d inputs\n", cmp->cmh_ninputs);
+ if (cmp->cmh_ninputs != 2)
+ return (EINVAL);
+
+ ctf_dprintf("passed argument sanity check\n");
+
+ cmi = list_head(&cmp->cmh_inputs);
+ VERIFY(cmi != NULL);
+ cmc = list_next(&cmp->cmh_inputs, cmi);
+ VERIFY(cmc != NULL);
+ ifp = cmi->cmi_input;
+ ofp = cmc->cmi_input;
+ VERIFY(ifp != NULL);
+ VERIFY(ofp != NULL);
+ cm.cm_src = ifp;
+ cm.cm_out = ofp;
+ cm.cm_dedup = B_TRUE;
+
+ if ((ret = ctf_merge_types_init(&cm)) != 0) {
+ return (ret);
+ }
+ if ((ret = ctf_diff_init(ifp, ifp, &cdp)) != 0)
+ goto err;
+
+ ctf_dprintf("Successfully initialized dedup\n");
+ if ((ret = ctf_diff_self(cdp, ctf_dedup_cb, &cm)) != 0)
+ goto err;
+
+ ctf_dprintf("Successfully diffed types\n");
+ ret = ctf_merge_common(&cm);
+ ctf_dprintf("deduping types result: %d\n", ret);
+ if (ret == 0)
+ ret = ctf_update(cm.cm_out);
+ if (ret != 0)
+ goto err;
+
+ ctf_dprintf("Successfully deduped types\n");
+ ctf_phase_dump(cm.cm_out, "dedup-pre-syms");
+
+
+ /*
+ * Now we need to fix up the object and function maps.
+ */
+ for (cmo = list_head(&cmi->cmi_omap); cmo != NULL;
+ cmo = list_next(&cmi->cmi_omap, cmo)) {
+ if (cmo->cmo_tid == 0)
+ continue;
+ ctf_dprintf("mapped %s %d->%d\n", cmo->cmo_name,
+ cmo->cmo_tid, cm.cm_tmap[cmo->cmo_tid].cmt_map);
+ cmo->cmo_tid = cm.cm_tmap[cmo->cmo_tid].cmt_map;
+ }
+
+ for (cmf = list_head(&cmi->cmi_fmap); cmf != NULL;
+ cmf = list_next(&cmi->cmi_fmap, cmf)) {
+ int i;
+
+ VERIFY(cm.cm_tmap[cmf->cmf_rtid].cmt_map != 0);
+ cmf->cmf_rtid = cm.cm_tmap[cmf->cmf_rtid].cmt_map;
+ for (i = 0; i < cmf->cmf_argc; i++) {
+ VERIFY(cm.cm_tmap[cmf->cmf_args[i]].cmt_map != 0);
+ cmf->cmf_args[i] = cm.cm_tmap[cmf->cmf_args[i]].cmt_map;
+ }
+ }
+
+ if (cmp->cmh_msyms == B_TRUE) {
+ ret = ctf_merge_symbols(cmp, cm.cm_out);
+ if (ret != 0) {
+ ret = ctf_errno(cm.cm_out);
+ ctf_dprintf("failed to dedup symbols: %s\n",
+ ctf_errmsg(ret));
+ goto err;
+ }
+
+ ret = ctf_merge_functions(cmp, cm.cm_out);
+ if (ret != 0) {
+ ret = ctf_errno(cm.cm_out);
+ ctf_dprintf("failed to dedup functions: %s\n",
+ ctf_errmsg(ret));
+ goto err;
+ }
+ }
+
+ ret = ctf_update(cm.cm_out);
+ if (ret == 0) {
+ cmc->cmi_input = NULL;
+ *outp = cm.cm_out;
+ }
+err:
+ ctf_merge_types_fini(&cm);
+ ctf_diff_fini(cdp);
+ return (ret);
+}
+
+int
+ctf_merge_set_nthreads(ctf_merge_t *cmp, const uint_t nthrs)
+{
+ if (nthrs == 0)
+ return (EINVAL);
+ cmp->cmh_nthreads = nthrs;
return (0);
}
diff --git a/usr/src/lib/libctf/common/ctf_subr.c b/usr/src/lib/libctf/common/ctf_subr.c
index 467b6a8181..26f7e8c4db 100644
--- a/usr/src/lib/libctf/common/ctf_subr.c
+++ b/usr/src/lib/libctf/common/ctf_subr.c
@@ -24,8 +24,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <ctf_impl.h>
#include <libctf.h>
#include <sys/mman.h>
@@ -56,6 +54,18 @@ ctf_alloc(size_t size)
return (malloc(size));
}
+void *
+mergeq_alloc(size_t size)
+{
+ return (malloc(size));
+}
+
+void *
+workq_alloc(size_t size)
+{
+ return (malloc(size));
+}
+
/*ARGSUSED*/
void
ctf_free(void *buf, size_t size)
@@ -63,6 +73,20 @@ ctf_free(void *buf, size_t size)
free(buf);
}
+/*ARGSUSED*/
+void
+mergeq_free(void *buf, size_t size)
+{
+ free(buf);
+}
+
+/*ARGSUSED*/
+void
+workq_free(void *buf, size_t size)
+{
+ free(buf);
+}
+
const char *
ctf_strerror(int err)
{
diff --git a/usr/src/lib/libctf/common/libctf.h b/usr/src/lib/libctf/common/libctf.h
index 13c7e07e99..0951ae0606 100644
--- a/usr/src/lib/libctf/common/libctf.h
+++ b/usr/src/lib/libctf/common/libctf.h
@@ -55,8 +55,7 @@ extern "C" {
extern int _libctf_debug;
typedef enum ctf_diff_flag {
- CTF_DIFF_F_IGNORE_INTNAMES = 0x01,
- CTF_DIFF_F_MASK = 0x01
+ CTF_DIFF_F_IGNORE_INTNAMES = 0x01
} ctf_diff_flag_t;
typedef struct ctf_diff ctf_diff_t;
@@ -75,12 +74,18 @@ extern int ctf_diff_functions(ctf_diff_t *, ctf_diff_func_f, void *);
extern int ctf_diff_objects(ctf_diff_t *, ctf_diff_obj_f, void *);
extern void ctf_diff_fini(ctf_diff_t *);
+#define CTF_CONVERT_F_IGNNONC 0x01
+extern ctf_file_t *ctf_fdconvert(int, const char *, uint_t, uint_t, int *,
+ char *, size_t);
+
typedef struct ctf_merge_handle ctf_merge_t;
extern ctf_merge_t *ctf_merge_init(int, int *);
extern int ctf_merge_add(ctf_merge_t *, ctf_file_t *);
+extern int ctf_merge_set_nthreads(ctf_merge_t *, const uint_t);
extern int ctf_merge_label(ctf_merge_t *, const char *);
extern int ctf_merge_uniquify(ctf_merge_t *, ctf_file_t *, const char *);
extern int ctf_merge_merge(ctf_merge_t *, ctf_file_t **);
+extern int ctf_merge_dedup(ctf_merge_t *, ctf_file_t **);
extern void ctf_merge_fini(ctf_merge_t *);
#define CTF_ELFWRITE_F_COMPRESS 0x1
diff --git a/usr/src/lib/libctf/common/libctf_impl.h b/usr/src/lib/libctf/common/libctf_impl.h
new file mode 100644
index 0000000000..11193e97d0
--- /dev/null
+++ b/usr/src/lib/libctf/common/libctf_impl.h
@@ -0,0 +1,59 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+#ifndef _LIBCTF_IMPL_H
+#define _LIBCTF_IMPL_H
+
+/*
+ * Portions of libctf implementations that are only suitable for CTF's userland
+ * library, eg. converting and merging related routines.
+ */
+
+#include <libelf.h>
+#include <libctf.h>
+#include <ctf_impl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum ctf_conv_status {
+ CTF_CONV_SUCCESS = 0,
+ CTF_CONV_ERROR = 1,
+ CTF_CONV_NOTSUP = 2
+} ctf_conv_status_t;
+
+typedef ctf_conv_status_t (*ctf_convert_f)(int, Elf *, uint_t, int *,
+ ctf_file_t **, char *, size_t);
+extern ctf_conv_status_t ctf_dwarf_convert(int, Elf *, uint_t, int *,
+ ctf_file_t **, char *, size_t);
+
+/*
+ * zlib compression routines
+ */
+extern int ctf_compress(ctf_file_t *fp, void **, size_t *, size_t *);
+
+extern int ctf_diff_self(ctf_diff_t *, ctf_diff_type_f, void *);
+
+/*
+ * Internal debugging aids
+ */
+extern void ctf_phase_dump(ctf_file_t *, const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBCTF_IMPL_H */
diff --git a/usr/src/lib/libctf/common/mapfile-vers b/usr/src/lib/libctf/common/mapfile-vers
index 95ddfd5d6c..3c00c47a58 100644
--- a/usr/src/lib/libctf/common/mapfile-vers
+++ b/usr/src/lib/libctf/common/mapfile-vers
@@ -81,25 +81,31 @@ SYMBOL_VERSION SUNWprivate_1.2 {
ctf_elffdwrite;
ctf_elfwrite;
ctf_enum_value;
+ ctf_fdconvert;
ctf_flags;
ctf_func_args_by_id;
ctf_func_info_by_id;
ctf_function_iter;
+ ctf_kind_name;
ctf_label_info;
ctf_label_iter;
ctf_label_topmost;
ctf_member_info;
ctf_merge_add;
+ ctf_merge_dedup;
ctf_merge_fini;
ctf_merge_init;
ctf_merge_label;
ctf_merge_merge;
+ ctf_merge_set_nthreads;
ctf_merge_uniquify;
ctf_object_iter;
ctf_parent_file;
ctf_parent_label;
ctf_parent_name;
ctf_set_array;
+ ctf_set_root;
+ ctf_set_size;
ctf_string_iter;
ctf_symbol_name;
ctf_type_align;
diff --git a/usr/src/lib/libdwarf/Makefile b/usr/src/lib/libdwarf/Makefile
new file mode 100644
index 0000000000..6b7ff6244b
--- /dev/null
+++ b/usr/src/lib/libdwarf/Makefile
@@ -0,0 +1,40 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include ../Makefile.lib
+
+SUBDIRS = $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET = all
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+lint := TARGET = lint
+
+.KEEP_STATE:
+
+all clean clobber lint install_h: $(SUBDIRS)
+
+install: install_h $(SUBDIRS)
+
+check: $(CHECKHDRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../Makefile.targ
diff --git a/usr/src/lib/libdwarf/Makefile.com b/usr/src/lib/libdwarf/Makefile.com
new file mode 100644
index 0000000000..c737366af9
--- /dev/null
+++ b/usr/src/lib/libdwarf/Makefile.com
@@ -0,0 +1,92 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+LIBRARY= libdwarf.a
+VERS= .1
+
+OBJECTS=dwarf_abbrev.o \
+ dwarf_addr_finder.o \
+ dwarf_alloc.o \
+ dwarf_arange.o \
+ dwarf_die_deliv.o \
+ dwarf_elf_access.o \
+ dwarf_error.o \
+ dwarf_form.o \
+ dwarf_frame.o \
+ dwarf_frame2.o \
+ dwarf_frame3.o \
+ dwarf_funcs.o \
+ dwarf_global.o \
+ dwarf_harmless.o \
+ dwarf_init_finish.o \
+ dwarf_leb.o \
+ dwarf_line.o \
+ dwarf_line2.o \
+ dwarf_loc.o \
+ dwarf_macro.o \
+ dwarf_names.o \
+ dwarf_original_elf_init.o \
+ dwarf_print_lines.o \
+ dwarf_pubtypes.o \
+ dwarf_query.o \
+ dwarf_ranges.o \
+ dwarf_sort_line.o \
+ dwarf_string.o \
+ dwarf_stubs.o \
+ dwarf_types.o \
+ dwarf_util.o \
+ dwarf_vars.o \
+ dwarf_weaks.o \
+ malloc_check.o \
+ pro_alloc.o \
+ pro_arange.o \
+ pro_die.o \
+ pro_encode_nm.o \
+ pro_error.o \
+ pro_expr.o \
+ pro_finish.o \
+ pro_forms.o \
+ pro_frame.o \
+ pro_funcs.o \
+ pro_init.o \
+ pro_line.o \
+ pro_macinfo.o \
+ pro_pubnames.o \
+ pro_reloc.o \
+ pro_reloc_stream.o \
+ pro_reloc_symbolic.o \
+ pro_section.o \
+ pro_types.o \
+ pro_vars.o \
+ pro_weaks.o
+
+include ../../Makefile.lib
+include ../../Makefile.rootfs
+
+LIBS = $(DYNLIB)
+LDLIBS += -lelf -lc
+
+SRCDIR = ../common
+CPPFLAGS += -I$(SRCDIR) -DELF_TARGET_ALL=1
+CERRWARN += -_gcc=-Wno-unused
+CERRWARN += -_gcc=-Wno-implicit-function-declaration
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+include ../../Makefile.targ
diff --git a/usr/src/lib/libdwarf/THIRDPARTYLICENSE b/usr/src/lib/libdwarf/THIRDPARTYLICENSE
new file mode 100644
index 0000000000..b9320c2d56
--- /dev/null
+++ b/usr/src/lib/libdwarf/THIRDPARTYLICENSE
@@ -0,0 +1,30 @@
+ Copyright (C) 2000, 2001 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., 59 Temple Place - Suite 330, Boston MA 02111-1307,
+ USA.
+
+ Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pky,
+ Mountain View, CA 94043, or:
+
+ http://www.sgi.com
+
+ For further information regarding this notice, see:
+
+ http://oss.sgi.com/projects/GenInfo/NoticeExplan
diff --git a/usr/src/lib/libdwarf/THIRDPARTYLICENSE.descrip b/usr/src/lib/libdwarf/THIRDPARTYLICENSE.descrip
new file mode 100644
index 0000000000..73abaac973
--- /dev/null
+++ b/usr/src/lib/libdwarf/THIRDPARTYLICENSE.descrip
@@ -0,0 +1 @@
+LIBDWARF LIBRARY THAT SUPPORTS THE DWARF OPEN SOURCE STANDARD
diff --git a/usr/src/lib/libdwarf/amd64/Makefile b/usr/src/lib/libdwarf/amd64/Makefile
new file mode 100644
index 0000000000..15a899f96f
--- /dev/null
+++ b/usr/src/lib/libdwarf/amd64/Makefile
@@ -0,0 +1,19 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
diff --git a/usr/src/lib/libdwarf/common/cmplrs/dwarf_addr_finder.h b/usr/src/lib/libdwarf/common/cmplrs/dwarf_addr_finder.h
new file mode 100644
index 0000000000..0eda6d1c44
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/cmplrs/dwarf_addr_finder.h
@@ -0,0 +1,55 @@
+/*
+ dwarf_addr_finder.h
+ $Source: /plroot/cmplrs.src/v7.4.5m/.RCS/PL/include/cmplrs/RCS/dwarf_addr_finder.h,v $
+ $Date: 2002/06/11 17:49:06 $
+
+ Defines user interface.
+
+*/
+
+/* return codes for functions
+*/
+#define DW_DLV_NO_ENTRY -1
+#define DW_DLV_OK 0
+#define DW_DLV_ERROR 1
+
+
+/* the following are the 'section' number passed to the called-back
+ function.
+ The called-back application must translate this to the
+ appropriate elf section number/pointer.
+
+ Putting this burden on the application avoids having to store
+ the numbers in the Dwarf_Debug structure (thereby saving space
+ for most consumers).
+*/
+#define DW_SECTION_INFO 0
+#define DW_SECTION_FRAME 1
+#define DW_SECTION_ARANGES 2
+#define DW_SECTION_LINE 3
+#define DW_SECTION_LOC 4 /* .debug_loc */
+
+/* section is one of the above codes: it specifies a section.
+ secoff is the offset in the dwarf section.
+ existingAddr is the value at the specified offset (so the
+ called back routine can sanity check the proceedings).
+ It's up to the caller to know the size of an address (4 or 8)
+ and update the right number of bytes.
+*/
+typedef int (*Dwarf_addr_callback_func) (int /*section*/,
+ Dwarf_Off /*secoff*/, Dwarf_Addr /*existingAddr*/);
+
+/* call this to do the work: it calls back thru cb_func
+ once per each address to be modified.
+ Once this returns you are done.
+ Returns DW_DLV_OK if finished ok.
+ Returns DW_DLV_ERROR if there was some kind of error, in which
+ the dwarf error number was passed back thu the dwerr ptr.
+ Returns DW_DLV_NO_ENTRY if there are no relevant dwarf sections,
+ so there were no addresses to be modified (and none
+ called back).
+*/
+int _dwarf_addr_finder(dwarf_elf_handle elf_file_ptr,
+ Dwarf_addr_callback_func cb_func,
+ int *dwerr);
+
diff --git a/usr/src/lib/libdwarf/common/config.h b/usr/src/lib/libdwarf/common/config.h
new file mode 100644
index 0000000000..42b286cfda
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/config.h
@@ -0,0 +1,143 @@
+/* config.h. Generated from config.h.in by configure. */
+/* config.h.in. Generated from configure.in by autoheader. */
+
+/* Define if building universal (internal helper macro) */
+/* #undef AC_APPLE_UNIVERSAL_BUILD */
+
+/* Define to 1 if you have the <alloca.h> header file. */
+#define HAVE_ALLOCA_H 1
+
+/* Define 1 if want to allow producer to build with 32/64bit section offsets
+ per dwarf3 */
+#define HAVE_DWARF2_99_EXTENSION 1
+
+/* Define to 1 if the elf64_getehdr function is in libelf.a. */
+#define HAVE_ELF64_GETEHDR 1
+
+/* Define to 1 if the elf64_getshdr function is in libelf.a. */
+#define HAVE_ELF64_GETSHDR 1
+
+/* Define 1 if Elf64_Rela defined. */
+#define HAVE_ELF64_RELA 1
+
+/* Define 1 if Elf64_Sym defined. */
+#define HAVE_ELF64_SYM 1
+
+/* Define to 1 if you have the <elfaccess.h> header file. */
+/* #undef HAVE_ELFACCESS_H */
+
+/* Define to 1 if you have the <elf.h> header file. */
+#define HAVE_ELF_H 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <libelf.h> header file. */
+#define HAVE_LIBELF_H 1
+
+/* Define to 1 if you have the <libelf/libelf.h> header file. */
+/* #undef HAVE_LIBELF_LIBELF_H */
+
+/* Define 1 if off64 is defined via libelf with GNU_SOURCE. */
+#define HAVE_LIBELF_OFF64_OK 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define 1 if need nonstandard printf format for 64bit */
+/* #undef HAVE_NONSTANDARD_PRINTF_64_FORMAT */
+
+/* Define 1 to default to old DW_FRAME_CFA_COL */
+/* #undef HAVE_OLD_FRAME_CFA_COL */
+
+/* Define 1 if plain libelf builds. */
+#define HAVE_RAW_LIBELF_OK 1
+
+/* Define 1 if R_IA_64_DIR32LSB is defined (might be enum value). */
+/* #undef HAVE_R_IA_64_DIR32LSB */
+
+/* Define 1 if want producer to build with IRIX offset sizes */
+/* #undef HAVE_SGI_IRIX_OFFSETS */
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define 1 if want producer to build with only 32bit section offsets */
+/* #undef HAVE_STRICT_DWARF2_32BIT_OFFSET */
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/ia64/elf.h> header file. */
+/* #undef HAVE_SYS_IA64_ELF_H */
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define 1 if want to allow Windows full path detection */
+/* #undef HAVE_WINDOWS_PATH */
+
+/* See if __uint32_t is predefined in the compiler. */
+/* #undef HAVE___UINT32_T */
+
+/* Define 1 if __uint32_t is in sgidefs.h. */
+/* #undef HAVE___UINT32_T_IN_SGIDEFS_H */
+
+/* Define 1 if sys/types.h defines __uint32_t. */
+/* #undef HAVE___UINT32_T_IN_SYS_TYPES_H */
+
+/* See if __uint64_t is predefined in the compiler. */
+/* #undef HAVE___UINT64_T */
+
+/* Define 1 if is in sgidefs.h. */
+/* #undef HAVE___UINT64_T_IN_SGIDEFS_H */
+
+/* Define 1 if sys/types.h defines __uint64_t. */
+/* #undef HAVE___UINT64_T_IN_SYS_TYPES_H */
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME ""
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION ""
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+ significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+# define WORDS_BIGENDIAN 1
+# endif
+#else
+# if defined(__sparc)
+# define WORDS_BIGENDIAN 1
+# else
+# undef WORDS_BIGENDIAN
+# endif
+#endif
diff --git a/usr/src/lib/libdwarf/common/dwarf.h b/usr/src/lib/libdwarf/common/dwarf.h
new file mode 100644
index 0000000000..b064c4d86b
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf.h
@@ -0,0 +1,1078 @@
+/*
+ Copyright (C) 2000,2001,2003,2004,2005,2006 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright 2002-2010 Sun Microsystems, Inc. All rights reserved.
+ Portions Copyright 2007-2010 David Anderson. 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
+
+*/
+
+
+#ifndef __DWARF_H
+#define __DWARF_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ dwarf.h DWARF debugging information values
+ $Revision: 1.41 $ $Date: 2006/04/17 00:09:56 $
+
+ The comment "DWARF3" appears where there are
+ new entries from DWARF3 as of 2004, "DWARF3f"
+ where there are new entries as of the November 2005
+ public review document and other comments apply
+ where extension entries appear.
+
+ Extensions part of DWARF4 are marked DWARF4.
+
+ A few extension names have omitted the 'vendor id'
+ (See chapter 7, "Vendor Extensibility"). Please
+ always use a 'vendor id' string in extension names.
+
+ Vendors should use a vendor string in names and
+ whereever possible avoid duplicating values used by
+ other vendor extensions
+
+*/
+
+
+#define DW_TAG_array_type 0x01
+#define DW_TAG_class_type 0x02
+#define DW_TAG_entry_point 0x03
+#define DW_TAG_enumeration_type 0x04
+#define DW_TAG_formal_parameter 0x05
+#define DW_TAG_imported_declaration 0x08
+#define DW_TAG_label 0x0a
+#define DW_TAG_lexical_block 0x0b
+#define DW_TAG_member 0x0d
+#define DW_TAG_pointer_type 0x0f
+#define DW_TAG_reference_type 0x10
+#define DW_TAG_compile_unit 0x11
+#define DW_TAG_string_type 0x12
+#define DW_TAG_structure_type 0x13
+#define DW_TAG_subroutine_type 0x15
+#define DW_TAG_typedef 0x16
+#define DW_TAG_union_type 0x17
+#define DW_TAG_unspecified_parameters 0x18
+#define DW_TAG_variant 0x19
+#define DW_TAG_common_block 0x1a
+#define DW_TAG_common_inclusion 0x1b
+#define DW_TAG_inheritance 0x1c
+#define DW_TAG_inlined_subroutine 0x1d
+#define DW_TAG_module 0x1e
+#define DW_TAG_ptr_to_member_type 0x1f
+#define DW_TAG_set_type 0x20
+#define DW_TAG_subrange_type 0x21
+#define DW_TAG_with_stmt 0x22
+#define DW_TAG_access_declaration 0x23
+#define DW_TAG_base_type 0x24
+#define DW_TAG_catch_block 0x25
+#define DW_TAG_const_type 0x26
+#define DW_TAG_constant 0x27
+#define DW_TAG_enumerator 0x28
+#define DW_TAG_file_type 0x29
+#define DW_TAG_friend 0x2a
+#define DW_TAG_namelist 0x2b
+ /* Early releases of this header had the following
+ misspelled with a trailing 's' */
+#define DW_TAG_namelist_item 0x2c /* DWARF3/2 spelling */
+#define DW_TAG_namelist_items 0x2c /* SGI misspelling/typo */
+#define DW_TAG_packed_type 0x2d
+#define DW_TAG_subprogram 0x2e
+ /* The DWARF2 document had two spellings of the following
+ two TAGs, DWARF3 specifies the longer spelling. */
+#define DW_TAG_template_type_parameter 0x2f /* DWARF3/2 spelling*/
+#define DW_TAG_template_type_param 0x2f /* DWARF2 spelling*/
+#define DW_TAG_template_value_parameter 0x30 /* DWARF3/2 spelling*/
+#define DW_TAG_template_value_param 0x30 /* DWARF2 spelling*/
+#define DW_TAG_thrown_type 0x31
+#define DW_TAG_try_block 0x32
+#define DW_TAG_variant_part 0x33
+#define DW_TAG_variable 0x34
+#define DW_TAG_volatile_type 0x35
+#define DW_TAG_dwarf_procedure 0x36 /* DWARF3 */
+#define DW_TAG_restrict_type 0x37 /* DWARF3 */
+#define DW_TAG_interface_type 0x38 /* DWARF3 */
+#define DW_TAG_namespace 0x39 /* DWARF3 */
+#define DW_TAG_imported_module 0x3a /* DWARF3 */
+#define DW_TAG_unspecified_type 0x3b /* DWARF3 */
+#define DW_TAG_partial_unit 0x3c /* DWARF3 */
+#define DW_TAG_imported_unit 0x3d /* DWARF3 */
+ /* Do not use DW_TAG_mutable_type */
+#define DW_TAG_mutable_type 0x3e /* Withdrawn from DWARF3 by DWARF3f. */
+#define DW_TAG_condition 0x3f /* DWARF3f */
+#define DW_TAG_shared_type 0x40 /* DWARF3f */
+#define DW_TAG_type_unit 0x41 /* DWARF4 */
+#define DW_TAG_rvalue_reference_type 0x42 /* DWARF4 */
+#define DW_TAG_template_alias 0x43 /* DWARF4 */
+#define DW_TAG_lo_user 0x4080
+
+#define DW_TAG_MIPS_loop 0x4081
+
+/* HP extensions: ftp://ftp.hp.com/pub/lang/tools/WDB/wdb-4.0.tar.gz */
+#define DW_TAG_HP_array_descriptor 0x4090 /* HP */
+
+/* GNU extensions. The first 3 missing the GNU_. */
+#define DW_TAG_format_label 0x4101 /* GNU. Fortran. */
+#define DW_TAG_function_template 0x4102 /* GNU. For C++ */
+#define DW_TAG_class_template 0x4103 /* GNU. For C++ */
+#define DW_TAG_GNU_BINCL 0x4104 /* GNU */
+#define DW_TAG_GNU_EINCL 0x4105 /* GNU */
+
+
+/* GNU extension. http://gcc.gnu.org/wiki/TemplateParmsDwarf */
+#define DW_TAG_GNU_template_template_parameter 0x4106 /* GNU */
+#define DW_TAG_GNU_template_template_param 0x4106 /* GNU */
+#define DW_TAG_GNU_template_parameter_pack 0x4107 /* GNU */
+#define DW_TAG_GNU_formal_parameter_pack 0x4108 /* GNU */
+
+/* ALTIUM extensions */
+ /* DSP-C/Starcore __circ qualifier */
+#define DW_TAG_ALTIUM_circ_type 0x5101 /* ALTIUM */
+ /* Starcore __mwa_circ qualifier */
+#define DW_TAG_ALTIUM_mwa_circ_type 0x5102 /* ALTIUM */
+ /* Starcore __rev_carry qualifier */
+#define DW_TAG_ALTIUM_rev_carry_type 0x5103 /* ALTIUM */
+ /* M16 __rom qualifier */
+#define DW_TAG_ALTIUM_rom 0x5111 /* ALTIUM */
+
+/* The following 3 are extensions to support UPC */
+#define DW_TAG_upc_shared_type 0x8765 /* UPC */
+#define DW_TAG_upc_strict_type 0x8766 /* UPC */
+#define DW_TAG_upc_relaxed_type 0x8767 /* UPC */
+
+/* PGI (STMicroelectronics) extensions. */
+#define DW_TAG_PGI_kanji_type 0xa000 /* PGI */
+#define DW_TAG_PGI_interface_block 0xa020 /* PGI */
+/* The following are SUN extensions */
+#define DW_TAG_SUN_function_template 0x4201 /* SUN */
+#define DW_TAG_SUN_class_template 0x4202 /* SUN */
+#define DW_TAG_SUN_struct_template 0x4203 /* SUN */
+#define DW_TAG_SUN_union_template 0x4204 /* SUN */
+#define DW_TAG_SUN_indirect_inheritance 0x4205 /* SUN */
+#define DW_TAG_SUN_codeflags 0x4206 /* SUN */
+#define DW_TAG_SUN_memop_info 0x4207 /* SUN */
+#define DW_TAG_SUN_omp_child_func 0x4208 /* SUN */
+#define DW_TAG_SUN_rtti_descriptor 0x4209 /* SUN */
+#define DW_TAG_SUN_dtor_info 0x420a /* SUN */
+#define DW_TAG_SUN_dtor 0x420b /* SUN */
+#define DW_TAG_SUN_f90_interface 0x420c /* SUN */
+#define DW_TAG_SUN_fortran_vax_structure 0x420d /* SUN */
+#define DW_TAG_SUN_hi 0x42ff /* SUN */
+
+
+#define DW_TAG_hi_user 0xffff
+
+#define DW_children_no 0
+#define DW_children_yes 1
+
+
+
+#define DW_FORM_addr 0x01
+#define DW_FORM_block2 0x03
+#define DW_FORM_block4 0x04
+#define DW_FORM_data2 0x05
+#define DW_FORM_data4 0x06
+#define DW_FORM_data8 0x07
+#define DW_FORM_string 0x08
+#define DW_FORM_block 0x09
+#define DW_FORM_block1 0x0a
+#define DW_FORM_data1 0x0b
+#define DW_FORM_flag 0x0c
+#define DW_FORM_sdata 0x0d
+#define DW_FORM_strp 0x0e
+#define DW_FORM_udata 0x0f
+#define DW_FORM_ref_addr 0x10
+#define DW_FORM_ref1 0x11
+#define DW_FORM_ref2 0x12
+#define DW_FORM_ref4 0x13
+#define DW_FORM_ref8 0x14
+#define DW_FORM_ref_udata 0x15
+#define DW_FORM_indirect 0x16
+#define DW_FORM_sec_offset 0x17 /* DWARF4 */
+#define DW_FORM_exprloc 0x18 /* DWARF4 */
+#define DW_FORM_flag_present 0x19 /* DWARF4 */
+/* 0x1a thru 0x1f were left unused accidentally. Reserved for future use. */
+#define DW_FORM_ref_sig8 0x20 /* DWARF4 */
+
+#define DW_AT_sibling 0x01
+#define DW_AT_location 0x02
+#define DW_AT_name 0x03
+#define DW_AT_ordering 0x09
+#define DW_AT_subscr_data 0x0a
+#define DW_AT_byte_size 0x0b
+#define DW_AT_bit_offset 0x0c
+#define DW_AT_bit_size 0x0d
+#define DW_AT_element_list 0x0f
+#define DW_AT_stmt_list 0x10
+#define DW_AT_low_pc 0x11
+#define DW_AT_high_pc 0x12
+#define DW_AT_language 0x13
+#define DW_AT_member 0x14
+#define DW_AT_discr 0x15
+#define DW_AT_discr_value 0x16
+#define DW_AT_visibility 0x17
+#define DW_AT_import 0x18
+#define DW_AT_string_length 0x19
+#define DW_AT_common_reference 0x1a
+#define DW_AT_comp_dir 0x1b
+#define DW_AT_const_value 0x1c
+#define DW_AT_containing_type 0x1d
+#define DW_AT_default_value 0x1e
+#define DW_AT_inline 0x20
+#define DW_AT_is_optional 0x21
+#define DW_AT_lower_bound 0x22
+#define DW_AT_producer 0x25
+#define DW_AT_prototyped 0x27
+#define DW_AT_return_addr 0x2a
+#define DW_AT_start_scope 0x2c
+#define DW_AT_bit_stride 0x2e /* DWARF3 name */
+#define DW_AT_stride_size 0x2e /* DWARF2 name */
+#define DW_AT_upper_bound 0x2f
+#define DW_AT_abstract_origin 0x31
+#define DW_AT_accessibility 0x32
+#define DW_AT_address_class 0x33
+#define DW_AT_artificial 0x34
+#define DW_AT_base_types 0x35
+#define DW_AT_calling_convention 0x36
+#define DW_AT_count 0x37
+#define DW_AT_data_member_location 0x38
+#define DW_AT_decl_column 0x39
+#define DW_AT_decl_file 0x3a
+#define DW_AT_decl_line 0x3b
+#define DW_AT_declaration 0x3c
+#define DW_AT_discr_list 0x3d
+#define DW_AT_encoding 0x3e
+#define DW_AT_external 0x3f
+#define DW_AT_frame_base 0x40
+#define DW_AT_friend 0x41
+#define DW_AT_identifier_case 0x42
+#define DW_AT_macro_info 0x43
+#define DW_AT_namelist_item 0x44
+#define DW_AT_priority 0x45
+#define DW_AT_segment 0x46
+#define DW_AT_specification 0x47
+#define DW_AT_static_link 0x48
+#define DW_AT_type 0x49
+#define DW_AT_use_location 0x4a
+#define DW_AT_variable_parameter 0x4b
+#define DW_AT_virtuality 0x4c
+#define DW_AT_vtable_elem_location 0x4d
+#define DW_AT_allocated 0x4e /* DWARF3 */
+#define DW_AT_associated 0x4f /* DWARF3 */
+#define DW_AT_data_location 0x50 /* DWARF3 */
+#define DW_AT_byte_stride 0x51 /* DWARF3f */
+#define DW_AT_stride 0x51 /* DWARF3 (do not use) */
+#define DW_AT_entry_pc 0x52 /* DWARF3 */
+#define DW_AT_use_UTF8 0x53 /* DWARF3 */
+#define DW_AT_extension 0x54 /* DWARF3 */
+#define DW_AT_ranges 0x55 /* DWARF3 */
+#define DW_AT_trampoline 0x56 /* DWARF3 */
+#define DW_AT_call_column 0x57 /* DWARF3 */
+#define DW_AT_call_file 0x58 /* DWARF3 */
+#define DW_AT_call_line 0x59 /* DWARF3 */
+#define DW_AT_description 0x5a /* DWARF3 */
+#define DW_AT_binary_scale 0x5b /* DWARF3f */
+#define DW_AT_decimal_scale 0x5c /* DWARF3f */
+#define DW_AT_small 0x5d /* DWARF3f */
+#define DW_AT_decimal_sign 0x5e /* DWARF3f */
+#define DW_AT_digit_count 0x5f /* DWARF3f */
+#define DW_AT_picture_string 0x60 /* DWARF3f */
+#define DW_AT_mutable 0x61 /* DWARF3f */
+#define DW_AT_threads_scaled 0x62 /* DWARF3f */
+#define DW_AT_explicit 0x63 /* DWARF3f */
+#define DW_AT_object_pointer 0x64 /* DWARF3f */
+#define DW_AT_endianity 0x65 /* DWARF3f */
+#define DW_AT_elemental 0x66 /* DWARF3f */
+#define DW_AT_pure 0x67 /* DWARF3f */
+#define DW_AT_recursive 0x68 /* DWARF3f */
+#define DW_AT_signature 0x69 /* DWARF4 */
+#define DW_AT_main_subprogram 0x6a /* DWARF4 */
+#define DW_AT_data_bit_offset 0x6b /* DWARF4 */
+#define DW_AT_const_expr 0x6c /* DWARF4 */
+#define DW_AT_enum_class 0x6d /* DWARF4 */
+#define DW_AT_linkage_name 0x6e /* DWARF4 */
+
+/* In extensions, we attempt to include the vendor extension
+ in the name even when the vendor leaves it out. */
+
+/* HP extensions. */
+#define DW_AT_HP_block_index 0x2000 /* HP */
+
+/* Follows extension so dwarfdump prints the most-likely-useful name. */
+#define DW_AT_lo_user 0x2000
+
+#define DW_AT_MIPS_fde 0x2001 /* MIPS/SGI */
+#define DW_AT_MIPS_loop_begin 0x2002 /* MIPS/SGI */
+#define DW_AT_MIPS_tail_loop_begin 0x2003 /* MIPS/SGI */
+#define DW_AT_MIPS_epilog_begin 0x2004 /* MIPS/SGI */
+#define DW_AT_MIPS_loop_unroll_factor 0x2005 /* MIPS/SGI */
+#define DW_AT_MIPS_software_pipeline_depth 0x2006 /* MIPS/SGI */
+#define DW_AT_MIPS_linkage_name 0x2007 /* MIPS/SGI, GNU, and others.*/
+#define DW_AT_MIPS_stride 0x2008 /* MIPS/SGI */
+#define DW_AT_MIPS_abstract_name 0x2009 /* MIPS/SGI */
+#define DW_AT_MIPS_clone_origin 0x200a /* MIPS/SGI */
+#define DW_AT_MIPS_has_inlines 0x200b /* MIPS/SGI */
+#define DW_AT_MIPS_stride_byte 0x200c /* MIPS/SGI */
+#define DW_AT_MIPS_stride_elem 0x200d /* MIPS/SGI */
+#define DW_AT_MIPS_ptr_dopetype 0x200e /* MIPS/SGI */
+#define DW_AT_MIPS_allocatable_dopetype 0x200f /* MIPS/SGI */
+#define DW_AT_MIPS_assumed_shape_dopetype 0x2010 /* MIPS/SGI */
+#define DW_AT_MIPS_assumed_size 0x2011 /* MIPS/SGI */
+
+/* HP extensions. */
+#define DW_AT_HP_unmodifiable 0x2001 /* conflict: MIPS */
+#define DW_AT_HP_actuals_stmt_list 0x2010 /* conflict: MIPS */
+#define DW_AT_HP_proc_per_section 0x2011 /* conflict: MIPS */
+#define DW_AT_HP_raw_data_ptr 0x2012 /* HP */
+#define DW_AT_HP_pass_by_reference 0x2013 /* HP */
+#define DW_AT_HP_opt_level 0x2014 /* HP */
+#define DW_AT_HP_prof_version_id 0x2015 /* HP */
+#define DW_AT_HP_opt_flags 0x2016 /* HP */
+#define DW_AT_HP_cold_region_low_pc 0x2017 /* HP */
+#define DW_AT_HP_cold_region_high_pc 0x2018 /* HP */
+#define DW_AT_HP_all_variables_modifiable 0x2019 /* HP */
+#define DW_AT_HP_linkage_name 0x201a /* HP */
+#define DW_AT_HP_prof_flags 0x201b /* HP */
+
+#define DW_AT_CPQ_discontig_ranges 0x2001 /* COMPAQ/HP */
+#define DW_AT_CPQ_semantic_events 0x2002 /* COMPAQ/HP */
+#define DW_AT_CPQ_split_lifetimes_var 0x2003 /* COMPAQ/HP */
+#define DW_AT_CPQ_split_lifetimes_rtn 0x2004 /* COMPAQ/HP */
+#define DW_AT_CPQ_prologue_length 0x2005 /* COMPAQ/HP */
+
+#define DW_AT_INTEL_other_endian 0x2026 /* Intel, 1 if byte swapped. */
+
+/* GNU extensions. */
+#define DW_AT_sf_names 0x2101 /* GNU */
+#define DW_AT_src_info 0x2102 /* GNU */
+#define DW_AT_mac_info 0x2103 /* GNU */
+#define DW_AT_src_coords 0x2104 /* GNU */
+#define DW_AT_body_begin 0x2105 /* GNU */
+#define DW_AT_body_end 0x2106 /* GNU */
+#define DW_AT_GNU_vector 0x2107 /* GNU */
+#define DW_AT_GNU_template_name 0x2108 /* GNU */
+
+/* ALTIUM extension: ALTIUM Compliant location lists (flag) */
+#define DW_AT_ALTIUM_loclist 0x2300 /* ALTIUM */
+
+/* Sun extensions */
+#define DW_AT_SUN_template 0x2201 /* SUN */
+#define DW_AT_VMS_rtnbeg_pd_address 0x2201 /* VMS */
+#define DW_AT_SUN_alignment 0x2202 /* SUN */
+#define DW_AT_SUN_vtable 0x2203 /* SUN */
+#define DW_AT_SUN_count_guarantee 0x2204 /* SUN */
+#define DW_AT_SUN_command_line 0x2205 /* SUN */
+#define DW_AT_SUN_vbase 0x2206 /* SUN */
+#define DW_AT_SUN_compile_options 0x2207 /* SUN */
+#define DW_AT_SUN_language 0x2208 /* SUN */
+#define DW_AT_SUN_browser_file 0x2209 /* SUN */
+#define DW_AT_SUN_vtable_abi 0x2210 /* SUN */
+#define DW_AT_SUN_func_offsets 0x2211 /* SUN */
+#define DW_AT_SUN_cf_kind 0x2212 /* SUN */
+#define DW_AT_SUN_vtable_index 0x2213 /* SUN */
+#define DW_AT_SUN_omp_tpriv_addr 0x2214 /* SUN */
+#define DW_AT_SUN_omp_child_func 0x2215 /* SUN */
+#define DW_AT_SUN_func_offset 0x2216 /* SUN */
+#define DW_AT_SUN_memop_type_ref 0x2217 /* SUN */
+#define DW_AT_SUN_profile_id 0x2218 /* SUN */
+#define DW_AT_SUN_memop_signature 0x2219 /* SUN */
+#define DW_AT_SUN_obj_dir 0x2220 /* SUN */
+#define DW_AT_SUN_obj_file 0x2221 /* SUN */
+#define DW_AT_SUN_original_name 0x2222 /* SUN */
+#define DW_AT_SUN_hwcprof_signature 0x2223 /* SUN */
+#define DW_AT_SUN_amd64_parmdump 0x2224 /* SUN */
+#define DW_AT_SUN_part_link_name 0x2225 /* SUN */
+#define DW_AT_SUN_link_name 0x2226 /* SUN */
+#define DW_AT_SUN_pass_with_const 0x2227 /* SUN */
+#define DW_AT_SUN_return_with_const 0x2228 /* SUN */
+#define DW_AT_SUN_import_by_name 0x2229 /* SUN */
+#define DW_AT_SUN_f90_pointer 0x222a /* SUN */
+#define DW_AT_SUN_pass_by_ref 0x222b /* SUN */
+#define DW_AT_SUN_f90_allocatable 0x222c /* SUN */
+#define DW_AT_SUN_f90_assumed_shape_array 0x222d /* SUN */
+#define DW_AT_SUN_c_vla 0x222e /* SUN */
+#define DW_AT_SUN_return_value_ptr 0x2230 /* SUN */
+#define DW_AT_SUN_dtor_start 0x2231 /* SUN */
+#define DW_AT_SUN_dtor_length 0x2232 /* SUN */
+#define DW_AT_SUN_dtor_state_initial 0x2233 /* SUN */
+#define DW_AT_SUN_dtor_state_final 0x2234 /* SUN */
+#define DW_AT_SUN_dtor_state_deltas 0x2235 /* SUN */
+#define DW_AT_SUN_import_by_lname 0x2236 /* SUN */
+#define DW_AT_SUN_f90_use_only 0x2237 /* SUN */
+#define DW_AT_SUN_namelist_spec 0x2238 /* SUN */
+#define DW_AT_SUN_is_omp_child_func 0x2239 /* SUN */
+#define DW_AT_SUN_fortran_main_alias 0x223a /* SUN */
+#define DW_AT_SUN_fortran_based 0x223b /* SUN */
+
+/* UPC extension */
+#define DW_AT_upc_threads_scaled 0x3210 /* UPC */
+
+/* PGI (STMicroelectronics) extensions. */
+#define DW_AT_PGI_lbase 0x3a00 /* PGI. Block, constant, reference. This attribute is an ASTPLAB extension used to describe the array local base. */
+#define DW_AT_PGI_soffset 0x3a01 /* PGI. Block, constant, reference. ASTPLAB adds this attribute to describe the section offset, or the offset to the first element in the dimension. */
+#define DW_AT_PGI_lstride 0x3a02 /* PGI. Block, constant, reference. ASTPLAB adds this attribute to describe the linear stride or the distance between elements in the dimension. */
+
+/* Apple Extensions for closures */
+#define DW_AT_APPLE_closure 0x3fe4 /* Apple */
+/* Apple Extensions for Objective-C runtime info */
+#define DW_AT_APPLE_major_runtime_vers 0x3fe5 /* Apple */
+#define DW_AT_APPLE_runtime_class 0x3fe6 /* Apple */
+
+
+#define DW_AT_hi_user 0x3fff
+
+#define DW_OP_addr 0x03
+#define DW_OP_deref 0x06
+#define DW_OP_const1u 0x08
+#define DW_OP_const1s 0x09
+#define DW_OP_const2u 0x0a
+#define DW_OP_const2s 0x0b
+#define DW_OP_const4u 0x0c
+#define DW_OP_const4s 0x0d
+#define DW_OP_const8u 0x0e
+#define DW_OP_const8s 0x0f
+#define DW_OP_constu 0x10
+#define DW_OP_consts 0x11
+#define DW_OP_dup 0x12
+#define DW_OP_drop 0x13
+#define DW_OP_over 0x14
+#define DW_OP_pick 0x15
+#define DW_OP_swap 0x16
+#define DW_OP_rot 0x17
+#define DW_OP_xderef 0x18
+#define DW_OP_abs 0x19
+#define DW_OP_and 0x1a
+#define DW_OP_div 0x1b
+#define DW_OP_minus 0x1c
+#define DW_OP_mod 0x1d
+#define DW_OP_mul 0x1e
+#define DW_OP_neg 0x1f
+#define DW_OP_not 0x20
+#define DW_OP_or 0x21
+#define DW_OP_plus 0x22
+#define DW_OP_plus_uconst 0x23
+#define DW_OP_shl 0x24
+#define DW_OP_shr 0x25
+#define DW_OP_shra 0x26
+#define DW_OP_xor 0x27
+#define DW_OP_bra 0x28
+#define DW_OP_eq 0x29
+#define DW_OP_ge 0x2a
+#define DW_OP_gt 0x2b
+#define DW_OP_le 0x2c
+#define DW_OP_lt 0x2d
+#define DW_OP_ne 0x2e
+#define DW_OP_skip 0x2f
+#define DW_OP_lit0 0x30
+#define DW_OP_lit1 0x31
+#define DW_OP_lit2 0x32
+#define DW_OP_lit3 0x33
+#define DW_OP_lit4 0x34
+#define DW_OP_lit5 0x35
+#define DW_OP_lit6 0x36
+#define DW_OP_lit7 0x37
+#define DW_OP_lit8 0x38
+#define DW_OP_lit9 0x39
+#define DW_OP_lit10 0x3a
+#define DW_OP_lit11 0x3b
+#define DW_OP_lit12 0x3c
+#define DW_OP_lit13 0x3d
+#define DW_OP_lit14 0x3e
+#define DW_OP_lit15 0x3f
+#define DW_OP_lit16 0x40
+#define DW_OP_lit17 0x41
+#define DW_OP_lit18 0x42
+#define DW_OP_lit19 0x43
+#define DW_OP_lit20 0x44
+#define DW_OP_lit21 0x45
+#define DW_OP_lit22 0x46
+#define DW_OP_lit23 0x47
+#define DW_OP_lit24 0x48
+#define DW_OP_lit25 0x49
+#define DW_OP_lit26 0x4a
+#define DW_OP_lit27 0x4b
+#define DW_OP_lit28 0x4c
+#define DW_OP_lit29 0x4d
+#define DW_OP_lit30 0x4e
+#define DW_OP_lit31 0x4f
+#define DW_OP_reg0 0x50
+#define DW_OP_reg1 0x51
+#define DW_OP_reg2 0x52
+#define DW_OP_reg3 0x53
+#define DW_OP_reg4 0x54
+#define DW_OP_reg5 0x55
+#define DW_OP_reg6 0x56
+#define DW_OP_reg7 0x57
+#define DW_OP_reg8 0x58
+#define DW_OP_reg9 0x59
+#define DW_OP_reg10 0x5a
+#define DW_OP_reg11 0x5b
+#define DW_OP_reg12 0x5c
+#define DW_OP_reg13 0x5d
+#define DW_OP_reg14 0x5e
+#define DW_OP_reg15 0x5f
+#define DW_OP_reg16 0x60
+#define DW_OP_reg17 0x61
+#define DW_OP_reg18 0x62
+#define DW_OP_reg19 0x63
+#define DW_OP_reg20 0x64
+#define DW_OP_reg21 0x65
+#define DW_OP_reg22 0x66
+#define DW_OP_reg23 0x67
+#define DW_OP_reg24 0x68
+#define DW_OP_reg25 0x69
+#define DW_OP_reg26 0x6a
+#define DW_OP_reg27 0x6b
+#define DW_OP_reg28 0x6c
+#define DW_OP_reg29 0x6d
+#define DW_OP_reg30 0x6e
+#define DW_OP_reg31 0x6f
+#define DW_OP_breg0 0x70
+#define DW_OP_breg1 0x71
+#define DW_OP_breg2 0x72
+#define DW_OP_breg3 0x73
+#define DW_OP_breg4 0x74
+#define DW_OP_breg5 0x75
+#define DW_OP_breg6 0x76
+#define DW_OP_breg7 0x77
+#define DW_OP_breg8 0x78
+#define DW_OP_breg9 0x79
+#define DW_OP_breg10 0x7a
+#define DW_OP_breg11 0x7b
+#define DW_OP_breg12 0x7c
+#define DW_OP_breg13 0x7d
+#define DW_OP_breg14 0x7e
+#define DW_OP_breg15 0x7f
+#define DW_OP_breg16 0x80
+#define DW_OP_breg17 0x81
+#define DW_OP_breg18 0x82
+#define DW_OP_breg19 0x83
+#define DW_OP_breg20 0x84
+#define DW_OP_breg21 0x85
+#define DW_OP_breg22 0x86
+#define DW_OP_breg23 0x87
+#define DW_OP_breg24 0x88
+#define DW_OP_breg25 0x89
+#define DW_OP_breg26 0x8a
+#define DW_OP_breg27 0x8b
+#define DW_OP_breg28 0x8c
+#define DW_OP_breg29 0x8d
+#define DW_OP_breg30 0x8e
+#define DW_OP_breg31 0x8f
+#define DW_OP_regx 0x90
+#define DW_OP_fbreg 0x91
+#define DW_OP_bregx 0x92
+#define DW_OP_piece 0x93
+#define DW_OP_deref_size 0x94
+#define DW_OP_xderef_size 0x95
+#define DW_OP_nop 0x96
+#define DW_OP_push_object_address 0x97 /* DWARF3 */
+#define DW_OP_call2 0x98 /* DWARF3 */
+#define DW_OP_call4 0x99 /* DWARF3 */
+#define DW_OP_call_ref 0x9a /* DWARF3 */
+#define DW_OP_form_tls_address 0x9b /* DWARF3f */
+#define DW_OP_call_frame_cfa 0x9c /* DWARF3f */
+#define DW_OP_bit_piece 0x9d /* DWARF3f */
+#define DW_OP_implicit_value 0x9e /* DWARF4 */
+#define DW_OP_stack_value 0x9f /* DWARF4 */
+
+
+ /* GNU extensions. */
+#define DW_OP_GNU_push_tls_address 0xe0 /* GNU */
+
+/* Follows extension so dwarfdump prints the most-likely-useful name. */
+#define DW_OP_lo_user 0xe0
+
+ /* HP extensions. */
+#define DW_OP_HP_unknown 0xe0 /* HP conflict: GNU */
+#define DW_OP_HP_is_value 0xe1 /* HP */
+#define DW_OP_HP_fltconst4 0xe2 /* HP */
+#define DW_OP_HP_fltconst8 0xe3 /* HP */
+#define DW_OP_HP_mod_range 0xe4 /* HP */
+#define DW_OP_HP_unmod_range 0xe5 /* HP */
+#define DW_OP_HP_tls 0xe6 /* HP */
+
+#define DW_OP_INTEL_bit_piece 0xe8 /* Intel: made obsolete by DW_OP_bit_piece above. */
+
+
+ /* Apple extension. */
+#define DW_OP_APPLE_uninit 0xf0 /* Apple */
+
+#define DW_OP_hi_user 0xff
+
+#define DW_ATE_address 0x1
+#define DW_ATE_boolean 0x2
+#define DW_ATE_complex_float 0x3
+#define DW_ATE_float 0x4
+#define DW_ATE_signed 0x5
+#define DW_ATE_signed_char 0x6
+#define DW_ATE_unsigned 0x7
+#define DW_ATE_unsigned_char 0x8
+#define DW_ATE_imaginary_float 0x9 /* DWARF3 */
+#define DW_ATE_packed_decimal 0xa /* DWARF3f */
+#define DW_ATE_numeric_string 0xb /* DWARF3f */
+#define DW_ATE_edited 0xc /* DWARF3f */
+#define DW_ATE_signed_fixed 0xd /* DWARF3f */
+#define DW_ATE_unsigned_fixed 0xe /* DWARF3f */
+#define DW_ATE_decimal_float 0xf /* DWARF3f */
+
+
+/* ALTIUM extensions. x80, x81 */
+#define DW_ATE_ALTIUM_fract 0x80 /* ALTIUM __fract type */
+
+/* Follows extension so dwarfdump prints the most-likely-useful name. */
+#define DW_ATE_lo_user 0x80
+
+/* Shown here to help dwarfdump build script. */
+#define DW_ATE_ALTIUM_accum 0x81 /* ALTIUM __accum type */
+
+/* HP Floating point extensions. */
+#define DW_ATE_HP_float80 0x80 /* (80 bit). HP */
+
+
+#define DW_ATE_HP_complex_float80 0x81 /* Complex (80 bit). HP */
+#define DW_ATE_HP_float128 0x82 /* (128 bit). HP */
+#define DW_ATE_HP_complex_float128 0x83 /* Complex (128 bit). HP */
+#define DW_ATE_HP_floathpintel 0x84 /* (82 bit IA64). HP */
+#define DW_ATE_HP_imaginary_float80 0x85 /* HP */
+#define DW_ATE_HP_imaginary_float128 0x86 /* HP */
+
+/* Sun extensions */
+#define DW_ATE_SUN_interval_float 0x91
+#define DW_ATE_SUN_imaginary_float 0x92 /* Obsolete: See DW_ATE_imaginary_float */
+
+#define DW_ATE_hi_user 0xff
+
+
+/* Decimal Sign codes. */
+#define DW_DS_unsigned 0x01 /* DWARF3f */
+#define DW_DS_leading_overpunch 0x02 /* DWARF3f */
+#define DW_DS_trailing_overpunch 0x03 /* DWARF3f */
+#define DW_DS_leading_separate 0x04 /* DWARF3f */
+
+#define DW_DS_trailing_separate 0x05 /* DWARF3f */
+
+/* Endian code name. */
+#define DW_END_default 0x00 /* DWARF3f */
+#define DW_END_big 0x01 /* DWARF3f */
+#define DW_END_little 0x02 /* DWARF3f */
+
+#define DW_END_lo_user 0x40 /* DWARF3f */
+#define DW_END_hi_user 0xff /* DWARF3f */
+
+/* For use with DW_TAG_SUN_codeflags
+ * If DW_TAG_SUN_codeflags is accepted as a dwarf standard, then
+ * standard dwarf ATCF entries start at 0x01
+ */
+#define DW_ATCF_lo_user 0x40 /* SUN */
+#define DW_ATCF_SUN_mop_bitfield 0x41 /* SUN */
+#define DW_ATCF_SUN_mop_spill 0x42 /* SUN */
+#define DW_ATCF_SUN_mop_scopy 0x43 /* SUN */
+#define DW_ATCF_SUN_func_start 0x44 /* SUN */
+#define DW_ATCF_SUN_end_ctors 0x45 /* SUN */
+#define DW_ATCF_SUN_branch_target 0x46 /* SUN */
+#define DW_ATCF_SUN_mop_stack_probe 0x47 /* SUN */
+#define DW_ATCF_SUN_func_epilog 0x48 /* SUN */
+#define DW_ATCF_hi_user 0xff /* SUN */
+
+/* Accessibility code name. */
+#define DW_ACCESS_public 0x01
+#define DW_ACCESS_protected 0x02
+#define DW_ACCESS_private 0x03
+
+/* Visibility code name. */
+#define DW_VIS_local 0x01
+#define DW_VIS_exported 0x02
+#define DW_VIS_qualified 0x03
+
+/* Virtuality code name. */
+#define DW_VIRTUALITY_none 0x00
+#define DW_VIRTUALITY_virtual 0x01
+#define DW_VIRTUALITY_pure_virtual 0x02
+
+#define DW_LANG_C89 0x0001
+#define DW_LANG_C 0x0002
+#define DW_LANG_Ada83 0x0003
+#define DW_LANG_C_plus_plus 0x0004
+#define DW_LANG_Cobol74 0x0005
+#define DW_LANG_Cobol85 0x0006
+#define DW_LANG_Fortran77 0x0007
+#define DW_LANG_Fortran90 0x0008
+#define DW_LANG_Pascal83 0x0009
+#define DW_LANG_Modula2 0x000a
+#define DW_LANG_Java 0x000b /* DWARF3 */
+#define DW_LANG_C99 0x000c /* DWARF3 */
+#define DW_LANG_Ada95 0x000d /* DWARF3 */
+#define DW_LANG_Fortran95 0x000e /* DWARF3 */
+#define DW_LANG_PLI 0x000f /* DWARF3 */
+#define DW_LANG_ObjC 0x0010 /* DWARF3f */
+#define DW_LANG_ObjC_plus_plus 0x0011 /* DWARF3f */
+#define DW_LANG_UPC 0x0012 /* DWARF3f */
+#define DW_LANG_D 0x0013 /* DWARF3f */
+#define DW_LANG_Python 0x0014 /* DWARF4 */
+/* The following 2 are not yet formally approved October 2010, but
+ it seems extremely likely they will be approved as the committee
+ chair agrees these should be ok and no one on the committee
+ has objected. */
+#define DW_LANG_OpenCL 0x0015 /* Provisionally DWARF5 */
+#define DW_LANG_Go 0x0016 /* Provisionally DWARF5 */
+#define DW_LANG_lo_user 0x8000
+#define DW_LANG_Mips_Assembler 0x8001 /* MIPS */
+#define DW_LANG_Upc 0x8765 /* UPC, use
+ DW_LANG_UPC instead. */
+/* ALTIUM extension */
+#define DW_LANG_ALTIUM_Assembler 0x9101 /* ALTIUM */
+
+/* Sun extensions */
+#define DW_LANG_SUN_Assembler 0x9001 /* SUN */
+
+#define DW_LANG_hi_user 0xffff
+
+/* Identifier case name. */
+#define DW_ID_case_sensitive 0x00
+#define DW_ID_up_case 0x01
+#define DW_ID_down_case 0x02
+#define DW_ID_case_insensitive 0x03
+
+/* Calling Convention Name. */
+#define DW_CC_normal 0x01
+#define DW_CC_program 0x02
+#define DW_CC_nocall 0x03
+#define DW_CC_lo_user 0x40
+
+/* ALTIUM extensions. */
+/* Function is an interrupt handler, return address on system stack. */
+#define DW_CC_ALTIUM_interrupt 0x65 /* ALTIUM*/
+
+/* Near function model, return address on system stack. */
+#define DW_CC_ALTIUM_near_system_stack 0x66 /*ALTIUM */
+
+/* Near function model, return address on user stack. */
+#define DW_CC_ALTIUM_near_user_stack 0x67 /* ALTIUM */
+
+/* Huge function model, return address on user stack. */
+#define DW_CC_ALTIUM_huge_user_stack 0x68 /* ALTIUM */
+
+
+#define DW_CC_hi_user 0xff
+
+/* Inline Code Name. */
+#define DW_INL_not_inlined 0x00
+#define DW_INL_inlined 0x01
+#define DW_INL_declared_not_inlined 0x02
+#define DW_INL_declared_inlined 0x03
+
+/* Ordering Name. */
+#define DW_ORD_row_major 0x00
+#define DW_ORD_col_major 0x01
+
+/* Discriminant Descriptor Name. */
+#define DW_DSC_label 0x00
+#define DW_DSC_range 0x01
+
+/* Line number standard opcode name. */
+#define DW_LNS_copy 0x01
+#define DW_LNS_advance_pc 0x02
+#define DW_LNS_advance_line 0x03
+#define DW_LNS_set_file 0x04
+#define DW_LNS_set_column 0x05
+#define DW_LNS_negate_stmt 0x06
+#define DW_LNS_set_basic_block 0x07
+#define DW_LNS_const_add_pc 0x08
+#define DW_LNS_fixed_advance_pc 0x09
+#define DW_LNS_set_prologue_end 0x0a /* DWARF3 */
+#define DW_LNS_set_epilogue_begin 0x0b /* DWARF3 */
+#define DW_LNS_set_isa 0x0c /* DWARF3 */
+
+/* Line number extended opcode name. */
+#define DW_LNE_end_sequence 0x01
+#define DW_LNE_set_address 0x02
+#define DW_LNE_define_file 0x03
+#define DW_LNE_set_discriminator 0x04 /* DWARF4 */
+
+/* HP extensions. */
+#define DW_LNE_HP_negate_is_UV_update 0x11 /* 17 HP */
+#define DW_LNE_HP_push_context 0x12 /* 18 HP */
+#define DW_LNE_HP_pop_context 0x13 /* 19 HP */
+#define DW_LNE_HP_set_file_line_column 0x14 /* 20 HP */
+#define DW_LNE_HP_set_routine_name 0x15 /* 21 HP */
+#define DW_LNE_HP_set_sequence 0x16 /* 22 HP */
+#define DW_LNE_HP_negate_post_semantics 0x17 /* 23 HP */
+#define DW_LNE_HP_negate_function_exit 0x18 /* 24 HP */
+#define DW_LNE_HP_negate_front_end_logical 0x19 /* 25 HP */
+#define DW_LNE_HP_define_proc 0x20 /* 32 HP */
+
+#define DW_LNE_lo_user 0x80 /* DWARF3 */
+#define DW_LNE_hi_user 0xff /* DWARF3 */
+
+/* These are known values for DW_LNS_set_isa. */
+#define DW_ISA_UNKNOWN 0
+/* The following two are ARM specific. */
+#define DW_ISA_ARM_thumb 1 /* ARM ISA */
+#define DW_ISA_ARM_arm 2 /* ARM ISA */
+
+/* Macro information. */
+#define DW_MACINFO_define 0x01
+#define DW_MACINFO_undef 0x02
+#define DW_MACINFO_start_file 0x03
+#define DW_MACINFO_end_file 0x04
+#define DW_MACINFO_vendor_ext 0xff
+
+/* CFA operator compaction (a space saving measure, see
+ the DWARF standard) means DW_CFA_extended and DW_CFA_nop
+ have the same value here. */
+#define DW_CFA_advance_loc 0x40
+#define DW_CFA_offset 0x80
+#define DW_CFA_restore 0xc0
+#define DW_CFA_extended 0
+
+#define DW_CFA_nop 0x00
+#define DW_CFA_set_loc 0x01
+#define DW_CFA_advance_loc1 0x02
+#define DW_CFA_advance_loc2 0x03
+#define DW_CFA_advance_loc4 0x04
+#define DW_CFA_offset_extended 0x05
+#define DW_CFA_restore_extended 0x06
+#define DW_CFA_undefined 0x07
+#define DW_CFA_same_value 0x08
+#define DW_CFA_register 0x09
+#define DW_CFA_remember_state 0x0a
+#define DW_CFA_restore_state 0x0b
+#define DW_CFA_def_cfa 0x0c
+#define DW_CFA_def_cfa_register 0x0d
+#define DW_CFA_def_cfa_offset 0x0e
+#define DW_CFA_def_cfa_expression 0x0f /* DWARF3 */
+#define DW_CFA_expression 0x10 /* DWARF3 */
+#define DW_CFA_offset_extended_sf 0x11 /* DWARF3 */
+#define DW_CFA_def_cfa_sf 0x12 /* DWARF3 */
+#define DW_CFA_def_cfa_offset_sf 0x13 /* DWARF3 */
+#define DW_CFA_val_offset 0x14 /* DWARF3f */
+#define DW_CFA_val_offset_sf 0x15 /* DWARF3f */
+#define DW_CFA_val_expression 0x16 /* DWARF3f */
+
+#define DW_CFA_lo_user 0x1c
+#define DW_CFA_low_user 0x1c /* Incorrect spelling, do not use. */
+
+/* SGI/MIPS extension. */
+#define DW_CFA_MIPS_advance_loc8 0x1d /* MIPS */
+
+/* GNU extensions. */
+#define DW_CFA_GNU_window_save 0x2d /* GNU */
+#define DW_CFA_GNU_args_size 0x2e /* GNU */
+#define DW_CFA_GNU_negative_offset_extended 0x2f /* GNU */
+
+#define DW_CFA_high_user 0x3f
+
+/* GNU exception header encoding. See the Generic
+ Elf Specification of the Linux Standard Base (LSB).
+ http://refspecs.freestandards.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/dwarfext.html
+ The upper 4 bits indicate how the value is to be applied.
+ The lower 4 bits indicate the format of the data.
+*/
+#define DW_EH_PE_absptr 0x00 /* GNU */
+#define DW_EH_PE_uleb128 0x01 /* GNU */
+#define DW_EH_PE_udata2 0x02 /* GNU */
+#define DW_EH_PE_udata4 0x03 /* GNU */
+#define DW_EH_PE_udata8 0x04 /* GNU */
+#define DW_EH_PE_sleb128 0x09 /* GNU */
+#define DW_EH_PE_sdata2 0x0A /* GNU */
+#define DW_EH_PE_sdata4 0x0B /* GNU */
+#define DW_EH_PE_sdata8 0x0C /* GNU */
+
+#define DW_EH_PE_pcrel 0x10 /* GNU */
+#define DW_EH_PE_textrel 0x20 /* GNU */
+#define DW_EH_PE_datarel 0x30 /* GNU */
+#define DW_EH_PE_funcrel 0x40 /* GNU */
+#define DW_EH_PE_aligned 0x50 /* GNU */
+
+#define DW_EH_PE_omit 0xff /* GNU. Means no value present. */
+
+
+/* Mapping from machine registers and pseudo-regs into the .debug_frame table.
+ DW_FRAME entries are machine specific. These describe
+ MIPS/SGI R3000, R4K, R4400 and all later MIPS/SGI IRIX machines.
+ They describe a mapping from hardware register number to
+ the number used in the table to identify that register.
+
+ The CFA (Canonical Frame Address) described in DWARF is called
+ the Virtual Frame Pointer on MIPS/SGI machines.
+
+ The DW_FRAME* names here are MIPS/SGI specfic.
+ Libdwarf interfaces defined in 2008 make the
+ frame definitions
+ here (and the fixed table sizes they imply) obsolete.
+ They are left here for compatibility.
+*/
+/* Default column used for CFA in the libdwarf reader client.
+ Assumes reg 0 never appears as
+ a register in DWARF information. Usable for MIPS,
+ but never a good idea, really. */
+#define DW_FRAME_CFA_COL 0
+
+#define DW_FRAME_REG1 1 /* integer reg 1 */
+#define DW_FRAME_REG2 2 /* integer reg 2 */
+#define DW_FRAME_REG3 3 /* integer reg 3 */
+#define DW_FRAME_REG4 4 /* integer reg 4 */
+#define DW_FRAME_REG5 5 /* integer reg 5 */
+#define DW_FRAME_REG6 6 /* integer reg 6 */
+#define DW_FRAME_REG7 7 /* integer reg 7 */
+#define DW_FRAME_REG8 8 /* integer reg 8 */
+#define DW_FRAME_REG9 9 /* integer reg 9 */
+#define DW_FRAME_REG10 10 /* integer reg 10 */
+#define DW_FRAME_REG11 11 /* integer reg 11 */
+#define DW_FRAME_REG12 12 /* integer reg 12 */
+#define DW_FRAME_REG13 13 /* integer reg 13 */
+#define DW_FRAME_REG14 14 /* integer reg 14 */
+#define DW_FRAME_REG15 15 /* integer reg 15 */
+#define DW_FRAME_REG16 16 /* integer reg 16 */
+#define DW_FRAME_REG17 17 /* integer reg 17 */
+#define DW_FRAME_REG18 18 /* integer reg 18 */
+#define DW_FRAME_REG19 19 /* integer reg 19 */
+#define DW_FRAME_REG20 20 /* integer reg 20 */
+#define DW_FRAME_REG21 21 /* integer reg 21 */
+#define DW_FRAME_REG22 22 /* integer reg 22 */
+#define DW_FRAME_REG23 23 /* integer reg 23 */
+#define DW_FRAME_REG24 24 /* integer reg 24 */
+#define DW_FRAME_REG25 25 /* integer reg 25 */
+#define DW_FRAME_REG26 26 /* integer reg 26 */
+#define DW_FRAME_REG27 27 /* integer reg 27 */
+#define DW_FRAME_REG28 28 /* integer reg 28 */
+#define DW_FRAME_REG29 29 /* integer reg 29 */
+#define DW_FRAME_REG30 30 /* integer reg 30 */
+#define DW_FRAME_REG31 31 /* integer reg 31, aka ra */
+
+ /* MIPS1, 2 have only some of these 64-bit registers.
+ ** MIPS1 save/restore takes 2 instructions per 64-bit reg, and
+ ** in that case, the register is considered stored after the second
+ ** swc1.
+ */
+#define DW_FRAME_FREG0 32 /* 64-bit floating point reg 0 */
+#define DW_FRAME_FREG1 33 /* 64-bit floating point reg 1 */
+#define DW_FRAME_FREG2 34 /* 64-bit floating point reg 2 */
+#define DW_FRAME_FREG3 35 /* 64-bit floating point reg 3 */
+#define DW_FRAME_FREG4 36 /* 64-bit floating point reg 4 */
+#define DW_FRAME_FREG5 37 /* 64-bit floating point reg 5 */
+#define DW_FRAME_FREG6 38 /* 64-bit floating point reg 6 */
+#define DW_FRAME_FREG7 39 /* 64-bit floating point reg 7 */
+#define DW_FRAME_FREG8 40 /* 64-bit floating point reg 8 */
+#define DW_FRAME_FREG9 41 /* 64-bit floating point reg 9 */
+#define DW_FRAME_FREG10 42 /* 64-bit floating point reg 10 */
+#define DW_FRAME_FREG11 43 /* 64-bit floating point reg 11 */
+#define DW_FRAME_FREG12 44 /* 64-bit floating point reg 12 */
+#define DW_FRAME_FREG13 45 /* 64-bit floating point reg 13 */
+#define DW_FRAME_FREG14 46 /* 64-bit floating point reg 14 */
+#define DW_FRAME_FREG15 47 /* 64-bit floating point reg 15 */
+#define DW_FRAME_FREG16 48 /* 64-bit floating point reg 16 */
+#define DW_FRAME_FREG17 49 /* 64-bit floating point reg 17 */
+#define DW_FRAME_FREG18 50 /* 64-bit floating point reg 18 */
+#define DW_FRAME_FREG19 51 /* 64-bit floating point reg 19 */
+#define DW_FRAME_FREG20 52 /* 64-bit floating point reg 20 */
+#define DW_FRAME_FREG21 53 /* 64-bit floating point reg 21 */
+#define DW_FRAME_FREG22 54 /* 64-bit floating point reg 22 */
+#define DW_FRAME_FREG23 55 /* 64-bit floating point reg 23 */
+#define DW_FRAME_FREG24 56 /* 64-bit floating point reg 24 */
+#define DW_FRAME_FREG25 57 /* 64-bit floating point reg 25 */
+#define DW_FRAME_FREG26 58 /* 64-bit floating point reg 26 */
+#define DW_FRAME_FREG27 59 /* 64-bit floating point reg 27 */
+#define DW_FRAME_FREG28 60 /* 64-bit floating point reg 28 */
+#define DW_FRAME_FREG29 61 /* 64-bit floating point reg 29 */
+#define DW_FRAME_FREG30 62 /* 64-bit floating point reg 30 */
+#define DW_FRAME_FREG31 63 /* 64-bit floating point reg 31 */
+
+/* ***IMPORTANT NOTE, TARGET DEPENDENCY ****
+ The following 4 #defines are dependent on
+ the target cpu(s) that you apply libdwarf to.
+ Ensure that DW_FRAME_UNDEFINED_VAL and DW_FRAME_SAME_VAL
+ do not conflict with the range [0-DW_FRAME_STATIC_LINK].
+ The value 63 works for MIPS cpus at least up to the R16000.
+
+ For a cpu with more than 63 real registers
+ DW_FRAME_HIGHEST_NORMAL_REGISTER
+ must be increased for things to work properly!
+ Also ensure that DW_FRAME_UNDEFINED_VAL DW_FRAME_SAME_VAL
+ are not in the range [0-DW_FRAME_STATIC_LINK]
+
+ Having DW_FRAME_HIGHEST_NORMAL_REGISTER be higher than
+ is strictly needed is safe.
+
+*/
+
+#ifndef DW_FRAME_HIGHEST_NORMAL_REGISTER
+#define DW_FRAME_HIGHEST_NORMAL_REGISTER 63
+#endif
+/* This is the number of columns in the Frame Table.
+ This constant should
+ be kept in sync with DW_REG_TABLE_SIZE defined in libdwarf.h
+ It must also be large enough to be beyond the highest
+ compiler-defined-register (meaning DW_FRAME_RA_COL DW_FRAME_STATIC_LINK
+ in the MIPS/IRIX case */
+#ifndef DW_FRAME_LAST_REG_NUM
+#define DW_FRAME_LAST_REG_NUM (DW_FRAME_HIGHEST_NORMAL_REGISTER + 3)
+#endif
+
+
+/* Column recording ra (return address from a function call).
+ This is common to many architectures, but as a 'simple register'
+ is not necessarily adequate for all architectures.
+ For MIPS/IRIX this register number is actually recorded on disk
+ in the .debug_frame section.
+ */
+#define DW_FRAME_RA_COL (DW_FRAME_HIGHEST_NORMAL_REGISTER + 1)
+
+/* Column recording static link applicable to up-level
+ addressing, as in IRIX mp code, pascal, etc.
+ This is common to many architectures but
+ is not necessarily adequate for all architectures.
+ For MIPS/IRIX this register number is actually recorded on disk
+ in the .debug_frame section.
+*/
+#define DW_FRAME_STATIC_LINK (DW_FRAME_HIGHEST_NORMAL_REGISTER + 2)
+
+
+
+/*
+ DW_FRAME_UNDEFINED_VAL and DW_FRAME_SAME_VAL are
+ never on disk, just generated by libdwarf. See libdwarf.h
+ for their values.
+*/
+
+
+
+#define DW_CHILDREN_no 0x00
+#define DW_CHILDREN_yes 0x01
+
+#define DW_ADDR_none 0
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __DWARF_H */
diff --git a/usr/src/lib/libdwarf/common/dwarf_abbrev.c b/usr/src/lib/libdwarf/common/dwarf_abbrev.c
new file mode 100644
index 0000000000..c2ae361f33
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_abbrev.c
@@ -0,0 +1,259 @@
+/*
+
+ Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2009-2010 David Anderson. 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
+
+*/
+/* The address of the Free Software Foundation is
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ SGI has moved from the above address.
+*/
+
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+#include "dwarf_abbrev.h"
+
+int
+dwarf_get_abbrev(Dwarf_Debug dbg,
+ Dwarf_Unsigned offset,
+ Dwarf_Abbrev * returned_abbrev,
+ Dwarf_Unsigned * length,
+ Dwarf_Unsigned * abbr_count, Dwarf_Error * error)
+{
+ Dwarf_Small *abbrev_ptr = 0;
+ Dwarf_Small *abbrev_section_end = 0;
+ Dwarf_Half attr = 0;
+ Dwarf_Half attr_form = 0;
+ Dwarf_Abbrev ret_abbrev = 0;
+ Dwarf_Unsigned labbr_count = 0;
+ Dwarf_Unsigned utmp = 0;
+
+
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ if (dbg->de_debug_abbrev.dss_data == 0) {
+ /* Loads abbrev section (and .debug_info as we do those
+ together). */
+ int res = _dwarf_load_debug_info(dbg, error);
+
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ }
+
+ if (offset >= dbg->de_debug_abbrev.dss_size) {
+ return (DW_DLV_NO_ENTRY);
+ }
+
+
+ ret_abbrev = (Dwarf_Abbrev) _dwarf_get_alloc(dbg, DW_DLA_ABBREV, 1);
+ if (ret_abbrev == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ ret_abbrev->ab_dbg = dbg;
+ if (returned_abbrev == 0 || abbr_count == 0) {
+ dwarf_dealloc(dbg, ret_abbrev, DW_DLA_ABBREV);
+ _dwarf_error(dbg, error, DW_DLE_DWARF_ABBREV_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+
+ *abbr_count = 0;
+ if (length != NULL)
+ *length = 1;
+
+ abbrev_ptr = dbg->de_debug_abbrev.dss_data + offset;
+ abbrev_section_end =
+ dbg->de_debug_abbrev.dss_data + dbg->de_debug_abbrev.dss_size;
+
+ DECODE_LEB128_UWORD(abbrev_ptr, utmp);
+ ret_abbrev->ab_code = (Dwarf_Word) utmp;
+ if (ret_abbrev->ab_code == 0) {
+ *returned_abbrev = ret_abbrev;
+ *abbr_count = 0;
+ if (length) {
+ *length = 1;
+ }
+ return (DW_DLV_OK);
+ }
+
+ DECODE_LEB128_UWORD(abbrev_ptr, utmp);
+ ret_abbrev->ab_tag = utmp;
+ ret_abbrev->ab_has_child = *(abbrev_ptr++);
+ ret_abbrev->ab_abbrev_ptr = abbrev_ptr;
+
+ do {
+ Dwarf_Unsigned utmp2;
+
+ DECODE_LEB128_UWORD(abbrev_ptr, utmp2);
+ attr = (Dwarf_Half) utmp2;
+ DECODE_LEB128_UWORD(abbrev_ptr, utmp2);
+ attr_form = (Dwarf_Half) utmp2;
+
+ if (attr != 0)
+ (labbr_count)++;
+
+ } while (abbrev_ptr < abbrev_section_end &&
+ (attr != 0 || attr_form != 0));
+
+ if (abbrev_ptr > abbrev_section_end) {
+ dwarf_dealloc(dbg, ret_abbrev, DW_DLA_ABBREV);
+ _dwarf_error(dbg, error, DW_DLE_ABBREV_DECODE_ERROR);
+ return (DW_DLV_ERROR);
+ }
+
+ if (length != NULL)
+ *length = abbrev_ptr - dbg->de_debug_abbrev.dss_data - offset;
+
+ *returned_abbrev = ret_abbrev;
+ *abbr_count = labbr_count;
+ return (DW_DLV_OK);
+}
+
+int
+dwarf_get_abbrev_code(Dwarf_Abbrev abbrev,
+ Dwarf_Unsigned * returned_code,
+ Dwarf_Error * error)
+{
+ if (abbrev == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DWARF_ABBREV_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ *returned_code = abbrev->ab_code;
+ return (DW_DLV_OK);
+}
+
+/* DWARF defines DW_TAG_hi_user as 0xffff so no tag should be
+ over 16 bits. */
+int
+dwarf_get_abbrev_tag(Dwarf_Abbrev abbrev,
+ Dwarf_Half * returned_tag, Dwarf_Error * error)
+{
+ if (abbrev == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DWARF_ABBREV_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ *returned_tag = abbrev->ab_tag;
+ return (DW_DLV_OK);
+}
+
+
+int
+dwarf_get_abbrev_children_flag(Dwarf_Abbrev abbrev,
+ Dwarf_Signed * returned_flag,
+ Dwarf_Error * error)
+{
+ if (abbrev == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DWARF_ABBREV_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ *returned_flag = abbrev->ab_has_child;
+ return (DW_DLV_OK);
+}
+
+
+int
+dwarf_get_abbrev_entry(Dwarf_Abbrev abbrev,
+ Dwarf_Signed index,
+ Dwarf_Half * returned_attr_num,
+ Dwarf_Signed * form,
+ Dwarf_Off * offset, Dwarf_Error * error)
+{
+ Dwarf_Byte_Ptr abbrev_ptr = 0;
+ Dwarf_Byte_Ptr abbrev_end = 0;
+ Dwarf_Byte_Ptr mark_abbrev_ptr = 0;
+ Dwarf_Half attr = 0;
+ Dwarf_Half attr_form = 0;
+
+ if (index < 0)
+ return (DW_DLV_NO_ENTRY);
+
+ if (abbrev == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DWARF_ABBREV_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ if (abbrev->ab_code == 0) {
+ return (DW_DLV_NO_ENTRY);
+ }
+
+ if (abbrev->ab_dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ abbrev_ptr = abbrev->ab_abbrev_ptr;
+ abbrev_end =
+ abbrev->ab_dbg->de_debug_abbrev.dss_data +
+ abbrev->ab_dbg->de_debug_abbrev.dss_size;
+
+ for (attr = 1, attr_form = 1;
+ index >= 0 && abbrev_ptr < abbrev_end && (attr != 0 ||
+ attr_form != 0);
+ index--) {
+ Dwarf_Unsigned utmp4;
+
+ mark_abbrev_ptr = abbrev_ptr;
+ DECODE_LEB128_UWORD(abbrev_ptr, utmp4);
+ attr = (Dwarf_Half) utmp4;
+ DECODE_LEB128_UWORD(abbrev_ptr, utmp4);
+ attr_form = (Dwarf_Half) utmp4;
+ }
+
+ if (abbrev_ptr >= abbrev_end) {
+ _dwarf_error(abbrev->ab_dbg, error, DW_DLE_ABBREV_DECODE_ERROR);
+ return (DW_DLV_ERROR);
+ }
+
+ if (index >= 0) {
+ return (DW_DLV_NO_ENTRY);
+ }
+
+ if (form != NULL)
+ *form = attr_form;
+ if (offset != NULL)
+ *offset = mark_abbrev_ptr - abbrev->ab_dbg->de_debug_abbrev.dss_data;
+
+ *returned_attr_num = (attr);
+ return DW_DLV_OK;
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_abbrev.h b/usr/src/lib/libdwarf/common/dwarf_abbrev.h
new file mode 100644
index 0000000000..b525924c83
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_abbrev.h
@@ -0,0 +1,55 @@
+/*
+
+ Copyright (C) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2008-2010 David Anderson. 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
+
+*/
+
+
+
+
+/* In a given CU, one of these is (eventually) set up
+ for every abbreviation we need to find (and for all.
+ those ealier in the abbreviations for that CU).
+ So we don't want elements needlessly big.
+*/
+struct Dwarf_Abbrev_s {
+ /* No TAG should exceed DW_TAG_hi_user, 0xffff, but
+ we do allow a larger value here. */
+ Dwarf_Word ab_tag;
+ /* Abbreviations are numbered (normally sequentially from
+ 1 and so 16 bits is not enough! */
+ Dwarf_Word ab_code;
+ Dwarf_Small ab_has_child;
+ Dwarf_Byte_Ptr ab_abbrev_ptr;
+ Dwarf_Debug ab_dbg;
+};
diff --git a/usr/src/lib/libdwarf/common/dwarf_addr_finder.c b/usr/src/lib/libdwarf/common/dwarf_addr_finder.c
new file mode 100644
index 0000000000..2fadefc1ea
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_addr_finder.c
@@ -0,0 +1,685 @@
+/*
+
+ Copyright (C) 2000-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 = 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;
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_alloc.c b/usr/src/lib/libdwarf/common/dwarf_alloc.c
new file mode 100644
index 0000000000..ddb423e841
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_alloc.c
@@ -0,0 +1,1258 @@
+/*
+
+ Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2007-2010 David Anderson. 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
+
+*/
+/* The address of the Free Software Foundation is
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ SGI has moved from the Crittenden Lane address.
+*/
+
+
+#undef DEBUG
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <sys/types.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "malloc_check.h"
+
+/*
+ These files are included to get the sizes
+ of structs to set the ah_bytes_one_struct field
+ of the Dwarf_Alloc_Hdr_s structs for each
+ allocation type.
+*/
+#include "dwarf_line.h"
+#include "dwarf_global.h"
+#include "dwarf_arange.h"
+#include "dwarf_abbrev.h"
+#include "dwarf_die_deliv.h"
+#include "dwarf_frame.h"
+#include "dwarf_loc.h"
+#include "dwarf_funcs.h"
+#include "dwarf_types.h"
+#include "dwarf_vars.h"
+#include "dwarf_weaks.h"
+
+
+static void _dwarf_free_special_error(Dwarf_Ptr space);
+
+#ifdef DWARF_SIMPLE_MALLOC
+static void _dwarf_simple_malloc_add_to_list(Dwarf_Debug dbg,
+ Dwarf_Ptr addr,
+ unsigned long size,
+ short alloc_type);
+static void _dwarf_simple_malloc_delete_from_list(Dwarf_Debug dbg,
+ Dwarf_Ptr space,
+ short alloc_type);
+void _dwarf_simple_malloc_botch(int err);
+
+#endif /* DWARF_SIMPLE_MALLOC */
+
+
+
+
+/*
+ This macro adds the size of a pointer to the size of a
+ struct that is given to it. It rounds up the size to
+ be a multiple of the size of a pointer. This is done
+ so that every struct returned by _dwarf_get_alloc()
+ can be preceded by a pointer to the chunk it came from.
+ Before allocating, it checks if the size of struct is less than
+ the size of a pointer. If yes, it returns the size
+ of 2 pointers. The returned size should be at least
+ the size of 2 pointers, since the first points to the
+ chunk the struct was allocated from, and the second
+ is used to link the free list.
+
+ We want DW_RESERVE to be at least the size of
+ a long long and at least the size of a pointer because
+ our struct has a long long and we want that aligned right.
+ Now Standard C defines long long as 8 bytes, so lets
+ make that standard. It will become unworkable when
+ long long or pointer grows beyound 8 bytes.
+ Unclear what to do with wierd requirements, like
+ 36 bit pointers.
+
+
+*/
+#define DW_RESERVE 8
+
+/* Round size up to the next multiple of DW_RESERVE bytes
+*/
+#define ROUND_SIZE(inputsize) \
+ (((inputsize) % (DW_RESERVE)) == 0 ? \
+ (inputsize): \
+ ((inputsize) + \
+ (DW_RESERVE) - ((inputsize) % (DW_RESERVE)) ))
+
+#define ROUND_SIZE_WITH_POINTER(i_size) (ROUND_SIZE(i_size) + DW_RESERVE)
+
+/* SMALL_ALLOC is for trivia where allocation is a waste.
+ Things that should be removed, really. */
+#define SMALL_ALLOC 2
+
+/* BASE_ALLOC is where a basic allocation makes sense, but 'not too large'.
+ No thorough evaluation of this value has been done, though
+ it was found wasteful of memory to have BASE_ALLOC be as large as
+ BIG_ALLOC. */
+#define BASE_ALLOC 64
+
+/* BIG_ALLOC is where a larger-than-BASE_ALLOC
+ allocation makes sense, but still 'not too large'.
+ No thorough evaluation of this value has been done. */
+#define BIG_ALLOC 128
+
+/* This translates into de_alloc_hdr index
+** the 0,1,1 entries are special: they don't use the
+** table values at all.
+** Rearranging the DW_DLA values would break binary compatibility
+** so that is not an option.
+*/
+struct ial_s {
+ int ia_al_num; /* Index into de_alloc_hdr table. */
+
+ /* In bytes, one struct instance. This does not account for extra
+ space needed per block, but that (DW_RESERVE) will be added in
+ later where it is needed (DW_RESERVE space never added in here).
+ */
+ int ia_struct_size;
+
+
+ /* Number of instances per alloc block. MUST be > 0. */
+ int ia_base_count;
+
+ int (*specialconstructor) (Dwarf_Debug, void *);
+ void (*specialdestructor) (void *);
+};
+
+static const
+struct ial_s index_into_allocated[ALLOC_AREA_INDEX_TABLE_MAX] = {
+ {0, 1, 1, 0, 0}, /* none */
+ {0, 1, 1, 0, 0}, /* 1 DW_DLA_STRING */
+ {1, sizeof(Dwarf_Loc), BASE_ALLOC, 0, 0}
+ , /* 2 DW_DLA_LOC */
+ {2, sizeof(Dwarf_Locdesc), BASE_ALLOC, 0, 0}
+ , /* 3 DW_DLA_LOCDESC */
+ {0, 1, 1, 0, 0}
+ , /* not used *//* 4 DW_DLA_ELLIST */
+ {0, 1, 1, 0, 0}
+ , /* not used *//* 5 DW_DLA_BOUNDS */
+ {3, sizeof(Dwarf_Block), BASE_ALLOC, 0, 0}
+ , /* 6 DW_DLA_BLOCK */
+ {0, 1, 1, 0, 0}
+ , /* the actual dwarf_debug structure *//* 7 DW_DLA_DEBUG */
+ {4, sizeof(struct Dwarf_Die_s), BIG_ALLOC, 0, 0}, /* 8 DW_DLA_DIE
+ */
+ {5, sizeof(struct Dwarf_Line_s), BIG_ALLOC, 0, 0}, /* 9
+ DW_DLA_LINE */
+ {6, sizeof(struct Dwarf_Attribute_s), BIG_ALLOC * 2, 0, 0},
+ /* 10 DW_DLA_ATTR */
+ {0, 1, 1, 0, 0}, /* not used *//* 11 DW_DLA_TYPE */
+ {0, 1, 1, 0, 0}, /* not used *//* 12 DW_DLA_SUBSCR */
+ {7, sizeof(struct Dwarf_Global_s), BASE_ALLOC, 0, 0}, /* 13
+ DW_DLA_GLOBAL
+ */
+ {8, sizeof(struct Dwarf_Error_s), BASE_ALLOC, 0, 0}, /* 14
+ DW_DLA_ERROR
+ */
+ {0, 1, 1, 0, 0}, /* 15 DW_DLA_LIST */
+ {0, 1, 1, 0, 0}, /* not used *//* 16 DW_DLA_LINEBUF */
+ {9, sizeof(struct Dwarf_Arange_s), BASE_ALLOC, 0, 0}, /* 17
+ DW_DLA_ARANGE
+ */
+ {10, sizeof(struct Dwarf_Abbrev_s), BIG_ALLOC, 0, 0}, /* 18
+ DW_DLA_ABBREV
+ */
+ {11, sizeof(Dwarf_Frame_Op), BIG_ALLOC, 0, 0}
+ , /* 19 DW_DLA_FRAME_OP */
+ {12, sizeof(struct Dwarf_Cie_s), BASE_ALLOC, 0, 0}, /* 20
+ DW_DLA_CIE */
+ {13, sizeof(struct Dwarf_Fde_s), BASE_ALLOC, 0, 0}, /* 21 DW_DLA_FDE */
+ {0, 1, 1, 0, 0}, /* 22 DW_DLA_LOC_BLOCK */
+ {0, 1, 1, 0, 0}, /* 23 DW_DLA_FRAME_BLOCK */
+ {14, sizeof(struct Dwarf_Global_s), BASE_ALLOC, 0, 0}, /* 24 DW_DLA_FUNC
+ UNUSED */
+ {15, sizeof(struct Dwarf_Global_s), BASE_ALLOC, 0, 0}, /* 25
+ DW_DLA_TYPENAME
+ UNUSED */
+ {16, sizeof(struct Dwarf_Global_s), BASE_ALLOC, 0, 0}, /* 26 DW_DLA_VAR
+ UNUSED */
+ {17, sizeof(struct Dwarf_Global_s), BASE_ALLOC, 0, 0}, /* 27 DW_DLA_WEAK
+ UNUSED */
+ {0, 1, 1, 0, 0}, /* 28 DW_DLA_ADDR */
+ {0, 1,1,0,0 }, /* 29 DW_DLA_RANGES */
+
+ /* The following DW_DLA data types
+ are known only inside libdwarf. */
+
+ {18, sizeof(struct Dwarf_Abbrev_List_s), BIG_ALLOC, 0, 0},
+ /* 30 DW_DLA_ABBREV_LIST */
+
+ {19, sizeof(struct Dwarf_Chain_s), BIG_ALLOC, 0, 0}, /* 31 DW_DLA_CHAIN */
+ {20, sizeof(struct Dwarf_CU_Context_s), BASE_ALLOC, 0, 0},
+ /* 32 DW_DLA_CU_CONTEXT */
+ {21, sizeof(struct Dwarf_Frame_s), BASE_ALLOC,
+ _dwarf_frame_constructor,
+ _dwarf_frame_destructor}, /* 33 DW_DLA_FRAME */
+ {22, sizeof(struct Dwarf_Global_Context_s), BASE_ALLOC, 0, 0},
+ /* 34 DW_DLA_GLOBAL_CONTEXT */
+ {23, sizeof(struct Dwarf_File_Entry_s), BASE_ALLOC, 0, 0}, /* 34 */
+ /* 35 DW_DLA_FILE_ENTRY */
+ {24, sizeof(struct Dwarf_Line_Context_s), BASE_ALLOC, 0, 0},
+ /* 36 DW_DLA_LINE_CONTEXT */
+ {25, sizeof(struct Dwarf_Loc_Chain_s), BASE_ALLOC, 0, 0}, /* 36 */
+ /* 37 DW_DLA_LOC_CHAIN */
+
+ {26, sizeof(struct Dwarf_Hash_Table_s),BASE_ALLOC, 0, 0}, /* 37 */
+ /* 38 DW_DLA_HASH_TABLE */
+
+/* The following really use Global struct: used to be unique struct
+ per type, but now merged (11/99). The opaque types
+ are visible in the interface. The types for
+ DW_DLA_FUNC,
+ DW_DLA_TYPENAME, DW_DLA_VAR, DW_DLA_WEAK also use
+ the global types.
+
+*/
+ {27, sizeof(struct Dwarf_Global_Context_s), BASE_ALLOC, 0, 0},
+ /* 39 DW_DLA_FUNC_CONTEXT */
+ {28, sizeof(struct Dwarf_Global_Context_s), BASE_ALLOC, 0, 0},
+ /* 40 DW_DLA_TYPENAME_CONTEXT */
+ {29, sizeof(struct Dwarf_Global_Context_s), BASE_ALLOC, 0, 0},
+ /* 41 DW_DLA_VAR_CONTEXT */
+ {30, sizeof(struct Dwarf_Global_Context_s), BASE_ALLOC, 0, 0},
+ /* 42 DW_DLA_WEAK_CONTEXT */
+ {31, sizeof(struct Dwarf_Global_Context_s), BASE_ALLOC, 0, 0},
+ /* 43 DW_DLA_PUBTYPES_CONTEXT DWARF3 */
+
+ {0,1,1,0,0 },
+ /* 44 DW_DLA_HASH_TABLE_ENTRY */
+
+
+};
+
+#ifndef DWARF_SIMPLE_MALLOC
+
+/*
+ This function is given a pointer to the header
+ structure that is used to allocate 1 struct of
+ the type given by alloc_type. It first checks
+ if a struct is available in its free list. If
+ not, it checks if 1 is available in its blob,
+ which is a chunk of memory that is reserved for
+ its use. If not, it malloc's a chunk. The
+ initial part of it is used to store the end
+ address of the chunk, and also to keep track
+ of the number of free structs in that chunk.
+ This information is used for freeing the chunk
+ when all the structs in it are free.
+
+ Assume all input arguments have been validated.
+
+ This function can be used only to allocate 1
+ struct of the given type.
+
+ It returns a pointer to the struct that the
+ user can use. It returns NULL only when it
+ is out of free structs, and cannot malloc
+ any more. The struct returned is zero-ed.
+
+ A pointer to the chunk that the struct belongs
+ to is stored in the bytes preceding the
+ returned address. Since this pointer it
+ never overwritten, when a struct is allocated
+ from the free_list this pointer does not
+ have to be written. In the 2 other cases,
+ where the struct is allocated from a new
+ chunk, or the blob, a pointer to the chunk
+ is written.
+*/
+static Dwarf_Ptr
+_dwarf_find_memory(Dwarf_Alloc_Hdr alloc_hdr)
+{
+ /* Pointer to the struct allocated. */
+ Dwarf_Small *ret_mem = 0;
+
+ /* Pointer to info about chunks allocated. */
+ Dwarf_Alloc_Area alloc_area;
+
+ /* Size of chunk malloc'ed when no free structs left. */
+ Dwarf_Signed mem_block_size;
+
+ /* Pointer to block malloc'ed. */
+ Dwarf_Small *mem_block;
+
+ /*
+ Check the alloc_area from which the last allocation was made
+ (most recent new block). If that is not successful, then search
+ the list of alloc_area's from alloc_header. */
+ alloc_area = alloc_hdr->ah_last_alloc_area;
+ if (alloc_area == NULL || alloc_area->aa_free_structs_in_chunk == 0)
+ for (alloc_area = alloc_hdr->ah_alloc_area_head;
+ alloc_area != NULL; alloc_area = alloc_area->aa_next) {
+
+ if (alloc_area->aa_free_structs_in_chunk > 0) {
+ break; /* found a free entry! */
+ }
+
+ }
+
+ if (alloc_area != NULL) {
+ alloc_area->aa_free_structs_in_chunk--;
+
+ if (alloc_area->aa_free_list != NULL) {
+ ret_mem = alloc_area->aa_free_list;
+
+ /*
+ Update the free list. The initial part of the struct is
+ used to hold a pointer to the next struct on the free
+ list. In this way, the free list chain is maintained at
+ 0 memory cost. */
+ alloc_area->aa_free_list =
+ ((Dwarf_Free_List) ret_mem)->fl_next;
+ } else if (alloc_area->aa_blob_start < alloc_area->aa_blob_end) {
+ ret_mem = alloc_area->aa_blob_start;
+
+ /*
+ Store pointer to chunk this struct belongs to in the
+ first few bytes. Return pointer to bytes after this
+ pointer storage. */
+ *(Dwarf_Alloc_Area *) ret_mem = alloc_area;
+ ret_mem += DW_RESERVE;
+
+ alloc_area->aa_blob_start += alloc_hdr->ah_bytes_one_struct;
+ } else {
+ /* else fall thru , though it should be impossible to fall
+ thru. And represents a disastrous programming error if
+ we get here. */
+#ifdef DEBUG
+ fprintf(stderr, "libdwarf Internal error start %x end %x\n",
+ (int) alloc_area->aa_blob_start,
+ (int) alloc_area->aa_blob_end);
+#endif
+ }
+ }
+
+ /* New memory has to malloc'ed since there are no free structs. */
+ if (ret_mem == 0) {
+ Dwarf_Word rounded_area_hdr_size;
+
+ alloc_hdr->ah_chunks_allocated++;
+
+ { /* this nonsense avoids a warning */
+ /* CONSTCOND would be better */
+ unsigned long v = sizeof(struct Dwarf_Alloc_Area_s);
+
+ rounded_area_hdr_size = ROUND_SIZE(v);
+ }
+
+ /*
+ Allocate memory to contain the required number of structs
+ and the Dwarf_Alloc_Area_s to control it. */
+ mem_block_size = alloc_hdr->ah_bytes_malloc_per_chunk +
+ rounded_area_hdr_size;
+
+ mem_block = malloc(mem_block_size);
+ if (mem_block == NULL) {
+ return (NULL);
+ }
+
+
+ /*
+ Attach the Dwarf_Alloc_Area_s struct to the list of chunks
+ malloc'ed for this struct type. Also initialize the fields
+ of the Dwarf_Alloc_Area_s. */
+ alloc_area = (Dwarf_Alloc_Area) mem_block;
+ alloc_area->aa_prev = 0;
+ if (alloc_hdr->ah_alloc_area_head != NULL) {
+ alloc_hdr->ah_alloc_area_head->aa_prev = alloc_area;
+ }
+ alloc_area->aa_free_list = 0;
+ alloc_area->aa_next = alloc_hdr->ah_alloc_area_head;
+ alloc_hdr->ah_alloc_area_head = alloc_area;
+
+ alloc_area->aa_alloc_hdr = alloc_hdr;
+ alloc_area->aa_free_structs_in_chunk =
+ (Dwarf_Sword) alloc_hdr->ah_structs_per_chunk - 1;
+ if (alloc_area->aa_free_structs_in_chunk < 1) {
+ /* If we get here, there is a disastrous programming error
+ somewhere. */
+#ifdef DEBUG
+ fprintf(stderr,
+ "libdwarf Internal error: free structs in chunk %d\n",
+ (int) alloc_area->aa_free_structs_in_chunk);
+#endif
+ return NULL;
+ }
+
+ /*
+ The struct returned begins immediately after the
+ Dwarf_Alloc_Area_s struct. */
+ ret_mem = mem_block + rounded_area_hdr_size;
+ alloc_area->aa_blob_start =
+ ret_mem + alloc_hdr->ah_bytes_one_struct;
+ alloc_area->aa_blob_end = mem_block + mem_block_size;
+
+ /*
+ Store pointer to chunk this struct belongs to in the first
+ few bytes. Return pointer to bytes after this pointer
+ storage. */
+ *(Dwarf_Alloc_Area *) ret_mem = alloc_area;
+ ret_mem += DW_RESERVE;
+ }
+
+ alloc_hdr->ah_last_alloc_area = alloc_area;
+ alloc_hdr->ah_struct_user_holds++;
+ memset(ret_mem, 0, alloc_hdr->ah_bytes_one_struct - DW_RESERVE);
+ return (ret_mem);
+}
+
+#endif /* ndef DWARF_SIMPLE_MALLOC */
+
+/*
+ This function returns a pointer to a region
+ of memory. For alloc_types that are not
+ strings or lists of pointers, only 1 struct
+ can be requested at a time. This is indicated
+ by an input count of 1. For strings, count
+ equals the length of the string it will
+ contain, i.e it the length of the string
+ plus 1 for the terminating null. For lists
+ of pointers, count is equal to the number of
+ pointers. For DW_DLA_FRAME_BLOCK, DW_DLA_RANGES, and
+ DW_DLA_LOC_BLOCK allocation types also, count
+ is the count of the number of structs needed.
+
+ This function cannot be used to allocate a
+ Dwarf_Debug_s struct.
+
+*/
+Dwarf_Ptr
+_dwarf_get_alloc(Dwarf_Debug dbg,
+ Dwarf_Small alloc_type, Dwarf_Unsigned count)
+{
+ Dwarf_Alloc_Hdr alloc_hdr;
+
+ Dwarf_Ptr ret_mem;
+
+ Dwarf_Signed size = 0;
+ unsigned int index;
+ unsigned int type = alloc_type;
+
+ if (dbg == NULL) {
+ return (NULL);
+ }
+
+ if (type >= ALLOC_AREA_INDEX_TABLE_MAX) {
+ /* internal error */
+ return NULL;
+ }
+ index = index_into_allocated[type].ia_al_num;
+ /* zero also illegal but not tested for */
+
+ /* If the Dwarf_Debug is not fully set up, we will get index 0 for
+ any type and must do something. 'Not fully set up' can only
+ happen for DW_DLA_ERROR, I (davea) believe, and for that we call
+ special code here.. */
+
+ if (index == 0) {
+ if (alloc_type == DW_DLA_STRING) {
+ size = count;
+ } else if (alloc_type == DW_DLA_LIST) {
+ size = count * sizeof(Dwarf_Ptr);
+ } else if (alloc_type == DW_DLA_FRAME_BLOCK) {
+ size = count * sizeof(Dwarf_Frame_Op);
+ } else if (alloc_type == DW_DLA_LOC_BLOCK) {
+ size = count * sizeof(Dwarf_Loc);
+ } else if (alloc_type == DW_DLA_HASH_TABLE_ENTRY) {
+ size = count * sizeof(struct Dwarf_Hash_Table_Entry_s);
+ } else if (alloc_type == DW_DLA_ADDR) {
+ size = count *
+ (sizeof(Dwarf_Addr) > sizeof(Dwarf_Off) ?
+ sizeof(Dwarf_Addr) : sizeof(Dwarf_Off));
+ } else if (alloc_type == DW_DLA_RANGES) {
+ size = count * sizeof(Dwarf_Ranges);
+ } else if (alloc_type == DW_DLA_ERROR) {
+ void *m = _dwarf_special_no_dbg_error_malloc();
+
+ dwarf_malloc_check_alloc_data(m, DW_DLA_ERROR);
+ return m;
+
+ } else {
+ /* If we get here, there is a disastrous programming error
+ somewhere. */
+#ifdef DEBUG
+ fprintf(stderr,
+ "libdwarf Internal error: type %d unexpected\n",
+ (int) type);
+#endif
+ }
+ } else {
+ alloc_hdr = &dbg->de_alloc_hdr[index];
+ if (alloc_hdr->ah_bytes_one_struct > 0) {
+#ifdef DWARF_SIMPLE_MALLOC
+ size = alloc_hdr->ah_bytes_one_struct;
+#else
+ {
+ void *m = _dwarf_find_memory(alloc_hdr);
+
+ dwarf_malloc_check_alloc_data(m, type);
+ if (index_into_allocated[type].specialconstructor) {
+ int res =
+ index_into_allocated[type].
+ specialconstructor(dbg, m);
+ if (res != DW_DLV_OK) {
+ /* We leak what we allocated in
+ _dwarf_find_memory when constructor fails. */
+ return NULL;
+ }
+ }
+ return m;
+ }
+#endif
+
+ } else {
+ /* Special case: should not really happen at all. */
+ if (type == DW_DLA_ERROR) {
+ /* dwarf_init failure. Because dbg is incomplete we
+ won't use it to record the malloc. */
+ void *m = _dwarf_special_no_dbg_error_malloc();
+
+ dwarf_malloc_check_alloc_data(m, DW_DLA_ERROR);
+ return m;
+ } else {
+ /* If we get here, there is a disastrous programming
+ error somewhere. */
+#ifdef DWARF_SIMPLE_MALLOC
+ _dwarf_simple_malloc_botch(3);
+#endif
+#ifdef DEBUG
+ fprintf(stderr,
+ "libdwarf Internal error: Type %d unexpected\n",
+ (int) type);
+#endif
+ }
+ }
+ }
+
+ ret_mem = malloc(size);
+#ifdef DWARF_SIMPLE_MALLOC
+ _dwarf_simple_malloc_add_to_list(dbg, ret_mem, (unsigned long) size,
+ type);
+#endif
+ if (ret_mem != NULL)
+ memset(ret_mem, 0, size);
+
+ dwarf_malloc_check_alloc_data(ret_mem, type);
+ if (index_into_allocated[type].specialconstructor) {
+ int res =
+ index_into_allocated[type].specialconstructor(dbg, ret_mem);
+ if (res != DW_DLV_OK) {
+ /* We leak what we allocated in _dwarf_find_memory when
+ constructor fails. */
+ return NULL;
+ }
+ }
+
+ return (ret_mem);
+}
+
+
+
+/*
+ This function is used to deallocate a region of memory
+ that was obtained by a call to _dwarf_get_alloc. Note
+ that though dwarf_dealloc() is a public function,
+ _dwarf_get_alloc() isn't.
+
+ For lists, typically arrays of pointers, it is assumed
+ that the space was allocated by a direct call to malloc,
+ and so a straight free() is done. This is also the case
+ for variable length blocks such as DW_DLA_FRAME_BLOCK
+ and DW_DLA_LOC_BLOCK and DW_DLA_RANGES.
+
+ For strings, the pointer might point to a string in
+ .debug_info or .debug_string. After this is checked,
+ and if found not to be the case, a free() is done,
+ again on the assumption that a malloc was used to
+ obtain the space.
+
+ For other types of structs, a pointer to the chunk that
+ the struct was allocated out of, is present in the bytes
+ preceding the pointer passed in. For this chunk it is
+ checked whether all the structs in that chunk are now free.
+ If so, the entire chunk is free_ed. Otherwise, the space
+ is added to the free list for that chunk, and the free count
+ incremented.
+
+ This function does not return anything.
+*/
+void
+dwarf_dealloc(Dwarf_Debug dbg,
+ Dwarf_Ptr space, Dwarf_Unsigned alloc_type)
+{
+ Dwarf_Alloc_Hdr alloc_hdr;
+ Dwarf_Alloc_Area alloc_area;
+ unsigned int type = alloc_type;
+ unsigned int index;
+
+ if (space == NULL) {
+ return;
+ }
+ if (type == DW_DLA_ERROR) {
+ /* Get pointer to Dwarf_Alloc_Area this struct came from. See
+ dwarf_alloc.h ROUND_SIZE_WITH_POINTER stuff */
+ alloc_area =
+ *(Dwarf_Alloc_Area *) ((char *) space - DW_RESERVE);
+ if (alloc_area == 0) {
+ /* This is the special case of a failed dwarf_init(). Also
+ (and more signficantly) there are a variety of other
+ situations where libdwarf does not *know* what dbg is
+ involved (because of a libdwarf-caller-error) so
+ libdwarf uses NULL as the dbg. Those too wind up here. */
+ _dwarf_free_special_error(space);
+ dwarf_malloc_check_dealloc_data(space, type);
+ return;
+ }
+
+ }
+ if (dbg == NULL) {
+ /* App error, or an app that failed to succeed in a
+ dwarf_init() call. */
+ return;
+ }
+ if (type >= ALLOC_AREA_INDEX_TABLE_MAX) {
+ /* internal or user app error */
+ return;
+ }
+
+ index = index_into_allocated[type].ia_al_num;
+ /*
+ A string pointer may point into .debug_info or .debug_string.
+ Otherwise, they are directly malloc'ed. */
+ dwarf_malloc_check_dealloc_data(space, type);
+ if (index == 0) {
+ if (type == DW_DLA_STRING) {
+ if ((Dwarf_Small *) space >= dbg->de_debug_info.dss_data &&
+ (Dwarf_Small *) space <
+ dbg->de_debug_info.dss_data + dbg->de_debug_info.dss_size)
+ return;
+
+ if (dbg->de_debug_line.dss_data != NULL &&
+ (Dwarf_Small *) space >= dbg->de_debug_line.dss_data &&
+ (Dwarf_Small *) space <
+ dbg->de_debug_line.dss_data + dbg->de_debug_line.dss_size)
+ return;
+
+ if (dbg->de_debug_pubnames.dss_data != NULL &&
+ (Dwarf_Small *) space >= dbg->de_debug_pubnames.dss_data &&
+ (Dwarf_Small *) space <
+ dbg->de_debug_pubnames.dss_data +
+ dbg->de_debug_pubnames.dss_size)
+ return;
+
+ if (dbg->de_debug_frame.dss_data != NULL &&
+ (Dwarf_Small *) space >= dbg->de_debug_frame.dss_data &&
+ (Dwarf_Small *) space <
+ dbg->de_debug_frame.dss_data + dbg->de_debug_frame.dss_size)
+ return;
+
+ if (dbg->de_debug_str.dss_data != NULL &&
+ (Dwarf_Small *) space >= dbg->de_debug_str.dss_data &&
+ (Dwarf_Small *) space <
+ dbg->de_debug_str.dss_data + dbg->de_debug_str.dss_size)
+ return;
+
+ if (dbg->de_debug_funcnames.dss_data != NULL &&
+ (Dwarf_Small *) space >= dbg->de_debug_funcnames.dss_data &&
+ (Dwarf_Small *) space <
+ dbg->de_debug_funcnames.dss_data +
+ dbg->de_debug_funcnames.dss_size)
+ return;
+
+ if (dbg->de_debug_typenames.dss_data != NULL &&
+ (Dwarf_Small *) space >= dbg->de_debug_typenames.dss_data &&
+ (Dwarf_Small *) space <
+ dbg->de_debug_typenames.dss_data +
+ dbg->de_debug_typenames.dss_size)
+ return;
+ if (dbg->de_debug_pubtypes.dss_data != NULL &&
+ (Dwarf_Small *) space >= dbg->de_debug_pubtypes.dss_data &&
+ (Dwarf_Small *) space <
+ dbg->de_debug_pubtypes.dss_data +
+ dbg->de_debug_pubtypes.dss_size)
+ return;
+
+ if (dbg->de_debug_varnames.dss_data != NULL &&
+ (Dwarf_Small *) space >= dbg->de_debug_varnames.dss_data &&
+ (Dwarf_Small *) space <
+ dbg->de_debug_varnames.dss_data +
+ dbg->de_debug_varnames.dss_size)
+ return;
+
+ if (dbg->de_debug_weaknames.dss_data != NULL &&
+ (Dwarf_Small *) space >= dbg->de_debug_weaknames.dss_data &&
+ (Dwarf_Small *) space <
+ dbg->de_debug_weaknames.dss_data +
+ dbg->de_debug_weaknames.dss_size)
+ return;
+
+#ifdef DWARF_SIMPLE_MALLOC
+ _dwarf_simple_malloc_delete_from_list(dbg, space, type);
+#endif
+ free(space);
+ return;
+ }
+
+ if (type == DW_DLA_LIST ||
+ type == DW_DLA_FRAME_BLOCK ||
+ type == DW_DLA_LOC_BLOCK || type == DW_DLA_ADDR ||
+ type == DW_DLA_RANGES ||
+ type == DW_DLA_HASH_TABLE_ENTRY) {
+
+#ifdef DWARF_SIMPLE_MALLOC
+ _dwarf_simple_malloc_delete_from_list(dbg, space, type);
+#endif
+ free(space);
+ return;
+ }
+ /* else is an alloc type that is not used */
+ /* app or internal error */
+#ifdef DWARF_SIMPLE_MALLOC
+ _dwarf_simple_malloc_botch(4);
+#endif
+ return;
+
+ }
+ if (index_into_allocated[type].specialdestructor) {
+ index_into_allocated[type].specialdestructor(space);
+ }
+#ifdef DWARF_SIMPLE_MALLOC
+ _dwarf_simple_malloc_delete_from_list(dbg, space, type);
+ free(space);
+#else /* !DWARF_SIMPLE_MALLOC */
+ alloc_hdr = &dbg->de_alloc_hdr[index];
+
+ /* Get pointer to Dwarf_Alloc_Area this struct came from. See
+ dwarf_alloc.h ROUND_SIZE_WITH_POINTER stuff */
+ alloc_area = *(Dwarf_Alloc_Area *) ((char *) space - DW_RESERVE);
+
+ /* ASSERT: alloc_area != NULL If NULL we could abort, let it
+ coredump below, or return, pretending all is well. We go on,
+ letting program crash. Is caller error. */
+
+ /*
+ Check that the alloc_hdr field of the alloc_area we have is
+ pointing to the right alloc_hdr. This is used to catch use of
+ incorrect deallocation code by the user. */
+ if (alloc_area->aa_alloc_hdr != alloc_hdr) {
+ /* If we get here, the user has called dwarf_dealloc wrongly or
+ there is some other disastrous error. By leaking mem here we
+ try to be safe... */
+#ifdef DEBUG
+ fprintf(stderr,
+ "libdwarf Internal error: type %d hdr mismatch %lx %lx "
+ "area ptr %lx\n",
+ (int) type,
+ (long) alloc_area->aa_alloc_hdr,
+ (long) alloc_hdr, (long) alloc_area);
+#endif
+ return;
+ }
+
+ alloc_hdr->ah_struct_user_holds--;
+ alloc_area->aa_free_structs_in_chunk++;
+
+ /*
+ Give chunk back to malloc only when every struct is freed */
+ if (alloc_area->aa_free_structs_in_chunk ==
+ alloc_hdr->ah_structs_per_chunk) {
+ if (alloc_area->aa_prev != NULL) {
+ alloc_area->aa_prev->aa_next = alloc_area->aa_next;
+ } else {
+ alloc_hdr->ah_alloc_area_head = alloc_area->aa_next;
+ }
+
+ if (alloc_area->aa_next != NULL) {
+ alloc_area->aa_next->aa_prev = alloc_area->aa_prev;
+ }
+
+ alloc_hdr->ah_chunks_allocated--;
+
+ if (alloc_area == alloc_hdr->ah_last_alloc_area) {
+ alloc_hdr->ah_last_alloc_area = NULL;
+ }
+ memset(alloc_area, 0, sizeof(*alloc_area));
+ free(alloc_area);
+ }
+
+ else {
+ ((Dwarf_Free_List) space)->fl_next = alloc_area->aa_free_list;
+ alloc_area->aa_free_list = space;
+ }
+#endif /* !DWARF_SIMPLE_MALLOC */
+}
+
+
+/*
+ Allocates space for a Dwarf_Debug_s struct,
+ since one does not exist.
+*/
+Dwarf_Debug
+_dwarf_get_debug(void
+ )
+{
+ Dwarf_Debug dbg;
+
+ dbg = (Dwarf_Debug) malloc(sizeof(struct Dwarf_Debug_s));
+ if (dbg == NULL)
+ return (NULL);
+ else
+ memset(dbg, 0, sizeof(struct Dwarf_Debug_s));
+ return (dbg);
+}
+
+
+/*
+ Sets up the Dwarf_Debug_s struct for all the
+ allocation types currently defined.
+ Allocation types DW_DLA_STRING, DW_DLA_LIST,
+ DW_DLA_FRAME_BLOCK, DW_DLA_LOC_BLOCK, DW_DLA_RANGES are
+ malloc'ed directly.
+
+ This routine should be called after _dwarf_setup(),
+ so that information about the sizes of the Dwarf
+ sections can be used to decide the number of
+ structs of each type malloc'ed.
+
+ Also DW_DLA_ELLIST, DW_DLA_BOUNDS, DW_DLA_TYPE,
+ DW_DLA_SUBSCR, DW_DLA_LINEBUF allocation types
+ are currently not used.
+ The ah_bytes_one_struct and ah_structs_per_chunk fields for
+ these types have been set to 1 for efficiency
+ in dwarf_get_alloc().
+
+ Ah_alloc_num should be greater than 1 for all
+ types that are currently being used.
+
+ Therefore, for these allocation types the
+ ah_bytes_one_struct, and ah_structs_per_chunk fields do not
+ need to be initialized.
+
+ Being an internal routine, assume proper dbg.
+*/
+
+Dwarf_Debug
+_dwarf_setup_debug(Dwarf_Debug dbg)
+{
+ int i;
+
+ for (i = 1; i <= MAX_DW_DLA; i++) {
+ const struct ial_s *ialp = &index_into_allocated[i];
+ unsigned int hdr_index = ialp->ia_al_num;
+ Dwarf_Word str_size = ialp->ia_struct_size;
+ Dwarf_Word str_count = ialp->ia_base_count;
+ Dwarf_Word rnded_size = ROUND_SIZE_WITH_POINTER(str_size);
+
+ Dwarf_Alloc_Hdr alloc_hdr = &dbg->de_alloc_hdr[hdr_index];
+
+ alloc_hdr->ah_bytes_one_struct = (Dwarf_Half) rnded_size;
+
+ /* ah_structs_per_chunk must be >0 else we are in trouble */
+ alloc_hdr->ah_structs_per_chunk = str_count;
+ alloc_hdr->ah_bytes_malloc_per_chunk = rnded_size * str_count;
+ }
+ return (dbg);
+}
+
+/*
+ This function prints out the statistics
+ collected on allocation of memory chunks.
+*/
+void
+dwarf_print_memory_stats(Dwarf_Debug dbg)
+{
+ Dwarf_Alloc_Hdr alloc_hdr;
+ Dwarf_Shalf i;
+
+ /*
+ Alloc types start at 1, not 0. Hence, the first NULL string, and
+ also a size of MAX_DW_DLA + 1. */
+ char *alloc_type_name[MAX_DW_DLA + 1] = {
+ "",
+ "DW_DLA_STRING",
+ "DW_DLA_LOC",
+ "DW_DLA_LOCDESC",
+ "DW_DLA_ELLIST",
+ "DW_DLA_BOUNDS",
+ "DW_DLA_BLOCK",
+ "DW_DLA_DEBUG",
+ "DW_DLA_DIE",
+ "DW_DLA_LINE",
+ "DW_DLA_ATTR",
+ "DW_DLA_TYPE",
+ "DW_DLA_SUBSCR",
+ "DW_DLA_GLOBAL",
+ "DW_DLA_ERROR",
+ "DW_DLA_LIST",
+ "DW_DLA_LINEBUF",
+ "DW_DLA_ARANGE",
+ "DW_DLA_ABBREV",
+ "DW_DLA_FRAME_OP",
+ "DW_DLA_CIE",
+ "DW_DLA_FDE",
+ "DW_DLA_LOC_BLOCK",
+ "DW_DLA_FRAME_BLOCK",
+ "DW_DLA_FUNC",
+ "DW_DLA_TYPENAME",
+ "DW_DLA_VAR",
+ "DW_DLA_WEAK",
+ "DW_DLA_ADDR",
+ "DW_DLA_RANGES",
+ "DW_DLA_ABBREV_LIST",
+ "DW_DLA_CHAIN",
+ "DW_DLA_CU_CONTEXT",
+ "DW_DLA_FRAME",
+ "DW_DLA_GLOBAL_CONTEXT",
+ "DW_DLA_FILE_ENTRY",
+ "DW_DLA_LINE_CONTEXT",
+ "DW_DLA_LOC_CHAIN",
+ "DW_DLA_HASH_TABLE",
+ "DW_DLA_FUNC_CONTEXT",
+ "DW_DLA_TYPENAME_CONTEXT",
+ "DW_DLA_VAR_CONTEXT",
+ "DW_DLA_WEAK_CONTEXT",
+ "DW_DLA_PUBTYPES_CONTEXT",
+ "DW_DLA_HASH_TABLE_ENTRY",
+ };
+
+ if (dbg == NULL)
+ return;
+
+ printf("Size of Dwarf_Debug %4ld bytes\n",
+ (long) sizeof(*dbg));
+ printf("Size of Dwarf_Alloc_Hdr_s %4ld bytes\n",
+ (long) sizeof(struct Dwarf_Alloc_Hdr_s));
+ printf("size of Dwarf_Alloc_Area_s %4ld bytes\n",
+ (long) sizeof(struct Dwarf_Alloc_Area_s));
+
+ printf(" Alloc Type Curr Structs byt str\n");
+ printf(" ---------- ---- ------- per per\n");
+ for (i = 1; i <= MAX_DW_DLA; i++) {
+ int indx = index_into_allocated[i].ia_al_num;
+
+ alloc_hdr = &dbg->de_alloc_hdr[indx];
+ if (alloc_hdr->ah_bytes_one_struct != 1) {
+ printf("%2d %-25s %6d %8d %6d %6d\n",
+ (int) i,
+ alloc_type_name[i],
+ (int) alloc_hdr->ah_chunks_allocated,
+ (int) alloc_hdr->ah_struct_user_holds,
+ (int) alloc_hdr->ah_bytes_malloc_per_chunk,
+ (int) alloc_hdr->ah_structs_per_chunk);
+ }
+ }
+}
+
+
+#ifndef DWARF_SIMPLE_MALLOC
+/*
+ This recursively frees
+ the chunks still allocated, and
+ forward chained through the aa_next
+ pointer.
+*/
+static void
+_dwarf_recursive_free(Dwarf_Alloc_Area alloc_area)
+{
+ if (alloc_area->aa_next != NULL) {
+ _dwarf_recursive_free(alloc_area->aa_next);
+ }
+
+ alloc_area->aa_next = 0;
+ alloc_area->aa_prev = 0;
+ free(alloc_area);
+}
+#endif
+
+/* In the 'rela' relocation case we might have malloc'd
+ space to ensure it is read-write. In that case, free the space. */
+static void
+rela_free(struct Dwarf_Section_s * sec)
+{
+ if (sec->dss_data_was_malloc) {
+ free(sec->dss_data);
+ }
+ sec->dss_data = 0;
+ sec->dss_data_was_malloc = 0;
+}
+
+/*
+ Used to free all space allocated for this Dwarf_Debug.
+ The caller should assume that the Dwarf_Debug pointer
+ itself is no longer valid upon return from this function.
+
+ In case of difficulty, this function simply returns quietly.
+*/
+int
+_dwarf_free_all_of_one_debug(Dwarf_Debug dbg)
+{
+ Dwarf_Alloc_Hdr alloc_hdr;
+ Dwarf_Shalf i;
+ Dwarf_CU_Context context = 0;
+ Dwarf_CU_Context nextcontext = 0;
+
+ if (dbg == NULL)
+ return (DW_DLV_ERROR);
+
+ /* To do complete validation that we have no surprising missing or
+ erroneous deallocs it is advisable to do the dwarf_deallocs here
+ that are not things the user can otherwise request.
+ Housecleaning. */
+
+ for (context = dbg->de_cu_context_list;
+ context; context = nextcontext) {
+ Dwarf_Hash_Table hash_table = context->cc_abbrev_hash_table;
+ _dwarf_free_abbrev_hash_table_contents(dbg,hash_table);
+ nextcontext = context->cc_next;
+ dwarf_dealloc(dbg, hash_table, DW_DLA_HASH_TABLE);
+ dwarf_dealloc(dbg, context, DW_DLA_CU_CONTEXT);
+ }
+
+ /* Housecleaning done. Now really free all the space. */
+#ifdef DWARF_SIMPLE_MALLOC
+ if (dbg->de_simple_malloc_base) {
+ struct simple_malloc_record_s *smp = dbg->de_simple_malloc_base;
+
+ while (smp) {
+ int i;
+ struct simple_malloc_record_s *prev_smp = 0;
+
+ for (i = 0; i < smp->sr_used; ++i) {
+ struct simple_malloc_entry_s *cur;
+
+ cur = &smp->sr_entry[i];
+ if (cur->se_addr != 0) {
+ free(cur->se_addr);
+ cur->se_addr = 0;
+ }
+ }
+ prev_smp = smp;
+ smp = smp->sr_next;
+ free(prev_smp);
+ }
+ dbg->de_simple_malloc_base = 0;
+ }
+#else
+ for (i = 1; i < ALLOC_AREA_REAL_TABLE_MAX; i++) {
+ int indx = i;
+
+ alloc_hdr = &dbg->de_alloc_hdr[indx];
+ if (alloc_hdr->ah_alloc_area_head != NULL) {
+ _dwarf_recursive_free(alloc_hdr->ah_alloc_area_head);
+ }
+ }
+
+#endif
+ rela_free(&dbg->de_debug_info);
+ rela_free(&dbg->de_debug_abbrev);
+ rela_free(&dbg->de_debug_line);
+ rela_free(&dbg->de_debug_loc);
+ rela_free(&dbg->de_debug_aranges);
+ rela_free(&dbg->de_debug_macinfo);
+ rela_free(&dbg->de_debug_pubnames);
+ rela_free(&dbg->de_debug_str);
+ rela_free(&dbg->de_debug_frame);
+ rela_free(&dbg->de_debug_frame_eh_gnu);
+ rela_free(&dbg->de_debug_pubtypes);
+ rela_free(&dbg->de_debug_funcnames);
+ rela_free(&dbg->de_debug_typenames);
+ rela_free(&dbg->de_debug_varnames);
+ rela_free(&dbg->de_debug_weaknames);
+ rela_free(&dbg->de_debug_ranges);
+ dwarf_harmless_cleanout(&dbg->de_harmless_errors);
+
+ memset(dbg, 0, sizeof(*dbg)); /* Prevent accidental use later. */
+ free(dbg);
+ return (DW_DLV_OK);
+}
+
+/* A special case: we have no dbg, no alloc header etc.
+ So create something out of thin air that we can recognize
+ in dwarf_dealloc.
+ Something with the prefix (prefix space hidden from caller).
+
+ Only applies to DW_DLA_ERROR, making up an error record.
+*/
+
+struct Dwarf_Error_s *
+_dwarf_special_no_dbg_error_malloc(void)
+{
+ /* the union unused things are to guarantee proper alignment */
+ union u {
+ Dwarf_Alloc_Area ptr_not_used;
+ struct Dwarf_Error_s base_not_used;
+ char data_space[sizeof(struct Dwarf_Error_s) +
+ (DW_RESERVE * 2)];
+ };
+ char *mem;
+
+ mem = malloc(sizeof(union u));
+
+ if (mem == 0) {
+ return 0;
+
+ }
+ memset(mem, 0, sizeof(union u));
+ mem += DW_RESERVE;
+ return (struct Dwarf_Error_s *) mem;
+}
+
+/* The free side of _dwarf_special_no_dbg_error_malloc()
+*/
+static void
+_dwarf_free_special_error(Dwarf_Ptr space)
+{
+ char *mem = (char *) space;
+
+ mem -= DW_RESERVE;
+ free(mem);
+}
+
+
+#ifdef DWARF_SIMPLE_MALLOC
+/* here solely for planting a breakpoint. */
+/* ARGSUSED */
+void
+_dwarf_simple_malloc_botch(int err)
+{
+ fprintf(stderr,"simple malloc botch %d\n",err);
+}
+static void
+_dwarf_simple_malloc_add_to_list(Dwarf_Debug dbg,
+ Dwarf_Ptr addr,
+ unsigned long size, short alloc_type)
+{
+ struct simple_malloc_record_s *cur;
+ struct simple_malloc_entry_s *newentry;
+
+ if (!dbg->de_simple_malloc_base) {
+ /* First entry to this routine. */
+ dbg->de_simple_malloc_base =
+ malloc(sizeof(struct simple_malloc_record_s));
+ if (!dbg->de_simple_malloc_base) {
+ _dwarf_simple_malloc_botch(7);
+ return; /* no memory, give up */
+ }
+ memset(dbg->de_simple_malloc_base,
+ 0, sizeof(struct simple_malloc_record_s));
+ }
+ cur = dbg->de_simple_malloc_base;
+
+ if (cur->sr_used >= DSM_BLOCK_COUNT) {
+ /* Better not be > than as that means chaos */
+
+ /* Create a new block to link at the head. */
+
+ struct simple_malloc_record_s *newblock =
+ malloc(sizeof(struct simple_malloc_record_s));
+ if (!newblock) {
+ _dwarf_simple_malloc_botch(8);
+ return; /* Can do nothing, out of memory */
+ }
+ memset(newblock, 0, sizeof(struct simple_malloc_record_s));
+ /* Link the new block at the head of the chain, and make it
+ 'current' */
+ dbg->de_simple_malloc_base = newblock;
+ newblock->sr_next = cur;
+ cur = newblock;
+ }
+ newentry = &cur->sr_entry[cur->sr_used];
+ newentry->se_addr = addr;
+ newentry->se_size = size;
+ newentry->se_type = alloc_type;
+ ++cur->sr_used;
+}
+
+/*
+ DWARF_SIMPLE_MALLOC: testing the hypothesis that the existing
+ malloc scheme here (see _dwarf_get_alloc()) is pointless complexity.
+
+ DWARF_SIMPLE_MALLOC also makes it easy for a malloc-tracing
+ tool to verify libdwarf malloc has no botches (though of course
+ such does not test the complicated standard-libdwarf-alloc code).
+
+ To properly answer the question, the simple-malloc allocate
+ and delete should be something other than a simple list.
+ Perhaps a heap, or perhaps a red-black tree.
+
+*/
+static void
+_dwarf_simple_malloc_delete_from_list(Dwarf_Debug dbg,
+ Dwarf_Ptr space, short alloc_type)
+{
+ if (space == 0) {
+ _dwarf_simple_malloc_botch(6);
+ }
+ if (dbg->de_simple_malloc_base) {
+ struct simple_malloc_record_s *smp = dbg->de_simple_malloc_base;
+
+ while (smp) {
+ int i;
+
+ for (i = 0; i < smp->sr_used; ++i) {
+ struct simple_malloc_entry_s *cur;
+
+ cur = &smp->sr_entry[i];
+ if (cur->se_addr == space) {
+ if (cur->se_type != alloc_type) {
+ _dwarf_simple_malloc_botch(0);
+ }
+ cur->se_addr = 0;
+ return;
+ }
+ }
+ smp = smp->sr_next;
+ }
+ }
+ /* Never found the space. */
+ _dwarf_simple_malloc_botch(1);
+ return;
+
+}
+#endif
diff --git a/usr/src/lib/libdwarf/common/dwarf_alloc.h b/usr/src/lib/libdwarf/common/dwarf_alloc.h
new file mode 100644
index 0000000000..3a61c692c6
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_alloc.h
@@ -0,0 +1,177 @@
+/*
+
+ Copyright (C) 2000,2005 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2008-2010 David Anderson. 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
+
+*/
+
+/* #define DWARF_SIMPLE_MALLOC 1 */
+
+Dwarf_Ptr _dwarf_get_alloc(Dwarf_Debug, Dwarf_Small, Dwarf_Unsigned);
+Dwarf_Debug _dwarf_get_debug(void);
+Dwarf_Debug _dwarf_setup_debug(Dwarf_Debug);
+int _dwarf_free_all_of_one_debug(Dwarf_Debug);
+
+typedef struct Dwarf_Alloc_Area_s *Dwarf_Alloc_Area;
+typedef struct Dwarf_Free_List_s *Dwarf_Free_List;
+
+/* ALLOC_AREA_INDEX_TABLE_MAX is the size of the
+ struct ial_s index_into_allocated array in dwarf_alloc.c
+*/
+#define ALLOC_AREA_INDEX_TABLE_MAX 45
+/* ALLOC_AREA_REAL_TABLE_MAX is the size of the array needed
+ to hold pointers to dwarf alloc chunk areas.
+ It's smaller as some of the index_into_allocated
+ entries (they look like {0,1,1,0,0} )
+ are treated specially and don't use 'chunks'.
+*/
+#define ALLOC_AREA_REAL_TABLE_MAX 32
+
+/*
+ This struct is used to chain all the deallocated
+ structs on the free list of each chain. The structs
+ are chained internally, by using the memory they
+ contain.
+*/
+struct Dwarf_Free_List_s {
+ Dwarf_Free_List fl_next;
+};
+
+
+/*
+ This struct is used to manage all the chunks malloc'ed
+ for a particular alloc_type. Many of the fields are
+ initialized by dwarf_init().
+*/
+struct Dwarf_Alloc_Hdr_s {
+
+ /* Count of actual number of structs user app holds pointers to
+ currently. */
+ Dwarf_Sword ah_struct_user_holds;
+
+ /*
+ Size of each struct that will be allocated for this alloc_type.
+ Initialized by dwarf_init(). */
+ Dwarf_Half ah_bytes_one_struct;
+
+ /*
+ Number of structs of this alloc_type that will be contained in
+ each chunk that is malloc'ed. Initialized by dwarf_init(). */
+ Dwarf_Word ah_structs_per_chunk;
+
+ /*
+ Number of bytes malloc'ed per chunk which is basically
+ (ah_bytes_one_struct+_DWARF_RESERVE) * ah_alloc_num. */
+ Dwarf_Word ah_bytes_malloc_per_chunk;
+
+ /* Count of chunks currently allocated for type. */
+ Dwarf_Sword ah_chunks_allocated;
+
+ /*
+ Points to a chain of Dwarf_Alloc_Area_s structs that represent
+ all the chunks currently allocated for the alloc_type. */
+ Dwarf_Alloc_Area ah_alloc_area_head;
+
+ /* Last Alloc Area that was allocated by malloc. The
+ free-space-search area looks here first and only if it is full
+ goes thru the list pointed to by ah_alloc_area_head. */
+ Dwarf_Alloc_Area ah_last_alloc_area;
+};
+
+
+/*
+ This struct is used to manage each chunk that is
+ malloc'ed for a particular alloc_type. For each
+ allocation type, the allocation header points to
+ a list of all the chunks malloc'ed for that type.
+*/
+struct Dwarf_Alloc_Area_s {
+
+ /* Points to the free list of structs in the chunk. */
+ Dwarf_Ptr aa_free_list;
+
+ /*
+ Count of the number of free structs in the chunk. This includes
+ both those on the free list, and in the blob. */
+ Dwarf_Sword aa_free_structs_in_chunk;
+
+ /*
+ Points to the first byte of the blob from which struct will be
+ allocated. A struct is put on the free_list only when it
+ dwarf_deallocated. Initial allocations are from the blob. */
+ Dwarf_Small *aa_blob_start;
+
+ /* Points just past the last byte of the blob. */
+ Dwarf_Small *aa_blob_end;
+
+ /* Points to alloc_hdr this alloc_area is linked to: The owner, in
+ other words. */
+ Dwarf_Alloc_Hdr aa_alloc_hdr;
+
+ /*
+ Used for chaining Dwarf_Alloc_Area_s atructs. Alloc areas are
+ doubly linked to enable deletion from the list in constant time. */
+ Dwarf_Alloc_Area aa_next;
+ Dwarf_Alloc_Area aa_prev;
+};
+
+struct Dwarf_Error_s *_dwarf_special_no_dbg_error_malloc(void);
+
+#ifdef DWARF_SIMPLE_MALLOC
+/*
+ DWARF_SIMPLE_MALLOC is for testing the hypothesis that the existing
+ complex malloc scheme in libdwarf is pointless complexity.
+
+ DWARF_SIMPLE_MALLOC also makes it easy for a malloc-tracing
+ tool to verify libdwarf malloc has no botches (though of course
+ such does not test the complicated standard-libdwarf-alloc code).
+
+*/
+
+struct simple_malloc_entry_s {
+ Dwarf_Small *se_addr;
+ unsigned long se_size;
+ short se_type;
+};
+#define DSM_BLOCK_COUNT (1000)
+#define DSM_BLOCK_SIZE (sizeof(struct simple_malloc_entry_s)*DSM_BLOCK_COUNT)
+
+/* we do this so dwarf_dealloc can really free everything */
+struct simple_malloc_record_s {
+ struct simple_malloc_record_s *sr_next;
+ int sr_used;
+ struct simple_malloc_entry_s sr_entry[DSM_BLOCK_COUNT];
+};
+
+
+
+#endif /* DWARF_SIMPLE_MALLOC */
diff --git a/usr/src/lib/libdwarf/common/dwarf_arange.c b/usr/src/lib/libdwarf/common/dwarf_arange.c
new file mode 100644
index 0000000000..e7ad8acc5e
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_arange.c
@@ -0,0 +1,593 @@
+/*
+
+ Copyright (C) 2000-2004 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2007-2010 David Anderson. 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
+
+*/
+/* The address of the Free Software Foundation is
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ SGI has moved from the Crittenden Lane address.
+*/
+
+
+
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+#include "dwarf_arange.h"
+#include "dwarf_global.h" /* for _dwarf_fixup_* */
+
+
+/* Common code for two user-visible routines to share.
+ Errors here result in memory leaks, but errors here
+ are serious (making aranges unusable) so we assume
+ callers will not repeat the error often or mind the leaks.
+*/
+static int
+dwarf_get_aranges_list(Dwarf_Debug dbg,
+ Dwarf_Chain * chain_out,
+ Dwarf_Signed * chain_count_out,
+ Dwarf_Error * error)
+{
+ /* Sweeps through the arange. */
+ Dwarf_Small *arange_ptr = 0;
+ Dwarf_Small *arange_ptr_start = 0;
+
+ /* Start of arange header. Used for rounding offset of arange_ptr
+ to twice the tuple size. Libdwarf requirement. */
+ Dwarf_Small *header_ptr = 0;
+
+ /* Version of .debug_aranges header. */
+ Dwarf_Half version = 0;
+
+ /* Offset of current set of aranges into .debug_info. */
+ Dwarf_Off info_offset = 0;
+
+ /* Size in bytes of addresses in target. */
+ Dwarf_Small address_size = 0;
+
+ /* Size in bytes of segment offsets in target. */
+ Dwarf_Small segment_size = 0;
+
+ /* Count of total number of aranges. */
+ Dwarf_Unsigned arange_count = 0;
+
+ Dwarf_Arange arange = 0;
+
+ /* Used to chain Dwarf_Aranges structs. */
+ Dwarf_Chain curr_chain = NULL;
+ Dwarf_Chain prev_chain = NULL;
+ Dwarf_Chain head_chain = NULL;
+
+ arange_ptr = dbg->de_debug_aranges.dss_data;
+ arange_ptr_start = arange_ptr;
+ do {
+ /* Length of current set of aranges. */
+ Dwarf_Unsigned length = 0;
+ Dwarf_Small remainder = 0;
+ Dwarf_Small *arange_ptr_past_end = 0;
+ Dwarf_Unsigned range_entry_size = 0;
+
+ int local_length_size;
+
+ /*REFERENCED*/ /* Not used in this instance of the macro */
+ int local_extension_size = 0;
+
+ header_ptr = arange_ptr;
+
+ /* READ_AREA_LENGTH updates arange_ptr for consumed bytes */
+ READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned,
+ arange_ptr, local_length_size,
+ local_extension_size);
+ arange_ptr_past_end = arange_ptr + length;
+
+
+ READ_UNALIGNED(dbg, version, Dwarf_Half,
+ arange_ptr, sizeof(Dwarf_Half));
+ arange_ptr += sizeof(Dwarf_Half);
+ length = length - sizeof(Dwarf_Half);
+ if (version != CURRENT_VERSION_STAMP) {
+ _dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR);
+ return (DW_DLV_ERROR);
+ }
+
+ READ_UNALIGNED(dbg, info_offset, Dwarf_Off,
+ arange_ptr, local_length_size);
+ arange_ptr += local_length_size;
+ length = length - local_length_size;
+ if (info_offset >= dbg->de_debug_info.dss_size) {
+ FIX_UP_OFFSET_IRIX_BUG(dbg, info_offset,
+ "arange info offset.a");
+ if (info_offset >= dbg->de_debug_info.dss_size) {
+ _dwarf_error(dbg, error, DW_DLE_ARANGE_OFFSET_BAD);
+ return (DW_DLV_ERROR);
+ }
+ }
+
+ address_size = *(Dwarf_Small *) arange_ptr;
+ /* It is not an error if the sizes differ.
+ Unusual, but not an error. */
+ arange_ptr = arange_ptr + sizeof(Dwarf_Small);
+ length = length - sizeof(Dwarf_Small);
+
+ segment_size = *(Dwarf_Small *) arange_ptr;
+ arange_ptr = arange_ptr + sizeof(Dwarf_Small);
+ length = length - sizeof(Dwarf_Small);
+ if (segment_size != 0) {
+ _dwarf_error(dbg, error, DW_DLE_SEGMENT_SIZE_BAD);
+ return (DW_DLV_ERROR);
+ }
+
+ range_entry_size = 2*address_size + segment_size;
+ /* Round arange_ptr offset to next multiple of address_size. */
+ remainder = (Dwarf_Unsigned) (arange_ptr - header_ptr) %
+ (range_entry_size);
+ if (remainder != 0) {
+ arange_ptr = arange_ptr + (2 * address_size) - remainder;
+ length = length - ((2 * address_size) - remainder);
+ }
+ do {
+ Dwarf_Addr range_address = 0;
+ Dwarf_Unsigned segment_selector = 0;
+ Dwarf_Unsigned range_length = 0;
+ /* For segmented address spaces, the first field to
+ read is a segment selector (new in DWARF4) */
+ if(version == 4 && segment_size != 0) {
+ READ_UNALIGNED(dbg, segment_selector, Dwarf_Unsigned,
+ arange_ptr, segment_size);
+ arange_ptr += address_size;
+ length = length - address_size;
+ }
+
+ READ_UNALIGNED(dbg, range_address, Dwarf_Addr,
+ arange_ptr, address_size);
+ arange_ptr += address_size;
+ length = length - address_size;
+
+ READ_UNALIGNED(dbg, range_length, Dwarf_Unsigned,
+ arange_ptr, address_size);
+ arange_ptr += address_size;
+ length = length - address_size;
+
+ { /* We used to suppress all-zero entries, but
+ now we return all aranges entries so we show
+ the entire content. March 31, 2010. */
+
+ arange = (Dwarf_Arange)
+ _dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1);
+ if (arange == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ arange->ar_segment_selector = segment_selector;
+ arange->ar_segment_selector_size = segment_size;
+ arange->ar_address = range_address;
+ arange->ar_length = range_length;
+ arange->ar_info_offset = info_offset;
+ arange->ar_dbg = dbg;
+ arange_count++;
+
+ curr_chain = (Dwarf_Chain)
+ _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
+ if (curr_chain == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ curr_chain->ch_item = arange;
+ if (head_chain == NULL)
+ head_chain = prev_chain = curr_chain;
+ else {
+ prev_chain->ch_next = curr_chain;
+ prev_chain = curr_chain;
+ }
+ }
+ /* The current set of ranges is terminated by
+ range_address 0 and range_length 0, but that
+ does not necessarily terminate the ranges for this CU!
+ There can be multiple sets in that DWARF
+ does not explicitly forbid multiple sets.
+ DWARF2,3,4 section 7.20
+ We stop short to avoid overrun of the end of the CU.
+ */
+
+ } while (arange_ptr_past_end >= (arange_ptr + range_entry_size));
+
+ /* A compiler could emit some padding bytes here. dwarf2/3
+ (dwarf4 sec 7.20) does not clearly make extra padding
+ bytes illegal. */
+ if (arange_ptr_past_end < arange_ptr) {
+ char buf[200];
+ Dwarf_Unsigned pad_count = arange_ptr - arange_ptr_past_end;
+ Dwarf_Unsigned offset = arange_ptr - arange_ptr_start;
+ snprintf(buf,sizeof(buf),"DW_DLE_ARANGE_LENGTH_BAD."
+ " 0x%" DW_PR_DUx
+ " pad bytes at offset 0x%" DW_PR_DUx
+ " in .debug_aranges",
+ pad_count, offset);
+ dwarf_insert_harmless_error(dbg,buf);
+ }
+ /* For most compilers, arange_ptr == arange_ptr_past_end at
+ this point. But not if there were padding bytes */
+ arange_ptr = arange_ptr_past_end;
+ } while (arange_ptr <
+ dbg->de_debug_aranges.dss_data + dbg->de_debug_aranges.dss_size);
+
+ if (arange_ptr !=
+ dbg->de_debug_aranges.dss_data + dbg->de_debug_aranges.dss_size) {
+ _dwarf_error(dbg, error, DW_DLE_ARANGE_DECODE_ERROR);
+ return (DW_DLV_ERROR);
+ }
+ *chain_out = head_chain;
+ *chain_count_out = arange_count;
+ return DW_DLV_OK;
+}
+
+/*
+ This function returns the count of the number of
+ aranges in the .debug_aranges section. It sets
+ aranges to point to a block of Dwarf_Arange's
+ describing the arange's. It returns DW_DLV_ERROR
+ on error.
+
+ Must be identical in most aspects to
+ dwarf_get_aranges_addr_offsets!
+
+*/
+int
+dwarf_get_aranges(Dwarf_Debug dbg,
+ Dwarf_Arange ** aranges,
+ Dwarf_Signed * returned_count, Dwarf_Error * error)
+{
+ /* Count of total number of aranges. */
+ Dwarf_Signed arange_count = 0;
+
+ Dwarf_Arange *arange_block = 0;
+
+ /* Used to chain Dwarf_Aranges structs. */
+ Dwarf_Chain curr_chain = NULL;
+ Dwarf_Chain prev_chain = NULL;
+ Dwarf_Chain head_chain = NULL;
+ Dwarf_Unsigned i = 0;
+ int res = DW_DLV_ERROR;
+
+ /* ***** BEGIN CODE ***** */
+
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ res = _dwarf_load_section(dbg, &dbg->de_debug_aranges, error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ res = dwarf_get_aranges_list(dbg,&head_chain,&arange_count,error);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+
+ arange_block = (Dwarf_Arange *)
+ _dwarf_get_alloc(dbg, DW_DLA_LIST, arange_count);
+ if (arange_block == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ curr_chain = head_chain;
+ for (i = 0; i < arange_count; i++) {
+ *(arange_block + i) = curr_chain->ch_item;
+ prev_chain = curr_chain;
+ curr_chain = curr_chain->ch_next;
+ dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN);
+ }
+
+ *aranges = arange_block;
+ *returned_count = (arange_count);
+ return DW_DLV_OK;
+}
+
+/*
+ This function returns DW_DLV_OK if it succeeds
+ and DW_DLV_ERR or DW_DLV_OK otherwise.
+ count is set to the number of addresses in the
+ .debug_aranges section.
+ For each address, the corresponding element in
+ an array is set to the address itself(aranges) and
+ the section offset (offsets).
+ Must be identical in most aspects to
+ dwarf_get_aranges!
+*/
+int
+_dwarf_get_aranges_addr_offsets(Dwarf_Debug dbg,
+ Dwarf_Addr ** addrs,
+ Dwarf_Off ** offsets,
+ Dwarf_Signed * count,
+ Dwarf_Error * error)
+{
+ Dwarf_Unsigned i = 0;
+
+ /* Used to chain Dwarf_Aranges structs. */
+ Dwarf_Chain curr_chain = NULL;
+ Dwarf_Chain prev_chain = NULL;
+ Dwarf_Chain head_chain = NULL;
+
+ Dwarf_Signed arange_count = 0;
+ Dwarf_Addr *arange_addrs = 0;
+ Dwarf_Off *arange_offsets = 0;
+
+ int res = DW_DLV_ERROR;
+
+ /* ***** BEGIN CODE ***** */
+
+ if (error != NULL)
+ *error = NULL;
+
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ res = _dwarf_load_section(dbg, &dbg->de_debug_aranges,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ res = dwarf_get_aranges_list(dbg,&head_chain,&arange_count,error);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+
+ arange_addrs = (Dwarf_Addr *)
+ _dwarf_get_alloc(dbg, DW_DLA_ADDR, arange_count);
+ if (arange_addrs == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ arange_offsets = (Dwarf_Off *)
+ _dwarf_get_alloc(dbg, DW_DLA_ADDR, arange_count);
+ if (arange_offsets == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ curr_chain = head_chain;
+ for (i = 0; i < arange_count; i++) {
+ Dwarf_Arange ar = curr_chain->ch_item;
+
+ arange_addrs[i] = ar->ar_address;
+ arange_offsets[i] = ar->ar_info_offset;
+ prev_chain = curr_chain;
+ curr_chain = curr_chain->ch_next;
+ dwarf_dealloc(dbg, ar, DW_DLA_ARANGE);
+ dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN);
+ }
+ *count = arange_count;
+ *offsets = arange_offsets;
+ *addrs = arange_addrs;
+ return (DW_DLV_OK);
+}
+
+
+/*
+ This function takes a pointer to a block
+ of Dwarf_Arange's, and a count of the
+ length of the block. It checks if the
+ given address is within the range of an
+ address range in the block. If yes, it
+ returns the appropriate Dwarf_Arange.
+ Otherwise, it returns DW_DLV_ERROR.
+*/
+int
+dwarf_get_arange(Dwarf_Arange * aranges,
+ Dwarf_Unsigned arange_count,
+ Dwarf_Addr address,
+ Dwarf_Arange * returned_arange, Dwarf_Error * error)
+{
+ Dwarf_Arange curr_arange = 0;
+ Dwarf_Unsigned i = 0;
+
+ if (aranges == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ARANGES_NULL);
+ return (DW_DLV_ERROR);
+ }
+ for (i = 0; i < arange_count; i++) {
+ curr_arange = *(aranges + i);
+ if (address >= curr_arange->ar_address &&
+ address <
+ curr_arange->ar_address + curr_arange->ar_length) {
+ *returned_arange = curr_arange;
+ return (DW_DLV_OK);
+ }
+ }
+
+ return (DW_DLV_NO_ENTRY);
+}
+
+
+/*
+ This function takes an Dwarf_Arange,
+ and returns the offset of the first
+ die in the compilation-unit that the
+ arange belongs to. Returns DW_DLV_ERROR
+ on error.
+*/
+int
+dwarf_get_cu_die_offset(Dwarf_Arange arange,
+ Dwarf_Off * returned_offset,
+ Dwarf_Error * error)
+{
+ Dwarf_Debug dbg = 0;
+ Dwarf_Off offset = 0;
+
+ if (arange == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ARANGE_NULL);
+ return (DW_DLV_ERROR);
+ }
+ dbg = arange->ar_dbg;
+ offset = arange->ar_info_offset;
+ if (!dbg->de_debug_info.dss_data) {
+ int res = _dwarf_load_debug_info(dbg, error);
+
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ }
+ *returned_offset = offset + _dwarf_length_of_cu_header(dbg, offset);
+ return DW_DLV_OK;
+}
+
+/*
+ This function takes an Dwarf_Arange,
+ and returns the offset of the CU header
+ in the compilation-unit that the
+ arange belongs to. Returns DW_DLV_ERROR
+ on error.
+ Ensures .debug_info loaded so
+ the cu_offset is meaningful.
+*/
+int
+dwarf_get_arange_cu_header_offset(Dwarf_Arange arange,
+ Dwarf_Off * cu_header_offset_returned,
+ Dwarf_Error * error)
+{
+ Dwarf_Debug dbg = 0;
+ if (arange == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ARANGE_NULL);
+ return (DW_DLV_ERROR);
+ }
+ dbg = arange->ar_dbg;
+ /* Like dwarf_get_arange_info this ensures debug_info loaded:
+ the cu_header is in debug_info and will be used else
+ we would not call dwarf_get_arange_cu_header_offset. */
+ if (!dbg->de_debug_info.dss_data) {
+ int res = _dwarf_load_debug_info(dbg, error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ }
+ *cu_header_offset_returned = arange->ar_info_offset;
+ return DW_DLV_OK;
+}
+
+
+
+
+/*
+ This function takes a Dwarf_Arange, and returns
+ true if it is not NULL. It also stores the start
+ address of the range in *start, the length of the
+ range in *length, and the offset of the first die
+ in the compilation-unit in *cu_die_offset. It
+ returns false on error.
+ If cu_die_offset returned ensures .debug_info loaded so
+ the cu_die_offset is meaningful.
+*/
+int
+dwarf_get_arange_info(Dwarf_Arange arange,
+ Dwarf_Addr * start,
+ Dwarf_Unsigned * length,
+ Dwarf_Off * cu_die_offset, Dwarf_Error * error)
+{
+ if (arange == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ARANGE_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ if (start != NULL)
+ *start = arange->ar_address;
+ if (length != NULL)
+ *length = arange->ar_length;
+ if (cu_die_offset != NULL) {
+ Dwarf_Debug dbg = arange->ar_dbg;
+ Dwarf_Off offset = arange->ar_info_offset;
+
+ if (!dbg->de_debug_info.dss_data) {
+ int res = _dwarf_load_debug_info(dbg, error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ }
+ *cu_die_offset =
+ offset + _dwarf_length_of_cu_header(dbg, offset);
+ }
+ return (DW_DLV_OK);
+}
+
+
+/* New for DWARF4, entries may have segment information.
+ *segment is only meaningful if *segment_entry_size is non-zero. */
+int
+dwarf_get_arange_info_b(Dwarf_Arange arange,
+ Dwarf_Unsigned* segment,
+ Dwarf_Unsigned* segment_entry_size,
+ Dwarf_Addr * start,
+ Dwarf_Unsigned* length,
+ Dwarf_Off * cu_die_offset,
+ Dwarf_Error * error)
+{
+ if (arange == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ARANGE_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ if(segment != NULL) {
+ *segment = arange->ar_segment_selector;
+ }
+ if(segment_entry_size != NULL) {
+ *segment_entry_size = arange->ar_segment_selector_size;
+ }
+ if (start != NULL)
+ *start = arange->ar_address;
+ if (length != NULL)
+ *length = arange->ar_length;
+ if (cu_die_offset != NULL) {
+ Dwarf_Debug dbg = arange->ar_dbg;
+ Dwarf_Off offset = arange->ar_info_offset;
+
+ if (!dbg->de_debug_info.dss_data) {
+ int res = _dwarf_load_debug_info(dbg, error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ }
+ *cu_die_offset =
+ offset + _dwarf_length_of_cu_header(dbg, offset);
+ }
+ return (DW_DLV_OK);
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_arange.h b/usr/src/lib/libdwarf/common/dwarf_arange.h
new file mode 100644
index 0000000000..d6c537c452
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_arange.h
@@ -0,0 +1,71 @@
+/*
+
+ Copyright (C) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2010 David Anderson. 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 structure is used to read an arange into. */
+struct Dwarf_Arange_s {
+
+ /* The segment selector. Only non-zero if Dwarf4, only
+ meaningful if ar_segment_selector_size non-zero */
+ Dwarf_Unsigned ar_segment_selector;
+
+ /* Starting address of the arange, ie low-pc. */
+ Dwarf_Addr ar_address;
+
+ /* Length of the arange. */
+ Dwarf_Unsigned ar_length;
+
+
+ /*
+ Offset into .debug_info of the start of the compilation-unit
+ containing this set of aranges. */
+ Dwarf_Off ar_info_offset;
+
+ /* Corresponding Dwarf_Debug. */
+ Dwarf_Debug ar_dbg;
+
+ Dwarf_Half ar_segment_selector_size;
+};
+
+
+
+int
+ _dwarf_get_aranges_addr_offsets(Dwarf_Debug dbg,
+ Dwarf_Addr ** addrs,
+ Dwarf_Off ** offsets,
+ Dwarf_Signed * count,
+ Dwarf_Error * error);
diff --git a/usr/src/lib/libdwarf/common/dwarf_base_types.h b/usr/src/lib/libdwarf/common/dwarf_base_types.h
new file mode 100644
index 0000000000..00e2700a81
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_base_types.h
@@ -0,0 +1,123 @@
+/*
+
+ Copyright (C) 2000,2005 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2008-2010 David Anderson. 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
+
+*/
+
+
+
+#include "libdwarfdefs.h"
+
+#define true 1
+#define false 0
+
+/* to identify a cie */
+#define DW_CIE_ID ~(0x0)
+#define DW_CIE_VERSION 1 /* DWARF2 */
+#define DW_CIE_VERSION3 3 /* DWARF3 */
+#define DW_CIE_VERSION4 4 /* DWARF4 */
+
+#define DW_CU_VERSION2 2
+#define DW_CU_VERSION3 3
+#define DW_CU_VERSION4 4
+
+/* DWARF2,3 and 4 */
+#define DW_ARANGES_VERSION2 2
+
+#define DW_LINE_VERSION2 2
+#define DW_LINE_VERSION3 3
+#define DW_LINE_VERSION4 4
+
+
+/*
+ These are allocation type codes for structs that
+ are internal to the Libdwarf Consumer library.
+*/
+#define DW_DLA_ABBREV_LIST DW_DLA_RANGES + 1
+#define DW_DLA_CHAIN DW_DLA_RANGES + 2
+#define DW_DLA_CU_CONTEXT DW_DLA_RANGES + 3
+#define DW_DLA_FRAME DW_DLA_RANGES + 4
+#define DW_DLA_GLOBAL_CONTEXT DW_DLA_RANGES + 5
+#define DW_DLA_FILE_ENTRY DW_DLA_RANGES + 6
+#define DW_DLA_LINE_CONTEXT DW_DLA_RANGES + 7
+#define DW_DLA_LOC_CHAIN DW_DLA_RANGES + 8
+#define DW_DLA_HASH_TABLE DW_DLA_RANGES + 9
+#define DW_DLA_FUNC_CONTEXT DW_DLA_RANGES + 10
+#define DW_DLA_TYPENAME_CONTEXT DW_DLA_RANGES + 11
+#define DW_DLA_VAR_CONTEXT DW_DLA_RANGES + 12
+#define DW_DLA_WEAK_CONTEXT DW_DLA_RANGES + 13
+#define DW_DLA_PUBTYPES_CONTEXT DW_DLA_RANGES + 14 /* DWARF3 */
+#define DW_DLA_HASH_TABLE_ENTRY DW_DLA_RANGES + 15
+
+/* Maximum number of allocation types for allocation routines. */
+#define MAX_DW_DLA DW_DLA_HASH_TABLE_ENTRY
+
+/*Dwarf_Word is unsigned word usable for index, count in memory */
+/*Dwarf_Sword is signed word usable for index, count in memory */
+/* The are 32 or 64 bits depending if 64 bit longs or not, which
+** fits the ILP32 and LP64 models
+** These work equally well with ILP64.
+*/
+
+typedef unsigned long Dwarf_Word;
+typedef signed long Dwarf_Sword;
+
+typedef signed char Dwarf_Sbyte;
+typedef unsigned char Dwarf_Ubyte;
+typedef signed short Dwarf_Shalf;
+typedef Dwarf_Small *Dwarf_Byte_Ptr;
+
+/* these 2 are fixed sizes which must not vary with the
+** ILP32/LP64 model. Between these two, stay at 32 bit.
+*/
+typedef __uint32_t Dwarf_ufixed;
+typedef __int32_t Dwarf_sfixed;
+
+/*
+ In various places the code mistakenly associates
+ forms 8 bytes long with Dwarf_Signed or Dwarf_Unsigned
+ This is not a very portable assumption.
+ The following should be used instead for 64 bit integers.
+*/
+typedef __uint64_t Dwarf_ufixed64;
+typedef __int64_t Dwarf_sfixed64;
+
+
+typedef struct Dwarf_Abbrev_List_s *Dwarf_Abbrev_List;
+typedef struct Dwarf_File_Entry_s *Dwarf_File_Entry;
+typedef struct Dwarf_CU_Context_s *Dwarf_CU_Context;
+typedef struct Dwarf_Hash_Table_s *Dwarf_Hash_Table;
+typedef struct Dwarf_Hash_Table_Entry_s *Dwarf_Hash_Table_Entry;
+
+
+typedef struct Dwarf_Alloc_Hdr_s *Dwarf_Alloc_Hdr;
diff --git a/usr/src/lib/libdwarf/common/dwarf_die_deliv.c b/usr/src/lib/libdwarf/common/dwarf_die_deliv.c
new file mode 100644
index 0000000000..4ba9f2aded
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_die_deliv.c
@@ -0,0 +1,855 @@
+/*
+
+ Copyright (C) 2000-2006 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2007-2010 David Anderson. 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
+
+*/
+/* The address of the Free Software Foundation is
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ SGI has moved from the Crittenden Lane address.
+*/
+
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#ifdef HAVE_ELF_H
+#include <elf.h>
+#endif
+#include <stdio.h>
+#include "dwarf_die_deliv.h"
+
+
+/*
+ For a given Dwarf_Debug dbg, this function checks
+ if a CU that includes the given offset has been read
+ or not. If yes, it returns the Dwarf_CU_Context
+ for the CU. Otherwise it returns NULL. Being an
+ internal routine, it is assumed that a valid dbg
+ is passed.
+
+ **This is a sequential search. May be too slow.
+
+ If debug_info and debug_abbrev not loaded, this will
+ wind up returning NULL. So no need to load before calling
+ this.
+*/
+static Dwarf_CU_Context
+_dwarf_find_CU_Context(Dwarf_Debug dbg, Dwarf_Off offset)
+{
+ Dwarf_CU_Context cu_context = 0;
+
+ if (offset >= dbg->de_info_last_offset)
+ return (NULL);
+
+ if (dbg->de_cu_context != NULL &&
+ dbg->de_cu_context->cc_next != NULL &&
+ dbg->de_cu_context->cc_next->cc_debug_info_offset == offset) {
+
+ return (dbg->de_cu_context->cc_next);
+ }
+
+ if (dbg->de_cu_context != NULL &&
+ dbg->de_cu_context->cc_debug_info_offset <= offset) {
+
+ for (cu_context = dbg->de_cu_context;
+ cu_context != NULL; cu_context = cu_context->cc_next) {
+
+ if (offset >= cu_context->cc_debug_info_offset &&
+ offset < cu_context->cc_debug_info_offset +
+ cu_context->cc_length + cu_context->cc_length_size
+ + cu_context->cc_extension_size) {
+
+ return (cu_context);
+ }
+ }
+ }
+
+ for (cu_context = dbg->de_cu_context_list;
+ cu_context != NULL; cu_context = cu_context->cc_next) {
+
+ if (offset >= cu_context->cc_debug_info_offset &&
+ offset < cu_context->cc_debug_info_offset +
+ cu_context->cc_length + cu_context->cc_length_size
+ + cu_context->cc_extension_size) {
+
+ return (cu_context);
+ }
+ }
+
+ return (NULL);
+}
+
+
+/*
+ This routine checks the dwarf_offdie() list of
+ CU contexts for the right CU context.
+*/
+static Dwarf_CU_Context
+_dwarf_find_offdie_CU_Context(Dwarf_Debug dbg, Dwarf_Off offset)
+{
+ Dwarf_CU_Context cu_context = 0;
+
+ for (cu_context = dbg->de_offdie_cu_context;
+ cu_context != NULL; cu_context = cu_context->cc_next)
+
+ if (offset >= cu_context->cc_debug_info_offset &&
+ offset < cu_context->cc_debug_info_offset +
+ cu_context->cc_length + cu_context->cc_length_size
+ + cu_context->cc_extension_size)
+
+ return (cu_context);
+
+ return (NULL);
+}
+
+
+/*
+ This function is used to create a CU Context for
+ a compilation-unit that begins at offset in
+ .debug_info. The CU Context is attached to the
+ list of CU Contexts for this dbg. It is assumed
+ that the CU at offset has not been read before,
+ and so do not call this routine before making
+ sure of this with _dwarf_find_CU_Context().
+ Returns NULL on error. As always, being an
+ internal routine, assumes a good dbg.
+
+ This function must always set a dwarf error code
+ before returning NULL. Always.
+*/
+static Dwarf_CU_Context
+_dwarf_make_CU_Context(Dwarf_Debug dbg,
+ Dwarf_Off offset, Dwarf_Error * error)
+{
+ Dwarf_CU_Context cu_context = 0;
+ Dwarf_Unsigned length = 0;
+ Dwarf_Signed abbrev_offset = 0;
+ Dwarf_Byte_Ptr cu_ptr = 0;
+ int local_extension_size = 0;
+ int local_length_size = 0;
+
+ cu_context =
+ (Dwarf_CU_Context) _dwarf_get_alloc(dbg, DW_DLA_CU_CONTEXT, 1);
+ if (cu_context == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (NULL);
+ }
+ cu_context->cc_dbg = dbg;
+
+ cu_ptr = (Dwarf_Byte_Ptr) (dbg->de_debug_info.dss_data + offset);
+
+ /* READ_AREA_LENGTH updates cu_ptr for consumed bytes */
+ READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned,
+ cu_ptr, local_length_size, local_extension_size);
+ cu_context->cc_length_size = local_length_size;
+ cu_context->cc_extension_size = local_extension_size;
+
+
+ cu_context->cc_length = (Dwarf_Word) length;
+
+ READ_UNALIGNED(dbg, cu_context->cc_version_stamp, Dwarf_Half,
+ cu_ptr, sizeof(Dwarf_Half));
+ cu_ptr += sizeof(Dwarf_Half);
+
+ READ_UNALIGNED(dbg, abbrev_offset, Dwarf_Signed,
+ cu_ptr, local_length_size);
+ cu_ptr += local_length_size;
+ cu_context->cc_abbrev_offset = (Dwarf_Sword) abbrev_offset;
+
+ cu_context->cc_address_size = *(Dwarf_Small *) cu_ptr;
+
+ if ((length < CU_VERSION_STAMP_SIZE + local_length_size +
+ CU_ADDRESS_SIZE_SIZE) ||
+ (offset + length + local_length_size +
+ local_extension_size > dbg->de_debug_info.dss_size)) {
+
+ dwarf_dealloc(dbg, cu_context, DW_DLA_CU_CONTEXT);
+ _dwarf_error(dbg, error, DW_DLE_CU_LENGTH_ERROR);
+ return (NULL);
+ }
+
+ if (cu_context->cc_version_stamp != CURRENT_VERSION_STAMP
+ && cu_context->cc_version_stamp != CURRENT_VERSION_STAMP3
+ && cu_context->cc_version_stamp != CURRENT_VERSION_STAMP4) {
+ dwarf_dealloc(dbg, cu_context, DW_DLA_CU_CONTEXT);
+ _dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR);
+ return (NULL);
+ }
+
+ if (abbrev_offset >= dbg->de_debug_abbrev.dss_size) {
+ dwarf_dealloc(dbg, cu_context, DW_DLA_CU_CONTEXT);
+ _dwarf_error(dbg, error, DW_DLE_ABBREV_OFFSET_ERROR);
+ return (NULL);
+ }
+
+ cu_context->cc_abbrev_hash_table =
+ (Dwarf_Hash_Table) _dwarf_get_alloc(dbg, DW_DLA_HASH_TABLE, 1);
+ if (cu_context->cc_abbrev_hash_table == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (NULL);
+ }
+
+ cu_context->cc_debug_info_offset = (Dwarf_Word) offset;
+ dbg->de_info_last_offset =
+ (Dwarf_Word) (offset + length +
+ local_extension_size + local_length_size);
+
+ if (dbg->de_cu_context_list == NULL) {
+ dbg->de_cu_context_list = cu_context;
+ dbg->de_cu_context_list_end = cu_context;
+ } else {
+ dbg->de_cu_context_list_end->cc_next = cu_context;
+ dbg->de_cu_context_list_end = cu_context;
+ }
+
+ return (cu_context);
+}
+
+
+/*
+ Returns offset of next compilation-unit thru next_cu_offset
+ pointer.
+ It basically sequentially moves from one
+ cu to the next. The current cu is recorded
+ internally by libdwarf.
+
+ The _b form is new for DWARF4 adding new returned fields.
+*/
+int
+dwarf_next_cu_header(Dwarf_Debug dbg,
+ Dwarf_Unsigned * cu_header_length,
+ Dwarf_Half * version_stamp,
+ Dwarf_Unsigned * abbrev_offset,
+ Dwarf_Half * address_size,
+ Dwarf_Unsigned * next_cu_offset,
+ Dwarf_Error * error)
+{
+ return dwarf_next_cu_header_b(dbg,
+ cu_header_length,
+ version_stamp,
+ abbrev_offset,
+ address_size,
+ 0,0,
+ next_cu_offset,
+ error);
+}
+int
+dwarf_next_cu_header_b(Dwarf_Debug dbg,
+ Dwarf_Unsigned * cu_header_length,
+ Dwarf_Half * version_stamp,
+ Dwarf_Unsigned * abbrev_offset,
+ Dwarf_Half * address_size,
+ Dwarf_Half * offset_size,
+ Dwarf_Half * extension_size,
+ Dwarf_Unsigned * next_cu_offset,
+ Dwarf_Error * error)
+{
+ /* Offset for current and new CU. */
+ Dwarf_Unsigned new_offset = 0;
+
+ /* CU Context for current CU. */
+ Dwarf_CU_Context cu_context = 0;
+
+ /* ***** BEGIN CODE ***** */
+
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ /*
+ Get offset into .debug_info of next CU. If dbg has no context,
+ this has to be the first one. */
+ if (dbg->de_cu_context == NULL) {
+ new_offset = 0;
+ if (!dbg->de_debug_info.dss_data) {
+ int res = _dwarf_load_debug_info(dbg, error);
+
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ }
+
+ } else {
+ new_offset = dbg->de_cu_context->cc_debug_info_offset +
+ dbg->de_cu_context->cc_length +
+ dbg->de_cu_context->cc_length_size +
+ dbg->de_cu_context->cc_extension_size;
+ }
+
+ /*
+ Check that there is room in .debug_info beyond the new offset
+ for at least a new cu header. If not, return 0 to indicate end
+ of debug_info section, and reset de_cu_debug_info_offset to
+ enable looping back through the cu's. */
+ if ((new_offset + _dwarf_length_of_cu_header_simple(dbg)) >=
+ dbg->de_debug_info.dss_size) {
+ dbg->de_cu_context = NULL;
+ return (DW_DLV_NO_ENTRY);
+ }
+
+ /* Check if this CU has been read before. */
+ cu_context = _dwarf_find_CU_Context(dbg, new_offset);
+
+ /* If not, make CU Context for it. */
+ if (cu_context == NULL) {
+ cu_context = _dwarf_make_CU_Context(dbg, new_offset, error);
+ if (cu_context == NULL) {
+ /* Error if CU Context could not be made. Since
+ _dwarf_make_CU_Context has already registered an error
+ we do not do that here: we let the lower error pass
+ thru. */
+ return (DW_DLV_ERROR);
+ }
+ }
+
+ dbg->de_cu_context = cu_context;
+
+ if (cu_header_length != NULL)
+ *cu_header_length = cu_context->cc_length;
+
+ if (version_stamp != NULL)
+ *version_stamp = cu_context->cc_version_stamp;
+
+ if (abbrev_offset != NULL)
+ *abbrev_offset = cu_context->cc_abbrev_offset;
+
+ if (address_size != NULL)
+ *address_size = cu_context->cc_address_size;
+ if (offset_size != NULL)
+ *offset_size = cu_context->cc_length_size;
+ if (extension_size != NULL)
+ *extension_size = cu_context->cc_extension_size;
+
+ new_offset = new_offset + cu_context->cc_length +
+ cu_context->cc_length_size + cu_context->cc_extension_size;
+ *next_cu_offset = new_offset;
+ return (DW_DLV_OK);
+}
+
+
+/*
+ This function does two slightly different things
+ depending on the input flag want_AT_sibling. If
+ this flag is true, it checks if the input die has
+ a DW_AT_sibling attribute. If it does it returns
+ a pointer to the start of the sibling die in the
+ .debug_info section. Otherwise it behaves the
+ same as the want_AT_sibling false case.
+
+ If the want_AT_sibling flag is false, it returns
+ a pointer to the immediately adjacent die in the
+ .debug_info section.
+
+ Die_info_end points to the end of the .debug_info
+ portion for the cu the die belongs to. It is used
+ to check that the search for the next die does not
+ cross the end of the current cu. Cu_info_start points
+ to the start of the .debug_info portion for the
+ current cu, and is used to add to the offset for
+ DW_AT_sibling attributes. Finally, has_die_child
+ is a pointer to a Dwarf_Bool that is set true if
+ the present die has children, false otherwise.
+ However, in case want_AT_child is true and the die
+ has a DW_AT_sibling attribute *has_die_child is set
+ false to indicate that the children are being skipped.
+
+ die_info_end points to the last byte+1 of the cu.
+
+*/
+static Dwarf_Byte_Ptr
+_dwarf_next_die_info_ptr(Dwarf_Byte_Ptr die_info_ptr,
+ Dwarf_CU_Context cu_context,
+ Dwarf_Byte_Ptr die_info_end,
+ Dwarf_Byte_Ptr cu_info_start,
+ Dwarf_Bool want_AT_sibling,
+ Dwarf_Bool * has_die_child)
+{
+ Dwarf_Byte_Ptr info_ptr = 0;
+ Dwarf_Byte_Ptr abbrev_ptr = 0;
+ Dwarf_Word abbrev_code = 0;
+ Dwarf_Abbrev_List abbrev_list;
+ Dwarf_Half attr = 0;
+ Dwarf_Half attr_form = 0;
+ Dwarf_Unsigned offset = 0;
+ Dwarf_Word leb128_length = 0;
+ Dwarf_Unsigned utmp = 0;
+ Dwarf_Debug dbg = 0;
+
+ info_ptr = die_info_ptr;
+ DECODE_LEB128_UWORD(info_ptr, utmp);
+ abbrev_code = (Dwarf_Word) utmp;
+ if (abbrev_code == 0) {
+ return NULL;
+ }
+
+
+ abbrev_list = _dwarf_get_abbrev_for_code(cu_context, abbrev_code);
+ if (abbrev_list == NULL) {
+ return (NULL);
+ }
+ dbg = cu_context->cc_dbg;
+
+ *has_die_child = abbrev_list->ab_has_child;
+
+ abbrev_ptr = abbrev_list->ab_abbrev_ptr;
+ do {
+ Dwarf_Unsigned utmp2;
+
+ DECODE_LEB128_UWORD(abbrev_ptr, utmp2);
+ attr = (Dwarf_Half) utmp2;
+ DECODE_LEB128_UWORD(abbrev_ptr, utmp2);
+ attr_form = (Dwarf_Half) utmp2;
+ if (attr_form == DW_FORM_indirect) {
+ Dwarf_Unsigned utmp6;
+
+ /* DECODE_LEB128_UWORD updates info_ptr */
+ DECODE_LEB128_UWORD(info_ptr, utmp6);
+ attr_form = (Dwarf_Half) utmp6;
+
+ }
+
+ if (want_AT_sibling && attr == DW_AT_sibling) {
+ switch (attr_form) {
+ case DW_FORM_ref1:
+ offset = *(Dwarf_Small *) info_ptr;
+ break;
+ case DW_FORM_ref2:
+ /* READ_UNALIGNED does not update info_ptr */
+ READ_UNALIGNED(dbg, offset, Dwarf_Unsigned,
+ info_ptr, sizeof(Dwarf_Half));
+ break;
+ case DW_FORM_ref4:
+ READ_UNALIGNED(dbg, offset, Dwarf_Unsigned,
+ info_ptr, sizeof(Dwarf_ufixed));
+ break;
+ case DW_FORM_ref8:
+ READ_UNALIGNED(dbg, offset, Dwarf_Unsigned,
+ info_ptr, sizeof(Dwarf_Unsigned));
+ break;
+ case DW_FORM_ref_udata:
+ offset =
+ _dwarf_decode_u_leb128(info_ptr, &leb128_length);
+ break;
+ case DW_FORM_ref_addr:
+ /* Very unusual. The FORM is intended to refer to
+ a different CU, but a different CU cannot
+ be a sibling, can it?
+ We could ignore this and treat as if no DW_AT_sibling
+ present. Or derive the offset from it and if
+ it is in the same CU use it directly.
+ The offset here is *supposed* to be a global offset,
+ so adding cu_info_start is wrong to any offset
+ we find here unless cu_info_start
+ is zero! Lets pretend there is no DW_AT_sibling
+ attribute. */
+ goto no_sibling_attr;
+ default:
+ return (NULL);
+ }
+
+ /* Reset *has_die_child to indicate children skipped. */
+ *has_die_child = false;
+
+ /* A value beyond die_info_end indicates an error. Exactly
+ at die_info_end means 1-past-cu-end and simply means we
+ are at the end, do not return NULL. Higher level code
+ will detect that we are at the end. */
+ if (cu_info_start + offset > die_info_end) {
+ /* Error case, bad DWARF. */
+ return (NULL);
+ }
+ /* At or before end-of-cu */
+ return (cu_info_start + offset);
+ }
+
+ no_sibling_attr:
+ if (attr_form != 0) {
+ info_ptr += _dwarf_get_size_of_val(cu_context->cc_dbg,
+ attr_form,
+ cu_context->cc_address_size,
+ info_ptr,
+ cu_context->cc_length_size);
+ /* It is ok for info_ptr == die_info_end, as we will test
+ later before using a too-large info_ptr */
+ if (info_ptr > die_info_end) {
+ /* More than one-past-end indicates a bug somewhere,
+ likely bad dwarf generation. */
+ return (NULL);
+ }
+ }
+ } while (attr != 0 || attr_form != 0);
+
+ return (info_ptr);
+}
+
+
+/*
+ Given a Dwarf_Debug dbg, and a Dwarf_Die die, it returns
+ a Dwarf_Die for the sibling of die. In case die is NULL,
+ it returns (thru ptr) a Dwarf_Die for the first die in the current
+ cu in dbg. Returns DW_DLV_ERROR on error.
+
+ It is assumed that every sibling chain including those with
+ only one element is terminated with a NULL die, except a
+ chain with only a NULL die.
+
+ The algorithm moves from one die to the adjacent one. It
+ returns when the depth of children it sees equals the number
+ of sibling chain terminations. A single count, child_depth
+ is used to track the depth of children and sibling terminations
+ encountered. Child_depth is incremented when a die has the
+ Has-Child flag set unless the child happens to be a NULL die.
+ Child_depth is decremented when a die has Has-Child false,
+ and the adjacent die is NULL. Algorithm returns when
+ child_depth is 0.
+
+ **NOTE: Do not modify input die, since it is used at the end.
+*/
+int
+dwarf_siblingof(Dwarf_Debug dbg,
+ Dwarf_Die die,
+ Dwarf_Die * caller_ret_die, Dwarf_Error * error)
+{
+ Dwarf_Die ret_die = 0;
+ Dwarf_Byte_Ptr die_info_ptr = 0;
+ Dwarf_Byte_Ptr cu_info_start = 0;
+
+ /* die_info_end points 1-past end of die (once set) */
+ Dwarf_Byte_Ptr die_info_end = 0;
+ Dwarf_Word abbrev_code = 0;
+ Dwarf_Unsigned utmp = 0;
+
+
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ if (die == NULL) {
+ /* Find root die of cu */
+ /* die_info_end is untouched here, need not be set in this
+ branch. */
+ Dwarf_Off off2;
+
+ /* If we've not loaded debug_info, de_cu_context will be NULL,
+ so no need to laod */
+
+ if (dbg->de_cu_context == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_DBG_NO_CU_CONTEXT);
+ return (DW_DLV_ERROR);
+ }
+
+ off2 = dbg->de_cu_context->cc_debug_info_offset;
+ die_info_ptr = dbg->de_debug_info.dss_data +
+ off2 + _dwarf_length_of_cu_header(dbg, off2);
+ } else {
+ /* Find sibling die. */
+ Dwarf_Bool has_child = false;
+ Dwarf_Sword child_depth = 0;
+
+ /* We cannot have a legal die unless debug_info was loaded, so
+ no need to load debug_info here. */
+ CHECK_DIE(die, DW_DLV_ERROR);
+
+ die_info_ptr = die->di_debug_info_ptr;
+ if (*die_info_ptr == 0) {
+ return (DW_DLV_NO_ENTRY);
+ }
+ cu_info_start = dbg->de_debug_info.dss_data +
+ die->di_cu_context->cc_debug_info_offset;
+ die_info_end = cu_info_start + die->di_cu_context->cc_length +
+ die->di_cu_context->cc_length_size +
+ die->di_cu_context->cc_extension_size;
+
+ if ((*die_info_ptr) == 0) {
+ return (DW_DLV_NO_ENTRY);
+ }
+ child_depth = 0;
+ do {
+ die_info_ptr = _dwarf_next_die_info_ptr(die_info_ptr,
+ die->di_cu_context,
+ die_info_end,
+ cu_info_start, true,
+ &has_child);
+ if (die_info_ptr == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_NEXT_DIE_PTR_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ /* die_info_end is one past end. Do not read it!
+ A test for ``!= die_info_end'' would work as well,
+ but perhaps < reads more like the meaning. */
+ if(die_info_ptr < die_info_end) {
+ if ((*die_info_ptr) == 0 && has_child) {
+ die_info_ptr++;
+ has_child = false;
+ }
+ }
+
+ /* die_info_ptr can be one-past-end. */
+ if ((die_info_ptr == die_info_end) ||
+ ((*die_info_ptr) == 0)) {
+ for (; child_depth > 0 && *die_info_ptr == 0;
+ child_depth--, die_info_ptr++);
+ } else {
+ child_depth = has_child ? child_depth + 1 : child_depth;
+ }
+
+ } while (child_depth != 0);
+ }
+
+ /* die_info_ptr > die_info_end is really a bug (possibly in dwarf
+ generation)(but we are past end, no more DIEs here), whereas
+ die_info_ptr == die_info_end means 'one past end, no more DIEs
+ here'. */
+ if (die != NULL && die_info_ptr >= die_info_end) {
+ return (DW_DLV_NO_ENTRY);
+ }
+
+ if ((*die_info_ptr) == 0) {
+ return (DW_DLV_NO_ENTRY);
+ }
+
+ ret_die = (Dwarf_Die) _dwarf_get_alloc(dbg, DW_DLA_DIE, 1);
+ if (ret_die == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ ret_die->di_debug_info_ptr = die_info_ptr;
+ ret_die->di_cu_context =
+ die == NULL ? dbg->de_cu_context : die->di_cu_context;
+
+ DECODE_LEB128_UWORD(die_info_ptr, utmp);
+ abbrev_code = (Dwarf_Word) utmp;
+ if (abbrev_code == 0) {
+ /* Zero means a null DIE */
+ dwarf_dealloc(dbg, ret_die, DW_DLA_DIE);
+ return (DW_DLV_NO_ENTRY);
+ }
+ ret_die->di_abbrev_code = abbrev_code;
+ ret_die->di_abbrev_list =
+ _dwarf_get_abbrev_for_code(ret_die->di_cu_context, abbrev_code);
+ if (ret_die->di_abbrev_list == NULL || (die == NULL &&
+ ret_die->di_abbrev_list->
+ ab_tag !=
+ DW_TAG_compile_unit)) {
+ dwarf_dealloc(dbg, ret_die, DW_DLA_DIE);
+ _dwarf_error(dbg, error, DW_DLE_FIRST_DIE_NOT_CU);
+ return (DW_DLV_ERROR);
+ }
+
+ *caller_ret_die = ret_die;
+ return (DW_DLV_OK);
+}
+
+
+int
+dwarf_child(Dwarf_Die die,
+ Dwarf_Die * caller_ret_die, Dwarf_Error * error)
+{
+ Dwarf_Byte_Ptr die_info_ptr = 0;
+
+ /* die_info_end points one-past-end of die area. */
+ Dwarf_Byte_Ptr die_info_end = 0;
+ Dwarf_Die ret_die = 0;
+ Dwarf_Bool has_die_child = 0;
+ Dwarf_Debug dbg;
+ Dwarf_Word abbrev_code = 0;
+ Dwarf_Unsigned utmp = 0;
+
+
+ CHECK_DIE(die, DW_DLV_ERROR);
+ dbg = die->di_cu_context->cc_dbg;
+ die_info_ptr = die->di_debug_info_ptr;
+
+ /* NULL die has no child. */
+ if ((*die_info_ptr) == 0)
+ return (DW_DLV_NO_ENTRY);
+
+ die_info_end = dbg->de_debug_info.dss_data +
+ die->di_cu_context->cc_debug_info_offset +
+ die->di_cu_context->cc_length +
+ die->di_cu_context->cc_length_size +
+ die->di_cu_context->cc_extension_size;
+
+ die_info_ptr =
+ _dwarf_next_die_info_ptr(die_info_ptr, die->di_cu_context,
+ die_info_end, NULL, false,
+ &has_die_child);
+ if (die_info_ptr == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_NEXT_DIE_PTR_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ if (!has_die_child)
+ return (DW_DLV_NO_ENTRY);
+
+ ret_die = (Dwarf_Die) _dwarf_get_alloc(dbg, DW_DLA_DIE, 1);
+ if (ret_die == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ ret_die->di_debug_info_ptr = die_info_ptr;
+ ret_die->di_cu_context = die->di_cu_context;
+
+ DECODE_LEB128_UWORD(die_info_ptr, utmp);
+ abbrev_code = (Dwarf_Word) utmp;
+ if (abbrev_code == 0) {
+ /* We have arrived at a null DIE, at the end of a CU or the end
+ of a list of siblings. */
+ *caller_ret_die = 0;
+ dwarf_dealloc(dbg, ret_die, DW_DLA_DIE);
+ return DW_DLV_NO_ENTRY;
+ }
+ ret_die->di_abbrev_code = abbrev_code;
+ ret_die->di_abbrev_list =
+ _dwarf_get_abbrev_for_code(die->di_cu_context, abbrev_code);
+ if (ret_die->di_abbrev_list == NULL) {
+ dwarf_dealloc(dbg, ret_die, DW_DLA_DIE);
+ _dwarf_error(dbg, error, DW_DLE_DIE_BAD);
+ return (DW_DLV_ERROR);
+ }
+
+ *caller_ret_die = ret_die;
+ return (DW_DLV_OK);
+}
+
+/*
+ Given a (global, not cu_relative) die offset, this returns
+ a pointer to a DIE thru *new_die.
+ It is up to the caller to do a
+ dwarf_dealloc(dbg,*new_die,DW_DLE_DIE);
+*/
+int
+dwarf_offdie(Dwarf_Debug dbg,
+ Dwarf_Off offset, Dwarf_Die * new_die, Dwarf_Error * error)
+{
+ Dwarf_CU_Context cu_context = 0;
+ Dwarf_Off new_cu_offset = 0;
+ Dwarf_Die die = 0;
+ Dwarf_Byte_Ptr info_ptr = 0;
+ Dwarf_Unsigned abbrev_code = 0;
+ Dwarf_Unsigned utmp = 0;
+
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ cu_context = _dwarf_find_CU_Context(dbg, offset);
+ if (cu_context == NULL)
+ cu_context = _dwarf_find_offdie_CU_Context(dbg, offset);
+
+ if (cu_context == NULL) {
+ int res = _dwarf_load_debug_info(dbg, error);
+
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ if (dbg->de_offdie_cu_context_end != NULL) {
+ Dwarf_CU_Context lcu_context =
+ dbg->de_offdie_cu_context_end;
+ new_cu_offset =
+ lcu_context->cc_debug_info_offset +
+ lcu_context->cc_length +
+ lcu_context->cc_length_size +
+ lcu_context->cc_extension_size;
+ }
+
+
+ do {
+ if ((new_cu_offset +
+ _dwarf_length_of_cu_header_simple(dbg)) >=
+ dbg->de_debug_info.dss_size) {
+ _dwarf_error(dbg, error, DW_DLE_OFFSET_BAD);
+ return (DW_DLV_ERROR);
+ }
+
+ cu_context =
+ _dwarf_make_CU_Context(dbg, new_cu_offset, error);
+ if (cu_context == NULL) {
+ /* Error if CU Context could not be made. Since
+ _dwarf_make_CU_Context has already registered an
+ error we do not do that here: we let the lower error
+ pass thru. */
+
+ return (DW_DLV_ERROR);
+ }
+
+ if (dbg->de_offdie_cu_context == NULL) {
+ dbg->de_offdie_cu_context = cu_context;
+ dbg->de_offdie_cu_context_end = cu_context;
+ } else {
+ dbg->de_offdie_cu_context_end->cc_next = cu_context;
+ dbg->de_offdie_cu_context_end = cu_context;
+ }
+
+ new_cu_offset = new_cu_offset + cu_context->cc_length +
+ cu_context->cc_length_size;
+
+ } while (offset >= new_cu_offset);
+ }
+
+ die = (Dwarf_Die) _dwarf_get_alloc(dbg, DW_DLA_DIE, 1);
+ if (die == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ die->di_cu_context = cu_context;
+
+ info_ptr = dbg->de_debug_info.dss_data + offset;
+ die->di_debug_info_ptr = info_ptr;
+ DECODE_LEB128_UWORD(info_ptr, utmp);
+ abbrev_code = utmp;
+ if (abbrev_code == 0) {
+ /* we are at a null DIE (or there is a bug). */
+ *new_die = 0;
+ dwarf_dealloc(dbg, die, DW_DLA_DIE);
+ return DW_DLV_NO_ENTRY;
+ }
+ die->di_abbrev_code = abbrev_code;
+ die->di_abbrev_list =
+ _dwarf_get_abbrev_for_code(cu_context, abbrev_code);
+ if (die->di_abbrev_list == NULL) {
+ dwarf_dealloc(dbg, die, DW_DLA_DIE);
+ _dwarf_error(dbg, error, DW_DLE_DIE_ABBREV_LIST_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ *new_die = die;
+ return (DW_DLV_OK);
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_die_deliv.h b/usr/src/lib/libdwarf/common/dwarf_die_deliv.h
new file mode 100644
index 0000000000..f1ecb153ba
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_die_deliv.h
@@ -0,0 +1,57 @@
+/*
+
+ Copyright (C) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2008-2010 David Anderson. 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 struct holds information about a abbreviation.
+ It is put in the hash table for abbreviations for
+ a compile-unit.
+*/
+struct Dwarf_Abbrev_List_s {
+
+ Dwarf_Unsigned ab_code;
+ Dwarf_Half ab_tag;
+ Dwarf_Half ab_has_child;
+
+ /*
+ Points to start of attribute and form pairs in the .debug_abbrev
+ section for the abbrev. */
+ Dwarf_Byte_Ptr ab_abbrev_ptr;
+
+ struct Dwarf_Abbrev_List_s *ab_next;
+};
diff --git a/usr/src/lib/libdwarf/common/dwarf_elf_access.c b/usr/src/lib/libdwarf/common/dwarf_elf_access.c
new file mode 100644
index 0000000000..6caa64a758
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_elf_access.c
@@ -0,0 +1,976 @@
+/*
+ Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright 2007-2010 Sun Microsystems, Inc. All rights reserved.
+ Portions Copyright 2008-2010 Arxan Technologies, Inc. All Rights Reserved.
+ Portions Copyright 2009-2010 David Anderson. All rights reserved.
+ Portions Copyright 2009-2010 Novell 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
+
+*/
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include "dwarf_elf_access.h"
+
+#ifdef HAVE_ELF_H
+#include <elf.h>
+#endif
+#ifdef HAVE_LIBELF_H
+#include <libelf.h>
+#else
+#ifdef HAVE_LIBELF_LIBELF_H
+#include <libelf/libelf.h>
+#endif
+#endif
+
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define FALSE 0
+#define TRUE 1
+
+#ifndef EM_MIPS
+/* This is the standard elf value EM_MIPS. */
+#define EM_MIPS 8
+#endif
+
+
+#ifdef HAVE_ELF64_GETEHDR
+extern Elf64_Ehdr *elf64_getehdr(Elf *);
+#endif
+#ifdef HAVE_ELF64_GETSHDR
+extern Elf64_Shdr *elf64_getshdr(Elf_Scn *);
+#endif
+#ifdef WORDS_BIGENDIAN
+#define WRITE_UNALIGNED(dbg,dest,source, srclength,len_out) \
+ { \
+ dbg->de_copy_word(dest, \
+ ((char *)source) +srclength-len_out, \
+ len_out) ; \
+ }
+
+
+#else /* LITTLE ENDIAN */
+
+#define WRITE_UNALIGNED(dbg,dest,source, srclength,len_out) \
+ { \
+ dbg->de_copy_word( (dest) , \
+ ((char *)source) , \
+ len_out) ; \
+ }
+#endif
+
+
+
+typedef struct {
+ dwarf_elf_handle elf;
+ int is_64bit;
+ Dwarf_Small length_size;
+ Dwarf_Small pointer_size;
+ Dwarf_Unsigned section_count;
+ Dwarf_Endianness endianness;
+ Dwarf_Small machine;
+ int libdwarf_owns_elf;
+ Elf32_Ehdr *ehdr32;
+
+#ifdef HAVE_ELF64_GETEHDR
+ Elf64_Ehdr *ehdr64;
+#endif
+ /* Elf symtab and its strtab. Initialized at first
+ call to do relocations, the actual data is in the Dwarf_Debug
+ struct, not allocated locally here. */
+ struct Dwarf_Section_s *symtab;
+ struct Dwarf_Section_s *strtab;
+
+} dwarf_elf_object_access_internals_t;
+
+struct Dwarf_Elf_Rela {
+ Dwarf_ufixed64 r_offset;
+ /*Dwarf_ufixed64 r_info; */
+ Dwarf_ufixed64 r_type;
+ Dwarf_ufixed64 r_symidx;
+ Dwarf_ufixed64 r_addend;
+};
+
+
+static int dwarf_elf_object_access_load_section(void* obj_in,
+ Dwarf_Half section_index,
+ Dwarf_Small** section_data,
+ int* error);
+
+/*
+ dwarf_elf_object_access_internals_init()
+ */
+static int
+dwarf_elf_object_access_internals_init(void* obj_in,
+ dwarf_elf_handle elf,
+ int* error)
+{
+ dwarf_elf_object_access_internals_t*obj =
+ (dwarf_elf_object_access_internals_t*)obj_in;
+ char *ehdr_ident = 0;
+ Dwarf_Half machine = 0;
+ obj->elf = elf;
+
+ if ((ehdr_ident = elf_getident(elf, NULL)) == NULL) {
+ *error = DW_DLE_ELF_GETIDENT_ERROR;
+ return DW_DLV_ERROR;
+ }
+
+ obj->is_64bit = (ehdr_ident[EI_CLASS] == ELFCLASS64);
+
+
+ if(ehdr_ident[EI_DATA] == ELFDATA2LSB){
+ obj->endianness = DW_OBJECT_LSB;
+ }
+ else if(ehdr_ident[EI_DATA] == ELFDATA2MSB){
+ obj->endianness = DW_OBJECT_MSB;
+ }
+
+ if (obj->is_64bit) {
+#ifdef HAVE_ELF64_GETEHDR
+ obj->ehdr64 = elf64_getehdr(elf);
+ if (obj->ehdr64 == NULL) {
+ *error = DW_DLE_ELF_GETEHDR_ERROR;
+ return DW_DLV_ERROR;
+ }
+ obj->section_count = obj->ehdr64->e_shnum;
+ machine = obj->ehdr64->e_machine;
+ obj->machine = machine;
+#else
+ *error = DW_DLE_NO_ELF64_SUPPORT;
+ return DW_DLV_ERROR;
+#endif
+ }
+ else {
+ obj->ehdr32 = elf32_getehdr(elf);
+ if (obj->ehdr32 == NULL) {
+ *error = DW_DLE_ELF_GETEHDR_ERROR;
+ return DW_DLV_ERROR;
+ }
+ obj->section_count = obj->ehdr32->e_shnum;
+ machine = obj->ehdr32->e_machine;
+ obj->machine = machine;
+ }
+
+ /* The following length_size is Not Too Significant. Only used
+ one calculation, and an approximate one at that. */
+ obj->length_size = obj->is_64bit ? 8 : 4;
+ obj->pointer_size = obj->is_64bit ? 8 : 4;
+
+ if (obj->is_64bit && machine != EM_MIPS) {
+ /* MIPS/IRIX makes pointer size and length size 8 for -64.
+ Other platforms make length 4 always. */
+ /* 4 here supports 32bit-offset dwarf2, as emitted by cygnus
+ tools, and the dwarfv2.1 64bit extension setting.
+ This is not the same as the size-of-an-offset, which
+ is 4 in 32bit dwarf and 8 in 64bit dwarf. */
+ obj->length_size = 4;
+ }
+ return DW_DLV_OK;
+}
+
+/*
+ dwarf_elf_object_access_get_byte_order
+ */
+static
+Dwarf_Endianness
+dwarf_elf_object_access_get_byte_order(void* obj_in)
+{
+ dwarf_elf_object_access_internals_t*obj =
+ (dwarf_elf_object_access_internals_t*)obj_in;
+ return obj->endianness;
+}
+
+/*
+ dwarf_elf_object_access_get_section_count()
+ */
+static
+Dwarf_Unsigned
+dwarf_elf_object_access_get_section_count(void * obj_in)
+{
+ dwarf_elf_object_access_internals_t*obj =
+ (dwarf_elf_object_access_internals_t*)obj_in;
+ return obj->section_count;
+}
+
+
+/*
+ dwarf_elf_object_access_get_section()
+ */
+static
+int
+dwarf_elf_object_access_get_section_info(
+ void* obj_in,
+ Dwarf_Half section_index,
+ Dwarf_Obj_Access_Section* ret_scn,
+ int* error)
+{
+ dwarf_elf_object_access_internals_t*obj =
+ (dwarf_elf_object_access_internals_t*)obj_in;
+
+ Elf32_Shdr *shdr32 = 0;
+
+#ifdef HAVE_ELF64_GETSHDR
+ Elf64_Shdr *shdr64 = 0;
+#endif
+ Elf_Scn *scn = 0;
+
+
+ scn = elf_getscn(obj->elf, section_index);
+ if (scn == NULL) {
+ *error = DW_DLE_MDE;
+ return DW_DLV_ERROR;
+ }
+ if (obj->is_64bit) {
+#ifdef HAVE_ELF64_GETSHDR
+ shdr64 = elf64_getshdr(scn);
+ if (shdr64 == NULL) {
+ *error = DW_DLE_ELF_GETSHDR_ERROR;
+ return DW_DLV_ERROR;
+ }
+
+ ret_scn->size = shdr64->sh_size;
+ ret_scn->addr = shdr64->sh_addr;
+ ret_scn->link = shdr64->sh_link;
+
+ ret_scn->name = elf_strptr(obj->elf, obj->ehdr64->e_shstrndx,
+ shdr64->sh_name);
+ if(ret_scn->name == NULL) {
+ *error = DW_DLE_ELF_STRPTR_ERROR;
+ return DW_DLV_ERROR;
+ }
+ return DW_DLV_OK;
+#else
+ *error = DW_DLE_MISSING_ELF64_SUPPORT;
+ return DW_DLV_ERROR;
+#endif /* HAVE_ELF64_GETSHDR */
+ }
+ if ((shdr32 = elf32_getshdr(scn)) == NULL) {
+ *error = DW_DLE_ELF_GETSHDR_ERROR;
+ return DW_DLV_ERROR;
+ }
+
+ ret_scn->size = shdr32->sh_size;
+ ret_scn->addr = shdr32->sh_addr;
+ ret_scn->link = shdr32->sh_link;
+
+ ret_scn->name = elf_strptr(obj->elf, obj->ehdr32->e_shstrndx,
+ shdr32->sh_name);
+ if (ret_scn->name == NULL) {
+ *error = DW_DLE_ELF_STRPTR_ERROR;
+ return DW_DLV_ERROR;
+ }
+ return DW_DLV_OK;
+}
+
+/*
+ dwarf_elf_object_access_get_length_size
+ */
+static
+Dwarf_Small
+dwarf_elf_object_access_get_length_size(void* obj_in)
+{
+ dwarf_elf_object_access_internals_t*obj =
+ (dwarf_elf_object_access_internals_t*)obj_in;
+ return obj->length_size;
+}
+
+/*
+ dwarf_elf_object_access_get_pointer_size
+ */
+static
+Dwarf_Small
+dwarf_elf_object_access_get_pointer_size(void* obj_in)
+{
+ dwarf_elf_object_access_internals_t*obj =
+ (dwarf_elf_object_access_internals_t*)obj_in;
+ return obj->pointer_size;
+}
+
+#define MATCH_REL_SEC(i_,s_,r_) \
+if(i_ == s_.dss_index) { \
+ *r_ = &s_; \
+ return DW_DLV_OK; \
+}
+
+static int
+find_section_to_relocate(Dwarf_Debug dbg,Dwarf_Half section_index,
+ struct Dwarf_Section_s **relocatablesec, int *error)
+{
+ MATCH_REL_SEC(section_index,dbg->de_debug_info,relocatablesec);
+ MATCH_REL_SEC(section_index,dbg->de_debug_abbrev,relocatablesec);
+ MATCH_REL_SEC(section_index,dbg->de_debug_line,relocatablesec);
+ MATCH_REL_SEC(section_index,dbg->de_debug_loc,relocatablesec);
+ MATCH_REL_SEC(section_index,dbg->de_debug_aranges,relocatablesec);
+ MATCH_REL_SEC(section_index,dbg->de_debug_macinfo,relocatablesec);
+ MATCH_REL_SEC(section_index,dbg->de_debug_pubnames,relocatablesec);
+ MATCH_REL_SEC(section_index,dbg->de_debug_ranges,relocatablesec);
+ MATCH_REL_SEC(section_index,dbg->de_debug_frame,relocatablesec);
+ MATCH_REL_SEC(section_index,dbg->de_debug_frame_eh_gnu,relocatablesec);
+ MATCH_REL_SEC(section_index,dbg->de_debug_pubtypes,relocatablesec);
+ MATCH_REL_SEC(section_index,dbg->de_debug_funcnames,relocatablesec);
+ MATCH_REL_SEC(section_index,dbg->de_debug_typenames,relocatablesec);
+ MATCH_REL_SEC(section_index,dbg->de_debug_varnames,relocatablesec);
+ MATCH_REL_SEC(section_index,dbg->de_debug_weaknames,relocatablesec);
+ /* dbg-> de_debug_str,syms); */
+ /* de_elf_symtab,syms); */
+ /* de_elf_strtab,syms); */
+ *error = DW_DLE_RELOC_SECTION_MISMATCH;
+ return DW_DLV_ERROR;
+
+}
+#undef MATCH_REL_SEC
+
+static void
+get_rela_elf32(Dwarf_Small *data, unsigned int i,
+ int endianness,
+ int machine, struct Dwarf_Elf_Rela *relap)
+{
+ Elf32_Rela *relp = (Elf32_Rela*)(data + (i * sizeof(Elf32_Rela)));
+ relap->r_offset = relp->r_offset;
+ /*
+ relap->r_info = relp->r_info;
+ */
+ relap->r_type = ELF32_R_TYPE(relp->r_info);
+ relap->r_symidx = ELF32_R_SYM(relp->r_info);
+ relap->r_addend = relp->r_addend;
+}
+
+static void
+get_rela_elf64(Dwarf_Small *data, unsigned int i,
+ int endianness,
+ int machine,struct Dwarf_Elf_Rela *relap)
+{
+#ifdef HAVE_ELF64_RELA
+ Elf64_Rela * relp = (Elf64_Rela*)(data + (i * sizeof(Elf64_Rela)));
+ relap->r_offset = relp->r_offset;
+ /*
+ relap->r_info = relp->r_info;
+ */
+ if(machine == EM_MIPS && endianness == DW_OBJECT_LSB ) {
+ /* This is really wierd. Treat this very specially.
+ The Elf64 LE MIPS object used for
+ testing (that has rela) wants the
+ values as sym ssym type3 type2 type, treating
+ each value as independent value. But libelf xlate
+ treats it as something else so we fudge here.
+ It is unclear
+ how to precisely characterize where these relocations
+ were used.
+ SGI MIPS on IRIX never used .rela relocations.
+ The BE 64bit elf MIPS test object with rela uses traditional
+ elf relocation layouts, not this special case. */
+#define ELF64MIPS_REL_SYM(i) ((i) & 0xffffffff)
+#define ELF64MIPS_REL_TYPE(i) ((i >> 56) &0xff)
+ /* We ignore the special TYPE2 and TYPE3, they should be
+ value R_MIPS_NONE in rela. */
+ relap->r_type = ELF64MIPS_REL_TYPE(relp->r_info);
+ relap->r_symidx = ELF64MIPS_REL_SYM(relp->r_info);
+#undef MIPS64SYM
+#undef MIPS64TYPE
+ } else
+ {
+ relap->r_type = ELF64_R_TYPE(relp->r_info);
+ relap->r_symidx = ELF64_R_SYM(relp->r_info);
+ }
+ relap->r_addend = relp->r_addend;
+#endif
+}
+
+static void
+get_relocations_array(Dwarf_Bool is_64bit,
+ int endianness,
+ int machine,
+ Dwarf_Small *data,
+ unsigned int num_relocations,
+ struct Dwarf_Elf_Rela *relap)
+{
+ unsigned int i = 0;
+ void (*get_relocations)(Dwarf_Small *data, unsigned int i,
+ int endianness,
+ int machine,
+ struct Dwarf_Elf_Rela *relap);
+
+ /* Handle 32/64 bit issue
+ */
+ if (is_64bit) {
+ get_relocations = get_rela_elf64;
+ } else {
+ get_relocations = get_rela_elf32;
+ }
+
+ for (i=0; i < num_relocations; i++) {
+ get_relocations(data, i,endianness,machine, &(relap[i]));
+ }
+
+}
+
+static int
+get_relocation_entries(Dwarf_Bool is_64bit,
+ int endianness,
+ int machine,
+ Dwarf_Small *relocation_section,
+ Dwarf_Unsigned relocation_section_size,
+ struct Dwarf_Elf_Rela **relas,
+ unsigned int *nrelas,
+ int *error)
+{
+ unsigned int relocation_size = 0;
+
+ if (is_64bit) {
+#ifdef HAVE_ELF64_RELA
+ relocation_size = sizeof(Elf64_Rela);
+#else
+ *error = DW_DLE_MISSING_ELF64_SUPPORT;
+ return DW_DLV_ERROR;
+#endif
+ } else {
+ relocation_size = sizeof(Elf32_Rela);
+ }
+
+ if (relocation_section == NULL) {
+ *error = DW_DLE_RELOC_SECTION_PTR_NULL;
+ return(DW_DLV_ERROR);
+ }
+
+ if ((relocation_section_size != 0)) {
+ size_t bytescount = 0;
+ if(relocation_section_size%relocation_size) {
+ *error = DW_DLE_RELOC_SECTION_LENGTH_ODD;
+ return DW_DLV_ERROR;
+ }
+ *nrelas = relocation_section_size/relocation_size;
+ bytescount = (*nrelas) * sizeof(struct Dwarf_Elf_Rela);
+ *relas = malloc(bytescount);
+ if (!*relas) {
+ *error = DW_DLE_MAF;
+ return(DW_DLV_ERROR);
+ }
+ memset(*relas,0,bytescount);
+ get_relocations_array(is_64bit,endianness,machine, relocation_section,
+ *nrelas, *relas);
+ }
+ return(DW_DLV_OK);
+}
+
+static Dwarf_Bool
+is_32bit_abs_reloc(unsigned int type, Dwarf_Half machine)
+{
+ Dwarf_Bool r = 0;
+ switch (machine) {
+#if defined(EM_MIPS) && defined (R_MIPS_32)
+ case EM_MIPS:
+ r = (type == R_MIPS_32);
+ break;
+#endif
+#if defined(EM_SPARC32PLUS) && defined (R_SPARC_UA32)
+ case EM_SPARC32PLUS:
+ r = (type == R_SPARC_UA32);
+ break;
+#endif
+#if defined(EM_SPARCV9) && defined (R_SPARC_UA32)
+ case EM_SPARCV9:
+ r = (type == R_SPARC_UA32);
+ break;
+#endif
+#if defined(EM_SPARC) && defined (R_SPARC_UA32)
+ case EM_SPARC:
+ r = (type == R_SPARC_UA32);
+ break;
+#endif
+#if defined(EM_386) && defined (R_386_32)
+ case EM_386:
+ r = (type == R_386_32);
+ break;
+#endif
+#if defined(EM_IA_64) && defined (R_IA64_SECREL32LSB)
+ case EM_IA_64:
+ r = (type == R_IA64_SECREL32LSB);
+ break;
+#endif
+#if defined(EM_PPC64) && defined (R_PPC64_ADDR32)
+ case EM_PPC64:
+ r = (type == R_PPC64_ADDR32);
+ break;
+#endif
+#if defined(EM_PPC) && defined (R_PPC_ADDR32)
+ case EM_PPC:
+ r = (type == R_PPC_ADDR32);
+ break;
+#endif
+#if defined(EM_S390) && defined (R_390_32)
+ case EM_S390:
+ r = (type == R_390_32);
+ break;
+#endif
+#if defined(EM_X86_64) && defined (R_X86_64_32)
+ case EM_X86_64:
+ r = (type == R_X86_64_32);
+ break;
+#endif
+ }
+ return r;
+}
+
+static Dwarf_Bool
+is_64bit_abs_reloc(unsigned int type, Dwarf_Half machine)
+{
+ Dwarf_Bool r = 0;
+ switch (machine) {
+#if defined(EM_MIPS) && defined (R_MIPS_64)
+ case EM_MIPS:
+ r = (type == R_MIPS_64);
+ break;
+#endif
+#if defined(EM_SPARC32PLUS) && defined (R_SPARC_UA64)
+ case EM_SPARC32PLUS:
+ r = (type == R_SPARC_UA64);
+ break;
+#endif
+#if defined(EM_SPARCV9) && defined (R_SPARC_UA64)
+ case EM_SPARCV9:
+ r = (type == R_SPARC_UA64);
+ break;
+#endif
+#if defined(EM_SPARC) && defined (R_SPARC_UA64)
+ case EM_SPARC:
+ r = (type == R_SPARC_UA64);
+ break;
+#endif
+#if defined(EM_IA_64) && defined (R_IA64_SECREL32LSB)
+ case EM_IA_64:
+ r = (type == R_IA64_DIR64LSB);
+ break;
+#endif
+#if defined(EM_PPC64) && defined (R_PPC64_ADDR64)
+ case EM_PPC64:
+ r = (type == R_PPC64_ADDR64);
+ break;
+#endif
+#if defined(EM_S390) && defined (R_390_64)
+ case EM_S390:
+ r = (type == R_390_64);
+ break;
+#endif
+#if defined(EM_X86_64) && defined (R_X86_64_64)
+ case EM_X86_64:
+ r = (type == R_X86_64_64);
+ break;
+#endif
+ }
+ return r;
+}
+
+
+static void
+update_entry(Dwarf_Debug dbg,
+ Dwarf_Bool is_64bit, Dwarf_Endianness endianess,
+ Dwarf_Half machine, struct Dwarf_Elf_Rela *rela,
+ Dwarf_Small *target_section, Dwarf_Small *section_data)
+{
+ unsigned int type = 0;
+ unsigned int sym_idx = 0;
+#ifdef HAVE_ELF64_SYM
+ Elf64_Sym sym_buf;
+ Elf64_Sym *sym = 0;
+#else
+ Elf32_Sym sym_buf;
+ Elf32_Sym *sym = 0;
+#endif
+ Elf32_Sym *sym32 = 0;
+ Dwarf_ufixed64 offset = 0;
+ Dwarf_sfixed64 addend = 0;
+ Dwarf_Unsigned reloc_size = 0;
+
+
+ /* Dwarf_Elf_Rela dereferencing */
+ offset = rela->r_offset;
+ addend = rela->r_addend;
+ type = rela->r_type;
+ sym_idx = rela->r_symidx;
+
+ if (is_64bit) {
+#ifdef HAVE_ELF64_SYM
+ sym = &((Elf64_Sym*)section_data)[sym_idx];
+#endif
+ } else {
+ sym32 = &((Elf32_Sym*)section_data)[sym_idx];
+
+ /* Convert Elf32_Sym struct to Elf64_Sym struct. We point at
+ * an Elf64_Sym local variable (sym_buf) to allow us to use the
+ * same pointer (sym) for both 32-bit and 64-bit instances.
+ */
+ sym = &sym_buf;
+ sym->st_name = sym32->st_name;
+ sym->st_info = sym32->st_info;
+ sym->st_other = sym32->st_other;
+ sym->st_shndx = sym32->st_shndx;
+ sym->st_value = sym32->st_value;
+ sym->st_size = sym32->st_size;
+ }
+
+ /* Determine relocation size */
+ if (is_32bit_abs_reloc(type, machine)) {
+ reloc_size = 4;
+ } else if (is_64bit_abs_reloc(type, machine)) {
+ reloc_size = 8;
+ } else {
+ return;
+ }
+
+
+ {
+ /* Assuming we do not need to do a READ_UNALIGNED here
+ at target_section + offset and add its value to
+ outval. Some ABIs say no read (for example MIPS),
+ but if some do then which ones? */
+ Dwarf_Unsigned outval = sym->st_value + addend;
+ WRITE_UNALIGNED(dbg,target_section + offset,
+ &outval,sizeof(outval),reloc_size);
+ }
+}
+
+
+
+static int
+apply_rela_entries(Dwarf_Debug dbg,
+ Dwarf_Bool is_64bit,
+ Dwarf_Endianness endianess,
+ Dwarf_Half machine,
+ Dwarf_Small *target_section,
+ Dwarf_Small *symtab_section,
+ struct Dwarf_Elf_Rela *relas, unsigned int nrelas,
+ int *error)
+{
+ if ((target_section != NULL) && (relas != NULL)) {
+ unsigned int i;
+ for (i = 0; i < nrelas; i++) {
+ update_entry(dbg, is_64bit,
+ endianess,
+ machine,
+ &(relas)[i],
+ target_section,
+ symtab_section);
+ }
+ }
+ return DW_DLV_OK;
+}
+
+
+static int
+loop_through_relocations(
+ Dwarf_Debug dbg,
+ dwarf_elf_object_access_internals_t* obj,
+ struct Dwarf_Section_s *relocatablesec,
+ int *error)
+{
+ Dwarf_Small *target_section = 0;
+ Dwarf_Small *symtab_section = obj->symtab->dss_data;
+ Dwarf_Small *relocation_section = relocatablesec->dss_reloc_data;
+ Dwarf_Unsigned relocation_section_size =
+ relocatablesec->dss_reloc_size;
+ int ret = DW_DLV_ERROR;
+ struct Dwarf_Elf_Rela *relas = 0;
+ unsigned int nrelas = 0;
+ Dwarf_Small *mspace = 0;
+
+ ret = get_relocation_entries(obj->is_64bit,
+ obj->endianness,
+ obj->machine,
+ relocation_section,
+ relocation_section_size,
+ &relas, &nrelas, error);
+ if(ret != DW_DLV_OK) {
+ free(relas);
+ return ret;
+ }
+
+ /* Some systems read Elf in read-only memory via mmap or the like.
+ So the only safe thing is to copy the current data into
+ malloc space and refer to the malloc space instead of the
+ space returned by the elf library */
+ mspace = malloc(relocatablesec->dss_size);
+ if(!mspace) {
+ *error = DW_DLE_RELOC_SECTION_MALLOC_FAIL;
+ return DW_DLV_ERROR;
+ }
+ memcpy(mspace,relocatablesec->dss_data,relocatablesec->dss_size);
+ relocatablesec->dss_data = mspace;
+ target_section = relocatablesec->dss_data;
+ relocatablesec->dss_data_was_malloc = 1;
+
+ ret = apply_rela_entries(
+ dbg,
+ obj->is_64bit,
+ obj->endianness, obj->machine,
+ target_section,
+ symtab_section,
+ relas, nrelas, error);
+
+ free(relas);
+
+ return ret;
+}
+
+/*
+ Find the section data in dbg and find all the relevant
+ sections. Then do relocations.
+*/
+static int
+dwarf_elf_object_relocate_a_section(void* obj_in,
+ Dwarf_Half section_index,
+ Dwarf_Debug dbg,
+ int* error)
+{
+ int res = DW_DLV_ERROR;
+ dwarf_elf_object_access_internals_t*obj = 0;
+ struct Dwarf_Section_s * relocatablesec = 0;
+ if (section_index == 0) {
+ return DW_DLV_NO_ENTRY;
+ }
+ obj = (dwarf_elf_object_access_internals_t*)obj_in;
+
+ /* The section to relocate must already be loaded into memory. */
+ res = find_section_to_relocate(dbg, section_index,&relocatablesec,error);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+
+ /* Sun and possibly others do not always set sh_link in .debug_* sections.
+ So we cannot do full consistency checks. */
+ if(relocatablesec->dss_reloc_index == 0 ) {
+ /* Something is wrong. */
+ *error = DW_DLE_RELOC_SECTION_MISSING_INDEX;
+ return DW_DLV_ERROR;
+ }
+ /* Now load the relocations themselves. */
+ res = dwarf_elf_object_access_load_section(obj_in,
+ relocatablesec->dss_reloc_index,
+ &relocatablesec->dss_reloc_data, error);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+
+ /* Now get the symtab. */
+ if (!obj->symtab) {
+ obj->symtab = &dbg->de_elf_symtab;
+ obj->strtab = &dbg->de_elf_strtab;
+ }
+ if( obj->symtab->dss_index != relocatablesec->dss_reloc_link) {
+ /* Something is wrong. */
+ *error = DW_DLE_RELOC_MISMATCH_RELOC_INDEX;
+ return DW_DLV_ERROR;
+ }
+ if( obj->strtab->dss_index != obj->symtab->dss_link) {
+ /* Something is wrong. */
+ *error = DW_DLE_RELOC_MISMATCH_STRTAB_INDEX;
+ return DW_DLV_ERROR;
+ }
+ if(!obj->symtab->dss_data) {
+ /* Now load the symtab */
+ res = dwarf_elf_object_access_load_section(obj_in,
+ obj->symtab->dss_index,
+ &obj->symtab->dss_data, error);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+ }
+ if(! obj->strtab->dss_data) {
+ /* Now load the strtab */
+ res = dwarf_elf_object_access_load_section(obj_in,
+ obj->strtab->dss_index,
+ &obj->strtab->dss_data,error);
+ if(res != DW_DLV_OK){
+ return res;
+ }
+ }
+
+ /* We have all the data we need in memory. */
+ res = loop_through_relocations(dbg,obj,relocatablesec,error);
+
+ return res;
+}
+
+/*
+ dwarf_elf_object_access_load_section
+ */
+static int
+dwarf_elf_object_access_load_section(void* obj_in,
+ Dwarf_Half section_index,
+ Dwarf_Small** section_data,
+ int* error)
+{
+ dwarf_elf_object_access_internals_t*obj =
+ (dwarf_elf_object_access_internals_t*)obj_in;
+ if (section_index == 0) {
+ return DW_DLV_NO_ENTRY;
+ }
+
+ {
+ Elf_Scn *scn = 0;
+ Elf_Data *data = 0;
+
+ scn = elf_getscn(obj->elf, section_index);
+ if (scn == NULL) {
+ *error = DW_DLE_MDE;
+ return DW_DLV_ERROR;
+ }
+
+ /*
+ When using libelf as a producer, section data may be stored
+ in multiple buffers. In libdwarf however, we only use libelf
+ as a consumer (there is a dwarf producer API, but it doesn't
+ use libelf). Because of this, this single call to elf_getdata
+ will retrieve the entire section in a single contiguous
+ buffer. */
+ data = elf_getdata(scn, NULL);
+ if (data == NULL) {
+ *error = DW_DLE_MDE;
+ return DW_DLV_ERROR;
+ }
+ *section_data = data->d_buf;
+ }
+ return DW_DLV_OK;
+}
+
+
+/* dwarf_elf_access method table. */
+static const struct Dwarf_Obj_Access_Methods_s dwarf_elf_object_access_methods =
+{
+ dwarf_elf_object_access_get_section_info,
+ dwarf_elf_object_access_get_byte_order,
+ dwarf_elf_object_access_get_length_size,
+ dwarf_elf_object_access_get_pointer_size,
+ dwarf_elf_object_access_get_section_count,
+ dwarf_elf_object_access_load_section,
+ dwarf_elf_object_relocate_a_section
+};
+
+
+/*
+ Interface for the ELF object file implementation.
+ */
+int
+dwarf_elf_object_access_init(dwarf_elf_handle elf,
+ int libdwarf_owns_elf,
+ Dwarf_Obj_Access_Interface** ret_obj,
+ int *err)
+{
+ int res = 0;
+ dwarf_elf_object_access_internals_t *internals = 0;
+ Dwarf_Obj_Access_Interface *intfc = 0;
+
+ internals = malloc(sizeof(dwarf_elf_object_access_internals_t));
+ if(!internals) {
+ /* Impossible case, we hope. Give up. */
+ return DW_DLV_ERROR;
+ }
+ memset(internals,0,sizeof(*internals));
+ res = dwarf_elf_object_access_internals_init(internals, elf, err);
+ if(res != DW_DLV_OK){
+ free(internals);
+ return DW_DLV_ERROR;
+ }
+ internals->libdwarf_owns_elf = libdwarf_owns_elf;
+
+ intfc = malloc(sizeof(Dwarf_Obj_Access_Interface));
+ if(!intfc) {
+ /* Impossible case, we hope. Give up. */
+ free(internals);
+ return DW_DLV_ERROR;
+ }
+ /* Initialize the interface struct */
+ intfc->object = internals;
+ intfc->methods = &dwarf_elf_object_access_methods;
+
+ *ret_obj = intfc;
+ return DW_DLV_OK;
+}
+
+
+
+/*
+ Clean up the Dwarf_Obj_Access_Interface returned by elf_access_init.
+ */
+void
+dwarf_elf_object_access_finish(Dwarf_Obj_Access_Interface* obj)
+{
+ if(!obj) {
+ return;
+ }
+ if(obj->object) {
+ dwarf_elf_object_access_internals_t *internals =
+ (dwarf_elf_object_access_internals_t *)obj->object;
+ if(internals->libdwarf_owns_elf){
+ elf_end(internals->elf);
+ }
+ }
+ free(obj->object);
+ free(obj);
+}
+
+/*
+ This function returns the Elf * pointer
+ associated with a Dwarf_Debug.
+
+ This function only makes sense if ELF is implied.
+ */
+int
+dwarf_get_elf(Dwarf_Debug dbg, dwarf_elf_handle * elf,
+ Dwarf_Error * error)
+{
+ struct Dwarf_Obj_Access_Interface_s * obj = 0;
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ obj = dbg->de_obj_file;
+ if(obj) {
+ dwarf_elf_object_access_internals_t *internals =
+ (dwarf_elf_object_access_internals_t*)obj->object;
+ if(internals->elf == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_FNO);
+ return (DW_DLV_ERROR);
+ }
+ *elf = internals->elf;
+ return DW_DLV_OK;
+
+ }
+ _dwarf_error(dbg, error, DW_DLE_FNO);
+ return DW_DLV_ERROR;
+}
+
+
diff --git a/usr/src/lib/libdwarf/common/dwarf_elf_access.h b/usr/src/lib/libdwarf/common/dwarf_elf_access.h
new file mode 100644
index 0000000000..fd52c17938
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_elf_access.h
@@ -0,0 +1,55 @@
+#ifndef _DWARF_ELF_PORT_H
+#define _DWARF_ELF_PORT_H
+/*
+
+ Copyright (C) 2008-2010 David Anderson. All rights reserved.
+ Portions Copyright 2008-2010 Arxan Technologies, 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
+
+*/
+
+
+
+/* ELF (usually libelf) object access for the generic object file interface */
+
+int
+dwarf_elf_object_access_init(dwarf_elf_handle elf ,
+ int libdwarf_owns_elf,
+ Dwarf_Obj_Access_Interface** ret_obj,
+ int *err );
+
+void
+dwarf_elf_object_access_finish(Dwarf_Obj_Access_Interface* obj );
+
+/* End ELF object access for the generic object file interface */
+
+
+#endif
diff --git a/usr/src/lib/libdwarf/common/dwarf_error.c b/usr/src/lib/libdwarf/common/dwarf_error.c
new file mode 100644
index 0000000000..7327529820
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_error.c
@@ -0,0 +1,410 @@
+/*
+
+ Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2008-2010 David Anderson. 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
+
+*/
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#ifdef HAVE_ELF_H
+#include <elf.h>
+#endif
+
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <stdlib.h>
+
+/* Array to hold string representation of errors. Any time a
+ define is added to the list in libdwarf.h, a string should be
+ added to this Array
+*/
+
+const char *_dwarf_errmsgs[] = {
+
+ "No error (0)\n",
+ "DW_DLE_VMM 1 dwarf format/library version mismatch",
+ "DW_DLE_MAP 2 memory map failure",
+ "DW_DLE_LEE 3 libelf error",
+ "DW_DLE_NDS 4 no debug section",
+ "DW_DLE_NLS 5 no line section ",
+ "DW_DLE_ID 6 invalid descriptor for query ",
+ "DW_DLE_IOF 7 I/O failure ",
+ "DW_DLE_MAF 8 memory allocation failure ",
+ "DW_DLE_IA 9 invalid argument ",
+ "DW_DLE_MDE 10 mangled debugging entry ",
+ "DW_DLE_MLE 11 mangled line number entry ",
+ "DW_DLE_FNO 12 file not open ",
+ "DW_DLE_FNR 13 file not a regular file ",
+ "DW_DLE_FWA 14 file open with wrong access ",
+ "DW_DLE_NOB 15 not an object file ",
+ "DW_DLE_MOF 16 mangled object file header ",
+ "DW_DLE_EOLL 17 end of location list entries ",
+ "DW_DLE_NOLL 18 no location list section ",
+ "DW_DLE_BADOFF 19 Invalid offset ",
+ "DW_DLE_EOS 20 end of section ",
+ "DW_DLE_ATRUNC 21 abbreviations section appears truncated",
+ "DW_DLE_BADBITC 22 Address size passed to dwarf bad",
+
+ "DW_DLE_DBG_ALLOC 23 Unable to malloc a Dwarf_Debug structure",
+ "DW_DLE_FSTAT_ERROR 24 The file fd passed to dwarf_init "
+ "cannot be fstat()ed",
+ "DW_DLE_FSTAT_MODE_ERROR 25 The file mode bits do not "
+ "indicate that the file being opened via "
+ "dwarf_init() is a normal file",
+ "DW_DLE_INIT_ACCESS_WRONG 26 A call to dwarf_init had an "
+ "access of other than DW_DLC_READ",
+ "DW_DLE_ELF_BEGIN_ERROR 27 a call to "
+ "elf_begin(... ELF_C_READ_MMAP... ) failed",
+ "DW_DLE_ELF_GETEHDR_ERROR 28 a call to "
+ "elf32_getehdr() or elf64_getehdr() failed",
+ "DW_DLE_ELF_GETSHDR_ERROR 29 a call to "
+ "elf32_getshdr() or elf64_getshdr() failed",
+ "DW_DLE_ELF_STRPTR_ERROR 30 a call to "
+ "elf_strptr() failed trying to get a section name",
+ "DW_DLE_DEBUG_INFO_DUPLICATE 31 Only one .debug_info "
+ "section is allowed",
+ "DW_DLE_DEBUG_INFO_NULL 32 .debug_info section present but "
+ "elf_getdata() failed or section is zero-length",
+ "DW_DLE_DEBUG_ABBREV_DUPLICATE 33 Only one .debug_abbrev "
+ "section is allowed",
+ "DW_DLE_DEBUG_ABBREV_NULL 34 .debug_abbrev section present but "
+ "elf_getdata() failed or section is zero-length",
+ "DW_DLE_DEBUG_ARANGES_DUPLICATE 35 Only one .debug_aranges "
+ "section is allowed",
+ "DW_DLE_DEBUG_ARANGES_NULL 36 .debug_aranges section present but "
+ "elf_getdata() failed or section is zero-length",
+ "DW_DLE_DEBUG_LINE_DUPLICATE 37 Only one .debug_line "
+ "section is allowed",
+ "DW_DLE_DEBUG_LINE_NULL (38) .debug_line section present but "
+ "elf_getdata() failed or section is zero-length",
+ "DW_DLE_DEBUG_LOC_DUPLICATE (39) Only one .debug_loc "
+ "section is allowed",
+ "DW_DLE_DEBUG_LOC_NULL (40) .debug_loc section present but "
+ "elf_getdata() failed or section is zero-length",
+ "DW_DLE_DEBUG_MACINFO_DUPLICATE (41) Only one .debug_macinfo "
+ "section is allowed",
+ "DW_DLE_DEBUG_MACINFO_NULL (42) .debug_macinfo section present but "
+ "elf_getdata() failed or section is zero-length",
+ "DW_DLE_DEBUG_PUBNAMES_DUPLICATE (43) Only one .debug_pubnames "
+ "section is allowed",
+ "DW_DLE_DEBUG_PUBNAMES_NULL (44) .debug_pubnames section present but "
+ "elf_getdata() failed or section is zero-length",
+ "DW_DLE_DEBUG_STR_DUPLICATE (45) Only one .debug_str "
+ "section is allowed",
+ "DW_DLE_DEBUG_STR_NULL (46) .debug_str section present but "
+ "elf_getdata() failed or section is zero-length",
+ "DW_DLE_CU_LENGTH_ERROR (47)",
+ "DW_DLE_VERSION_STAMP_ERROR (48)",
+ "DW_DLE_ABBREV_OFFSET_ERROR (49)",
+ "DW_DLE_ADDRESS_SIZE_ERROR (50)",
+ "DW_DLE_DEBUG_INFO_PTR_NULL (51)",
+ "DW_DLE_DIE_NULL (52)",
+ "DW_DLE_STRING_OFFSET_BAD (53)",
+ "DW_DLE_DEBUG_LINE_LENGTH_BAD (54)",
+ "DW_DLE_LINE_PROLOG_LENGTH_BAD (55)",
+ "DW_DLE_LINE_NUM_OPERANDS_BAD",
+ "DW_DLE_LINE_SET_ADDR_ERROR",
+ "DW_DLE_LINE_EXT_OPCODE_BAD",
+ "DW_DLE_DWARF_LINE_NULL",
+ "DW_DLE_INCL_DIR_NUM_BAD",
+ "DW_DLE_LINE_FILE_NUM_BAD",
+ "DW_DLE_ALLOC_FAIL",
+ "DW_DLE_NO_CALLBACK_FUNC",
+ "DW_DLE_SECT_ALLOC",
+ "DW_DLE_FILE_ENTRY_ALLOC",
+ "DW_DLE_LINE_ALLOC",
+ "DW_DLE_FPGM_ALLOC",
+ "DW_DLE_INCDIR_ALLOC",
+ "DW_DLE_STRING_ALLOC",
+ "DW_DLE_CHUNK_ALLOC",
+ "DW_DLE_BYTEOFF_ERR",
+ "DW_DLE_CIE_ALLOC",
+ "DW_DLE_FDE_ALLOC",
+ "DW_DLE_REGNO_OVFL",
+ "DW_DLE_CIE_OFFS_ALLOC",
+ "DW_DLE_WRONG_ADDRESS",
+ "DW_DLE_EXTRA_NEIGHBORS",
+ "DW_DLE_WRONG_TAG",
+ "DW_DLE_DIE_ALLOC",
+ "DW_DLE_PARENT_EXISTS",
+ "DW_DLE_DBG_NULL",
+ "DW_DLE_DEBUGLINE_ERROR",
+ "DW_DLE_DEBUGFRAME_ERROR",
+ "DW_DLE_DEBUGINFO_ERROR",
+ "DW_DLE_ATTR_ALLOC",
+ "DW_DLE_ABBREV_ALLOC",
+ "DW_DLE_OFFSET_UFLW",
+ "DW_DLE_ELF_SECT_ERR",
+ "DW_DLE_DEBUG_FRAME_LENGTH_BAD",
+ "DW_DLE_FRAME_VERSION_BAD",
+ "DW_DLE_CIE_RET_ADDR_REG_ERROR",
+ "DW_DLE_FDE_NULL",
+ "DW_DLE_FDE_DBG_NULL",
+ "DW_DLE_CIE_NULL",
+ "DW_DLE_CIE_DBG_NULL",
+ "DW_DLE_FRAME_TABLE_COL_BAD",
+ "DW_DLE_PC_NOT_IN_FDE_RANGE",
+ "DW_DLE_CIE_INSTR_EXEC_ERROR",
+ "DW_DLE_FRAME_INSTR_EXEC_ERROR",
+ "DW_DLE_FDE_PTR_NULL",
+ "DW_DLE_RET_OP_LIST_NULL",
+ "DW_DLE_LINE_CONTEXT_NULL",
+ "DW_DLE_DBG_NO_CU_CONTEXT",
+ "DW_DLE_DIE_NO_CU_CONTEXT",
+ "DW_DLE_FIRST_DIE_NOT_CU",
+ "DW_DLE_NEXT_DIE_PTR_NULL",
+ "DW_DLE_DEBUG_FRAME_DUPLICATE Only one .debug_frame "
+ "section is allowed",
+ "DW_DLE_DEBUG_FRAME_NULL .debug_frame section present but "
+ "elf_getdata() failed or section is zero-length",
+ "DW_DLE_ABBREV_DECODE_ERROR",
+ "DW_DLE_DWARF_ABBREV_NULL",
+ "DW_DLE_ATTR_NULL",
+ "DW_DLE_DIE_BAD",
+ "DW_DLE_DIE_ABBREV_BAD",
+ "DW_DLE_ATTR_FORM_BAD",
+ "DW_DLE_ATTR_NO_CU_CONTEXT",
+ "DW_DLE_ATTR_FORM_SIZE_BAD",
+ "DW_DLE_ATTR_DBG_NULL",
+ "DW_DLE_BAD_REF_FORM",
+ "DW_DLE_ATTR_FORM_OFFSET_BAD",
+ "DW_DLE_LINE_OFFSET_BAD",
+ "DW_DLE_DEBUG_STR_OFFSET_BAD",
+ "DW_DLE_STRING_PTR_NULL",
+ "DW_DLE_PUBNAMES_VERSION_ERROR",
+ "DW_DLE_PUBNAMES_LENGTH_BAD",
+ "DW_DLE_GLOBAL_NULL",
+ "DW_DLE_GLOBAL_CONTEXT_NULL",
+ "DW_DLE_DIR_INDEX_BAD",
+ "DW_DLE_LOC_EXPR_BAD",
+ "DW_DLE_DIE_LOC_EXPR_BAD",
+ "DW_DLE_ADDR_ALLOC",
+ "DW_DLE_OFFSET_BAD",
+ "DW_DLE_MAKE_CU_CONTEXT_FAIL",
+ "DW_DLE_REL_ALLOC",
+ "DW_DLE_ARANGE_OFFSET_BAD",
+ "DW_DLE_SEGMENT_SIZE_BAD",
+ "DW_DLE_ARANGE_LENGTH_BAD",
+ "DW_DLE_ARANGE_DECODE_ERROR",
+ "DW_DLE_ARANGES_NULL",
+ "DW_DLE_ARANGE_NULL",
+ "DW_DLE_NO_FILE_NAME",
+ "DW_DLE_NO_COMP_DIR",
+ "DW_DLE_CU_ADDRESS_SIZE_BAD",
+ "DW_DLE_INPUT_ATTR_BAD",
+ "DW_DLE_EXPR_NULL",
+ "DW_DLE_BAD_EXPR_OPCODE",
+ "DW_DLE_EXPR_LENGTH_BAD",
+ "DW_DLE_MULTIPLE_RELOC_IN_EXPR",
+ "DW_DLE_ELF_GETIDENT_ERROR",
+ "DW_DLE_NO_AT_MIPS_FDE",
+ "DW_DLE_NO_CIE_FOR_FDE",
+ "DW_DLE_DIE_ABBREV_LIST_NULL",
+ "DW_DLE_DEBUG_FUNCNAMES_DUPLICATE",
+ "DW_DLE_DEBUG_FUNCNAMES_NULL .debug_funcnames section present but "
+ "elf_getdata() failed or section is zero-length",
+ "DW_DLE_DEBUG_FUNCNAMES_VERSION_ERROR",
+ "DW_DLE_DEBUG_FUNCNAMES_LENGTH_BAD",
+ "DW_DLE_FUNC_NULL",
+ "DW_DLE_FUNC_CONTEXT_NULL",
+ "DW_DLE_DEBUG_TYPENAMES_DUPLICATE",
+ "DW_DLE_DEBUG_TYPENAMES_NULL .debug_typenames section present but "
+ "elf_getdata() failed or section is zero-length",
+ "DW_DLE_DEBUG_TYPENAMES_VERSION_ERROR",
+ "DW_DLE_DEBUG_TYPENAMES_LENGTH_BAD",
+ "DW_DLE_TYPE_NULL",
+ "DW_DLE_TYPE_CONTEXT_NULL",
+ "DW_DLE_DEBUG_VARNAMES_DUPLICATE",
+ "DW_DLE_DEBUG_VARNAMES_NULL .debug_varnames section present but "
+ "elf_getdata() failed or section is zero-length",
+ "DW_DLE_DEBUG_VARNAMES_VERSION_ERROR",
+ "DW_DLE_DEBUG_VARNAMES_LENGTH_BAD",
+ "DW_DLE_VAR_NULL",
+ "DW_DLE_VAR_CONTEXT_NULL",
+ "DW_DLE_DEBUG_WEAKNAMES_DUPLICATE",
+ "DW_DLE_DEBUG_WEAKNAMES_NULL .debug_weaknames section present but "
+ "elf_getdata() failed or section is zero-length",
+
+ "DW_DLE_DEBUG_WEAKNAMES_VERSION_ERROR",
+ "DW_DLE_DEBUG_WEAKNAMES_LENGTH_BAD",
+ "DW_DLE_WEAK_NULL",
+ "DW_DLE_WEAK_CONTEXT_NULL (175)",
+ "DW_DLE_LOCDESC_COUNT_WRONG (176)",
+ "DW_DLE_MACINFO_STRING_NULL (177)",
+ "DW_DLE_MACINFO_STRING_EMPTY (178)",
+ "DW_DLE_MACINFO_INTERNAL_ERROR_SPACE (179)",
+ "DW_DLE_MACINFO_MALLOC_FAIL (180)",
+ "DW_DLE_DEBUGMACINFO_ERROR (181)",
+ "DW_DLE_DEBUG_MACRO_LENGTH_BAD (182)",
+ "DW_DLE_DEBUG_MACRO_MAX_BAD (183)",
+ "DW_DLE_DEBUG_MACRO_INTERNAL_ERR (184)",
+ "DW_DLE_DEBUG_MACRO_MALLOC_SPACE (185)",
+ "DW_DLE_DEBUG_MACRO_INCONSISTENT (186)",
+ "DW_DLE_DF_NO_CIE_AUGMENTATION(187)",
+ "DW_DLE_DF_REG_NUM_TOO_HIGH(188)",
+ "DW_DLE_DF_MAKE_INSTR_NO_INIT(189)",
+ "DW_DLE_DF_NEW_LOC_LESS_OLD_LOC(190)",
+ "DW_DLE_DF_POP_EMPTY_STACK(191)",
+ "DW_DLE_DF_ALLOC_FAIL(192)",
+ "DW_DLE_DF_FRAME_DECODING_ERROR(193)",
+ "DW_DLE_DEBUG_LOC_SECTION_SHORT(194)",
+ "DW_DLE_FRAME_AUGMENTATION_UNKNOWN(195)",
+ "DW_DLE_PUBTYPE_CONTEXT(196)",
+ "DW_DLE_DEBUG_PUBTYPES_LENGTH_BAD(197)",
+ "DW_DLE_DEBUG_PUBTYPES_VERSION_ERROR(198)",
+ "DW_DLE_DEBUG_PUBTYPES_DUPLICATE(199)",
+ "DW_DLE_FRAME_CIE_DECODE_ERROR(200)",
+ "DW_DLE_FRAME_REGISTER_UNREPRESENTABLE(201)",
+ "DW_DLE_FRAME_REGISTER_COUNT_MISMATCH(202)",
+ "DW_DLE_LINK_LOOP(203)",
+ "DW_DLE_STRP_OFFSET_BAD(204)",
+ "DW_DLE_DEBUG_RANGES_DUPLICATE(205)",
+ "DW_DLE_DEBUG_RANGES_OFFSET_BAD(206)",
+ "DW_DLE_DEBUG_RANGES_MISSING_END(207)",
+ "DW_DLE_DEBUG_RANGES_OUT_OF_MEM(208)",
+ "DW_DLE_DEBUG_SYMTAB_ERR(209)",
+ "DW_DLE_DEBUG_STRTAB_ERR(210)",
+ "DW_DLE_RELOC_MISMATCH_INDEX(211)",
+ "DW_DLE_RELOC_MISMATCH_RELOC_INDEX(212)",
+ "DW_DLE_RELOC_MISMATCH_STRTAB_INDEX(213)",
+ "DW_DLE_RELOC_SECTION_MISMATCH(214)",
+ "DW_DLE_RELOC_SECTION_MISSING_INDEX(215)",
+ "DW_DLE_RELOC_SECTION_LENGTH_ODD(216)",
+ "DW_DLE_RELOC_SECTION_PTR_NULL(217)",
+ "DW_DLE_RELOC_SECTION_MALLOC_FAIL(218)",
+ "DW_DLE_NO_ELF64_SUPPORT(219)",
+ "DW_DLE_MISSING_ELF64_SUPPORT(220)",
+ "DW_DLE_ORPHAN_FDE(221)",
+ "DW_DLE_DUPLICATE_INST_BLOCK(222)",
+ "DW_DLE_BAD_REF_SIG8_FORM(223)",
+ "DW_DLE_ATTR_EXPRLOC_FORM_BAD(224)",
+ "DW_DLE_FORM_SEC_OFFSET_LENGTH_BAD(225)",
+ "DW_DLE_NOT_REF_FORM(226)",
+ "DW_DLE_DEBUG_FRAME_LENGTH_NOT_MULTIPLE(227)"
+};
+
+
+
+
+/*
+ This function performs error handling as described in the
+ libdwarf consumer document section 3. Dbg is the Dwarf_debug
+ structure being processed. Error is a pointer to the pointer
+ to the error descriptor that will be returned. Errval is an
+ error code listed in dwarf_error.h.
+*/
+void
+_dwarf_error(Dwarf_Debug dbg, Dwarf_Error * error, Dwarf_Sword errval)
+{
+ Dwarf_Error errptr;
+
+ /*
+ Allow NULL dbg on entry, since sometimes that can happen and we
+ want to report the upper-level error, not this one. */
+ if (error != NULL) {
+
+ /*
+ If dbg is NULL, use the alternate error struct. However,
+ this will overwrite the earlier error. */
+ if (dbg != NULL) {
+ errptr =
+ (Dwarf_Error) _dwarf_get_alloc(dbg, DW_DLA_ERROR, 1);
+ if (errptr == NULL) {
+ fprintf(stderr,
+ "Could not allocate Dwarf_Error structure, "
+ "abort() in libdwarf.\n");
+ abort();
+ }
+ } else {
+ /* We have no dbg to work with. dwarf_init failed. We hack
+ up a special area. */
+ errptr = _dwarf_special_no_dbg_error_malloc();
+ if (errptr == NULL) {
+ fprintf(stderr,
+ "Could not allocate Dwarf_Error structure, "
+ "abort() in libdwarf..\n");
+ abort();
+ }
+ }
+
+ errptr->er_errval = errval;
+ *error = errptr;
+ return;
+ }
+
+ if (dbg != NULL && dbg->de_errhand != NULL) {
+ errptr = (Dwarf_Error) _dwarf_get_alloc(dbg, DW_DLA_ERROR, 1);
+ if (errptr == NULL) {
+ fprintf(stderr, "Could not allocate Dwarf_Error structure,"
+ " abort() in libdwarf.\n");
+ abort();
+ }
+ errptr->er_errval = errval;
+ dbg->de_errhand(errptr, dbg->de_errarg);
+ return;
+ }
+ fprintf(stderr,
+ "abort() in libdwarf. No error argument, no handler.\n");
+ abort();
+}
+
+
+Dwarf_Unsigned
+dwarf_errno(Dwarf_Error error)
+{
+ if (error == NULL) {
+ return (0);
+ }
+
+ return (error->er_errval);
+}
+
+
+/*
+*/
+char *
+dwarf_errmsg(Dwarf_Error error)
+{
+ if (error == NULL) {
+ return "Dwarf_Error is NULL";
+ }
+
+ if (error->er_errval > (sizeof(_dwarf_errmsgs) / sizeof(char *))) {
+ return "Dwarf_Error value out of range";
+ }
+
+ return ((char *) _dwarf_errmsgs[error->er_errval]);
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_error.h b/usr/src/lib/libdwarf/common/dwarf_error.h
new file mode 100644
index 0000000000..27acf70db0
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_error.h
@@ -0,0 +1,43 @@
+/*
+
+ Copyright (C) 2000 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
+
+*/
+
+
+
+void _dwarf_error(Dwarf_Debug dbg, Dwarf_Error * error,
+ Dwarf_Sword errval);
+
+struct Dwarf_Error_s {
+ Dwarf_Sword er_errval;
+};
diff --git a/usr/src/lib/libdwarf/common/dwarf_form.c b/usr/src/lib/libdwarf/common/dwarf_form.c
new file mode 100644
index 0000000000..fcdd64230c
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_form.c
@@ -0,0 +1,963 @@
+/*
+
+ Copyright (C) 2000,2002,2004,2005 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright 2007-2010 Sun Microsystems, Inc. All rights reserved.
+ Portions Copyright 2008-2010 David Anderson. 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
+
+*/
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include "dwarf_die_deliv.h"
+
+int
+dwarf_hasform(Dwarf_Attribute attr,
+ Dwarf_Half form,
+ Dwarf_Bool * return_bool, Dwarf_Error * error)
+{
+ Dwarf_CU_Context cu_context = 0;
+
+ if (attr == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ cu_context = attr->ar_cu_context;
+ if (cu_context == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT);
+ return (DW_DLV_ERROR);
+ }
+
+ if (cu_context->cc_dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ *return_bool = (attr->ar_attribute_form == form);
+ return DW_DLV_OK;
+}
+
+/* Not often called, we do not worry about efficiency here.
+ The dwarf_whatform() call does the sanity checks for us.
+*/
+int
+dwarf_whatform_direct(Dwarf_Attribute attr,
+ Dwarf_Half * return_form, Dwarf_Error * error)
+{
+ int res = dwarf_whatform(attr, return_form, error);
+
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ *return_form = attr->ar_attribute_form_direct;
+ return (DW_DLV_OK);
+}
+void *
+dwarf_uncompress_integer_block(
+ Dwarf_Debug dbg,
+ Dwarf_Bool unit_is_signed,
+ Dwarf_Small unit_length_in_bits,
+ void* input_block,
+ Dwarf_Unsigned input_length_in_bytes,
+ Dwarf_Unsigned* output_length_in_units_ptr,
+ Dwarf_Error* error
+)
+{
+ Dwarf_Unsigned output_length_in_units = 0;
+ void * output_block = 0;
+ int i = 0;
+ char * ptr = 0;
+ int remain = 0;
+ Dwarf_sfixed * array = 0;
+
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
+ return((void *)DW_DLV_BADADDR);
+ }
+
+ if (unit_is_signed == false ||
+ unit_length_in_bits != 32 ||
+ input_block == NULL ||
+ input_length_in_bytes == 0 ||
+ output_length_in_units_ptr == NULL) {
+
+ _dwarf_error(NULL, error, DW_DLE_BADBITC);
+ return ((void *) DW_DLV_BADADDR);
+ }
+
+ /* At this point we assume the format is: signed 32 bit */
+
+ /* first uncompress everything to find the total size. */
+
+ output_length_in_units = 0;
+ remain = input_length_in_bytes;
+ ptr = input_block;
+ while (remain > 0) {
+ Dwarf_Signed num;
+ Dwarf_Word len;
+ num = _dwarf_decode_s_leb128((unsigned char *)ptr, &len);
+ ptr += len;
+ remain -= len;
+ output_length_in_units++;
+ }
+
+ if (remain != 0) {
+ _dwarf_error(NULL, error, DW_DLE_ALLOC_FAIL);
+ return((void *)DW_DLV_BADADDR);
+ }
+
+ /* then alloc */
+
+ output_block = (void *)
+ _dwarf_get_alloc(dbg,
+ DW_DLA_STRING,
+ output_length_in_units * (unit_length_in_bits / 8));
+ if (output_block == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return((void*)DW_DLV_BADADDR);
+ }
+
+ /* then uncompress again and copy into new buffer */
+
+ array = (Dwarf_sfixed *) output_block;
+ remain = input_length_in_bytes;
+ ptr = input_block;
+ for (i=0; i<output_length_in_units && remain>0; i++) {
+ Dwarf_Signed num;
+ Dwarf_Word len;
+ num = _dwarf_decode_s_leb128((unsigned char *)ptr, &len);
+ ptr += len;
+ remain -= len;
+ array[i] = num;
+ }
+
+ if (remain != 0) {
+ dwarf_dealloc(dbg, (unsigned char *)output_block, DW_DLA_STRING);
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return((Dwarf_P_Attribute)DW_DLV_BADADDR);
+ }
+
+ *output_length_in_units_ptr = output_length_in_units;
+ return output_block;
+}
+
+void
+dwarf_dealloc_uncompressed_block(Dwarf_Debug dbg, void * space)
+{
+ dwarf_dealloc(dbg, space, DW_DLA_STRING);
+}
+
+
+int
+dwarf_whatform(Dwarf_Attribute attr,
+ Dwarf_Half * return_form, Dwarf_Error * error)
+{
+ Dwarf_CU_Context cu_context = 0;
+
+ if (attr == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ cu_context = attr->ar_cu_context;
+ if (cu_context == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT);
+ return (DW_DLV_ERROR);
+ }
+
+ if (cu_context->cc_dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ *return_form = attr->ar_attribute_form;
+ return (DW_DLV_OK);
+}
+
+
+/*
+ This function is analogous to dwarf_whatform.
+ It returns the attribute in attr instead of
+ the form.
+*/
+int
+dwarf_whatattr(Dwarf_Attribute attr,
+ Dwarf_Half * return_attr, Dwarf_Error * error)
+{
+ Dwarf_CU_Context cu_context = 0;
+
+ if (attr == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ cu_context = attr->ar_cu_context;
+ if (cu_context == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT);
+ return (DW_DLV_ERROR);
+ }
+
+ if (cu_context->cc_dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ *return_attr = (attr->ar_attribute);
+ return DW_DLV_OK;
+}
+
+
+/*
+ A global offset cannot be returned by this interface:
+ see dwarf_global_formref().
+
+ DW_FORM_ref_addr is considered an incorrect form
+ for this call because DW_FORM_ref_addr is a global-offset into
+ the debug_info section.
+
+ For the same reason DW_FORM_data4/data8 are not returned
+ from this function.
+
+ For the same reason DW_FORM_sec_offset is not returned
+ from this function, DW_FORM_sec_offset is a global offset
+ (to various sections, not a CU relative offset.
+
+ DW_FORM_ref_addr has a value which was documented in
+ DWARF2 as address-size but which was always an offset
+ so should have always been offset size (wording
+ corrected in DWARF3).
+
+
+*/
+int
+dwarf_formref(Dwarf_Attribute attr,
+ Dwarf_Off * ret_offset, Dwarf_Error * error)
+{
+ Dwarf_Debug dbg = 0;
+ Dwarf_Unsigned offset = 0;
+ Dwarf_CU_Context cu_context = 0;
+
+
+ if (attr == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ cu_context = attr->ar_cu_context;
+ if (cu_context == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT);
+ return (DW_DLV_ERROR);
+ }
+
+ if (cu_context->cc_dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ dbg = cu_context->cc_dbg;
+
+ switch (attr->ar_attribute_form) {
+
+ case DW_FORM_ref1:
+ offset = *(Dwarf_Small *) attr->ar_debug_info_ptr;
+ break;
+
+ case DW_FORM_ref2:
+ READ_UNALIGNED(dbg, offset, Dwarf_Unsigned,
+ attr->ar_debug_info_ptr, sizeof(Dwarf_Half));
+ break;
+
+ case DW_FORM_ref4:
+ READ_UNALIGNED(dbg, offset, Dwarf_Unsigned,
+ attr->ar_debug_info_ptr, sizeof(Dwarf_ufixed));
+ break;
+
+ case DW_FORM_ref8:
+ READ_UNALIGNED(dbg, offset, Dwarf_Unsigned,
+ attr->ar_debug_info_ptr, sizeof(Dwarf_Unsigned));
+ break;
+
+ case DW_FORM_ref_udata:
+ offset = _dwarf_decode_u_leb128(attr->ar_debug_info_ptr, NULL);
+ break;
+
+ default:
+ _dwarf_error(dbg, error, DW_DLE_BAD_REF_FORM);
+ return (DW_DLV_ERROR);
+ }
+
+ /* Check that offset is within current cu portion of .debug_info. */
+ if (offset >= cu_context->cc_length +
+ cu_context->cc_length_size + cu_context->cc_extension_size) {
+ _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_OFFSET_BAD);
+ return (DW_DLV_ERROR);
+ }
+
+ *ret_offset = (offset);
+ return DW_DLV_OK;
+}
+
+/* dwarf_formsig8 returns in the caller-provided 8 byte area
+ the 8 bytes of a DW_FORM_ref_sig8 (copying the bytes
+ directly to the caller). Not a string, an 8 byte
+ MD5 hash. This function is new in DWARF4 libdwarf.
+*/
+int dwarf_formsig8(Dwarf_Attribute attr,
+ Dwarf_Sig8 * returned_sig_bytes,
+ Dwarf_Error* error)
+{
+ Dwarf_Debug dbg = 0;
+ Dwarf_Unsigned field_end_offset = 0;
+ Dwarf_CU_Context cu_context = 0;
+
+
+ if (attr == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ cu_context = attr->ar_cu_context;
+ if (cu_context == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT);
+ return (DW_DLV_ERROR);
+ }
+
+ if (cu_context->cc_dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ dbg = cu_context->cc_dbg;
+
+ if(attr->ar_attribute_form != DW_FORM_ref_sig8 ) {
+ _dwarf_error(dbg, error, DW_DLE_BAD_REF_SIG8_FORM);
+ return (DW_DLV_ERROR);
+ }
+
+ field_end_offset = attr->ar_debug_info_ptr + sizeof(Dwarf_Sig8) -
+ (dbg->de_debug_info.dss_data + cu_context->cc_debug_info_offset);
+ /* Check that offset is within current cu portion of .debug_info. */
+ if (field_end_offset > cu_context->cc_length +
+ cu_context->cc_length_size + cu_context->cc_extension_size) {
+ _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_OFFSET_BAD);
+ return (DW_DLV_ERROR);
+ }
+
+ memcpy(returned_sig_bytes, attr->ar_debug_info_ptr,
+ sizeof(Dwarf_Sig8));
+ return DW_DLV_OK;
+}
+
+
+/*
+ Since this returns section-relative debug_info offsets,
+ this can represent all REFERENCE forms correctly
+ and allows all applicable forms.
+
+ DW_FORM_ref_addr has a value which was documented in
+ DWARF2 as address-size but which was always an offset
+ so should have always been offset size (wording
+ corrected in DWARF3).
+
+ See the DWARF4 document for the 3 cases fitting
+ reference forms. The caller must determine which section the
+ reference 'points' to. The function added in November 2009,
+ dwarf_get_form_class(), helps in this regard.
+
+*/
+int
+dwarf_global_formref(Dwarf_Attribute attr,
+ Dwarf_Off * ret_offset, Dwarf_Error * error)
+{
+ Dwarf_Debug dbg = 0;
+ Dwarf_Unsigned offset = 0;
+ Dwarf_Addr ref_addr = 0;
+ Dwarf_CU_Context cu_context = 0;
+ Dwarf_Half context_version = 0;
+
+ if (attr == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ cu_context = attr->ar_cu_context;
+ if (cu_context == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT);
+ return (DW_DLV_ERROR);
+ }
+ context_version = cu_context->cc_version_stamp;
+
+ if (cu_context->cc_dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ dbg = cu_context->cc_dbg;
+
+ switch (attr->ar_attribute_form) {
+
+ case DW_FORM_ref1:
+ offset = *(Dwarf_Small *) attr->ar_debug_info_ptr;
+ goto fixoffset;
+
+ case DW_FORM_ref2:
+ READ_UNALIGNED(dbg, offset, Dwarf_Unsigned,
+ attr->ar_debug_info_ptr, sizeof(Dwarf_Half));
+ goto fixoffset;
+
+ case DW_FORM_ref4:
+ READ_UNALIGNED(dbg, offset, Dwarf_Unsigned,
+ attr->ar_debug_info_ptr, sizeof(Dwarf_ufixed));
+ goto fixoffset;
+
+ case DW_FORM_ref8:
+ READ_UNALIGNED(dbg, offset, Dwarf_Unsigned,
+ attr->ar_debug_info_ptr, sizeof(Dwarf_Unsigned));
+ goto fixoffset;
+
+ case DW_FORM_ref_udata:
+ offset = _dwarf_decode_u_leb128(attr->ar_debug_info_ptr, NULL);
+
+ fixoffset: /* we have a local offset, make it
+ global */
+
+ /* check legality of offset */
+ if (offset >= cu_context->cc_length +
+ cu_context->cc_length_size +
+ cu_context->cc_extension_size) {
+ _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_OFFSET_BAD);
+ return (DW_DLV_ERROR);
+ }
+
+ /* globalize the offset */
+ offset += cu_context->cc_debug_info_offset;
+ break;
+ /* The DWARF2 document did not make clear that
+ DW_FORM_data4( and 8) were references with
+ global offsets to some section.
+ That was first clearly documented in DWARF3.
+ In DWARF4 these two forms are no longer references. */
+ case DW_FORM_data4:
+ if(context_version == DW_CU_VERSION4) {
+ _dwarf_error(dbg, error, DW_DLE_NOT_REF_FORM);
+ return (DW_DLV_ERROR);
+ }
+ READ_UNALIGNED(dbg, offset, Dwarf_Unsigned,
+ attr->ar_debug_info_ptr, sizeof(Dwarf_ufixed));
+ /* The offset is global. */
+ break;
+ case DW_FORM_data8:
+ if(context_version == DW_CU_VERSION4) {
+ _dwarf_error(dbg, error, DW_DLE_NOT_REF_FORM);
+ return (DW_DLV_ERROR);
+ }
+ READ_UNALIGNED(dbg, offset, Dwarf_Unsigned,
+ attr->ar_debug_info_ptr, sizeof(Dwarf_Unsigned));
+ /* The offset is global. */
+ break;
+ case DW_FORM_ref_addr:
+ case DW_FORM_sec_offset:
+ {
+ /* DW_FORM_sec_offset first exists in DWARF4.*/
+ /* It is up to the caller to know what the offset
+ of DW_FORM_sec_offset refers to,
+ the offset is not going to refer to .debug_info! */
+ unsigned length_size = cu_context->cc_length_size;
+ if(length_size == 4) {
+ READ_UNALIGNED(dbg, offset, Dwarf_Unsigned,
+ attr->ar_debug_info_ptr, sizeof(Dwarf_ufixed));
+ } else if (length_size == 8) {
+ READ_UNALIGNED(dbg, offset, Dwarf_Unsigned,
+ attr->ar_debug_info_ptr, sizeof(Dwarf_Unsigned));
+ } else {
+ _dwarf_error(dbg, error, DW_DLE_FORM_SEC_OFFSET_LENGTH_BAD);
+ return (DW_DLV_ERROR);
+ }
+ }
+ break;
+
+ default:
+ _dwarf_error(dbg, error, DW_DLE_BAD_REF_FORM);
+ return (DW_DLV_ERROR);
+ }
+
+ /* We do not know what section the offset refers to, so
+ we have no way to check it for correctness. */
+ *ret_offset = offset;
+ return DW_DLV_OK;
+}
+
+
+int
+dwarf_formaddr(Dwarf_Attribute attr,
+ Dwarf_Addr * return_addr, Dwarf_Error * error)
+{
+ Dwarf_Debug dbg = 0;
+ Dwarf_Addr ret_addr = 0;
+ Dwarf_CU_Context cu_context = 0;
+
+ if (attr == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ cu_context = attr->ar_cu_context;
+ if (cu_context == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT);
+ return (DW_DLV_ERROR);
+ }
+
+ if (cu_context->cc_dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ dbg = cu_context->cc_dbg;
+
+ if (attr->ar_attribute_form == DW_FORM_addr
+ /* || attr->ar_attribute_form == DW_FORM_ref_addr Allowance of
+ DW_FORM_ref_addr was a mistake. The value returned in that
+ case is NOT an address it is a global debug_info offset (ie,
+ not CU-relative offset within the CU in debug_info). The
+ Dwarf document refers to it as an address (misleadingly) in
+ sec 6.5.4 where it describes the reference form. It is
+ address-sized so that the linker can easily update it, but
+ it is a reference inside the debug_info section. No longer
+ allowed. */
+ ) {
+
+ READ_UNALIGNED(dbg, ret_addr, Dwarf_Addr,
+ attr->ar_debug_info_ptr,
+ cu_context->cc_address_size);
+ *return_addr = ret_addr;
+ return (DW_DLV_OK);
+ }
+
+ _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_BAD);
+ return (DW_DLV_ERROR);
+}
+
+
+int
+dwarf_formflag(Dwarf_Attribute attr,
+ Dwarf_Bool * ret_bool, Dwarf_Error * error)
+{
+ Dwarf_CU_Context cu_context = 0;
+
+ if (attr == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ cu_context = attr->ar_cu_context;
+ if (cu_context == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT);
+ return (DW_DLV_ERROR);
+ }
+
+ if (cu_context->cc_dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ if (attr->ar_attribute_form == DW_FORM_flag_present) {
+ /* Implicit means we don't read any data at all. Just
+ the existence of the Form does it. DWARF4. */
+ *ret_bool = 1;
+ return (DW_DLV_OK);
+ }
+
+ if (attr->ar_attribute_form == DW_FORM_flag) {
+ *ret_bool = (*(Dwarf_Small *) attr->ar_debug_info_ptr != 0);
+ return (DW_DLV_OK);
+ }
+ _dwarf_error(cu_context->cc_dbg, error, DW_DLE_ATTR_FORM_BAD);
+ return (DW_DLV_ERROR);
+}
+
+
+int
+dwarf_formudata(Dwarf_Attribute attr,
+ Dwarf_Unsigned * return_uval, Dwarf_Error * error)
+{
+ Dwarf_Unsigned ret_value = 0;
+ Dwarf_Debug dbg = 0;
+ Dwarf_CU_Context cu_context = 0;
+
+ if (attr == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+
+ cu_context = attr->ar_cu_context;
+ if (cu_context == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT);
+ return (DW_DLV_ERROR);
+ }
+
+ dbg = cu_context->cc_dbg;
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ switch (attr->ar_attribute_form) {
+
+ case DW_FORM_data1:
+ READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
+ attr->ar_debug_info_ptr, sizeof(Dwarf_Small));
+ *return_uval = ret_value;
+ return DW_DLV_OK;
+
+ /* READ_UNALIGNED does the right thing as it reads
+ the right number bits and generates host order.
+ So we can just assign to *return_uval. */
+ case DW_FORM_data2:{
+ READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
+ attr->ar_debug_info_ptr, sizeof(Dwarf_Half));
+ *return_uval = ret_value;
+ return DW_DLV_OK;
+ }
+
+ case DW_FORM_data4:{
+ READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
+ attr->ar_debug_info_ptr,
+ sizeof(Dwarf_ufixed));
+ *return_uval = ret_value;
+ return DW_DLV_OK;
+ }
+
+ case DW_FORM_data8:{
+ READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
+ attr->ar_debug_info_ptr,
+ sizeof(Dwarf_Unsigned));
+ *return_uval = ret_value;
+ return DW_DLV_OK;
+ }
+ break;
+ case DW_FORM_udata:
+ ret_value =
+ (_dwarf_decode_u_leb128(attr->ar_debug_info_ptr, NULL));
+ *return_uval = ret_value;
+ return DW_DLV_OK;
+
+
+ /* see bug 583450. We do not allow reading sdata from a udata
+ value. Caller can retry, calling sdata */
+
+
+ default:
+ break;
+ }
+ _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_BAD);
+ return (DW_DLV_ERROR);
+}
+
+
+int
+dwarf_formsdata(Dwarf_Attribute attr,
+ Dwarf_Signed * return_sval, Dwarf_Error * error)
+{
+ Dwarf_Signed ret_value = 0;
+ Dwarf_Debug dbg = 0;
+ Dwarf_CU_Context cu_context = 0;
+
+ if (attr == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ cu_context = attr->ar_cu_context;
+ if (cu_context == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT);
+ return (DW_DLV_ERROR);
+ }
+
+ dbg = cu_context->cc_dbg;
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ switch (attr->ar_attribute_form) {
+
+ case DW_FORM_data1:
+ *return_sval = (*(Dwarf_Sbyte *) attr->ar_debug_info_ptr);
+ return DW_DLV_OK;
+
+ /* READ_UNALIGNED does not sign extend.
+ So we have to use a cast to get the
+ value sign extended in the right way for each case. */
+ case DW_FORM_data2:{
+ READ_UNALIGNED(dbg, ret_value, Dwarf_Signed,
+ attr->ar_debug_info_ptr,
+ sizeof(Dwarf_Shalf));
+ *return_sval = (Dwarf_Shalf) ret_value;
+ return DW_DLV_OK;
+
+ }
+
+ case DW_FORM_data4:{
+ READ_UNALIGNED(dbg, ret_value, Dwarf_Signed,
+ attr->ar_debug_info_ptr,
+ sizeof(Dwarf_sfixed));
+ *return_sval = (Dwarf_sfixed) ret_value;
+ return DW_DLV_OK;
+ }
+
+ case DW_FORM_data8:{
+ READ_UNALIGNED(dbg, ret_value, Dwarf_Signed,
+ attr->ar_debug_info_ptr,
+ sizeof(Dwarf_Signed));
+ *return_sval = (Dwarf_Signed) ret_value;
+ return DW_DLV_OK;
+ }
+
+ case DW_FORM_sdata:
+ ret_value =
+ (_dwarf_decode_s_leb128(attr->ar_debug_info_ptr, NULL));
+ *return_sval = ret_value;
+ return DW_DLV_OK;
+
+
+ /* see bug 583450. We do not allow reading sdata from a udata
+ value. Caller can retry, calling sdata */
+
+
+ default:
+ break;
+ }
+ _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_BAD);
+ return (DW_DLV_ERROR);
+}
+
+
+int
+dwarf_formblock(Dwarf_Attribute attr,
+ Dwarf_Block ** return_block, Dwarf_Error * error)
+{
+ Dwarf_CU_Context cu_context = 0;
+ Dwarf_Debug dbg = 0;
+ Dwarf_Unsigned length = 0;
+ Dwarf_Small *data = 0;
+ Dwarf_Word leb128_length = 0;
+ Dwarf_Block *ret_block = 0;
+
+ if (attr == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ cu_context = attr->ar_cu_context;
+ if (cu_context == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT);
+ return (DW_DLV_ERROR);
+ }
+
+ if (cu_context->cc_dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ dbg = cu_context->cc_dbg;
+
+ switch (attr->ar_attribute_form) {
+
+ case DW_FORM_block1:
+ length = *(Dwarf_Small *) attr->ar_debug_info_ptr;
+ data = attr->ar_debug_info_ptr + sizeof(Dwarf_Small);
+ break;
+
+ case DW_FORM_block2:
+ READ_UNALIGNED(dbg, length, Dwarf_Unsigned,
+ attr->ar_debug_info_ptr, sizeof(Dwarf_Half));
+ data = attr->ar_debug_info_ptr + sizeof(Dwarf_Half);
+ break;
+
+ case DW_FORM_block4:
+ READ_UNALIGNED(dbg, length, Dwarf_Unsigned,
+ attr->ar_debug_info_ptr, sizeof(Dwarf_ufixed));
+ data = attr->ar_debug_info_ptr + sizeof(Dwarf_ufixed);
+ break;
+
+ case DW_FORM_block:
+ length = _dwarf_decode_u_leb128(attr->ar_debug_info_ptr,
+ &leb128_length);
+ data = attr->ar_debug_info_ptr + leb128_length;
+ break;
+
+ default:
+ _dwarf_error(cu_context->cc_dbg, error, DW_DLE_ATTR_FORM_BAD);
+ return (DW_DLV_ERROR);
+ }
+
+ /* Check that block lies within current cu in .debug_info. */
+ if (attr->ar_debug_info_ptr + length >=
+ dbg->de_debug_info.dss_data + cu_context->cc_debug_info_offset +
+ cu_context->cc_length + cu_context->cc_length_size +
+ cu_context->cc_extension_size) {
+ _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_SIZE_BAD);
+ return (DW_DLV_ERROR);
+ }
+
+ ret_block = (Dwarf_Block *) _dwarf_get_alloc(dbg, DW_DLA_BLOCK, 1);
+ if (ret_block == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ ret_block->bl_len = length;
+ ret_block->bl_data = (Dwarf_Ptr) data;
+ ret_block->bl_from_loclist = 0;
+ ret_block->bl_section_offset = data - dbg->de_debug_info.dss_data;
+
+
+ *return_block = ret_block;
+ return (DW_DLV_OK);
+}
+
+
+/* Contrary to long standing documentation,
+ The string pointer returned thru return_str must
+ never have dwarf_dealloc() applied to it.
+ Documentation fixed July 2005.
+*/
+int
+dwarf_formstring(Dwarf_Attribute attr,
+ char **return_str, Dwarf_Error * error)
+{
+ Dwarf_CU_Context cu_context = 0;
+ Dwarf_Debug dbg = 0;
+ Dwarf_Unsigned offset = 0;
+ int res = DW_DLV_ERROR;
+
+ if (attr == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ cu_context = attr->ar_cu_context;
+ if (cu_context == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT);
+ return (DW_DLV_ERROR);
+ }
+
+ if (cu_context->cc_dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ dbg = cu_context->cc_dbg;
+
+ if (attr->ar_attribute_form == DW_FORM_string) {
+
+ void *begin = attr->ar_debug_info_ptr;
+
+ if (0 == dbg->de_assume_string_in_bounds) {
+ /* Check that string lies within current cu in .debug_info.
+ */
+ void *end = dbg->de_debug_info.dss_data +
+ cu_context->cc_debug_info_offset +
+ cu_context->cc_length + cu_context->cc_length_size +
+ cu_context->cc_extension_size;
+ if (0 == _dwarf_string_valid(begin, end)) {
+ _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_SIZE_BAD);
+ return (DW_DLV_ERROR);
+ }
+ }
+ *return_str = (char *) (begin);
+ return DW_DLV_OK;
+ }
+
+ if (attr->ar_attribute_form == DW_FORM_strp) {
+ READ_UNALIGNED(dbg, offset, Dwarf_Unsigned,
+ attr->ar_debug_info_ptr,
+ cu_context->cc_length_size);
+
+ res = _dwarf_load_section(dbg, &dbg->de_debug_str,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ if (0 == dbg->de_assume_string_in_bounds) {
+ /* Check that string lies within current cu in .debug_info.
+ */
+ void *end = dbg->de_debug_str.dss_data +
+ dbg->de_debug_str.dss_size;
+ void*begin = dbg->de_debug_str.dss_data + offset;
+ if (0 == _dwarf_string_valid(begin, end)) {
+ _dwarf_error(dbg, error, DW_DLE_STRP_OFFSET_BAD);
+ return (DW_DLV_ERROR);
+ }
+ }
+ *return_str = (char *) (dbg->de_debug_str.dss_data + offset);
+ return DW_DLV_OK;
+ }
+
+ _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_BAD);
+ return (DW_DLV_ERROR);
+}
+
+int
+dwarf_formexprloc(Dwarf_Attribute attr,
+ Dwarf_Unsigned * return_exprlen,
+ Dwarf_Ptr * block_ptr,
+ Dwarf_Error * error)
+{
+ Dwarf_Debug dbg = 0;
+ Dwarf_CU_Context cu_context = 0;
+
+ if (attr == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ cu_context = attr->ar_cu_context;
+ if (cu_context == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT);
+ return (DW_DLV_ERROR);
+ }
+
+ dbg = cu_context->cc_dbg;
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ if (attr->ar_attribute_form == DW_FORM_exprloc ) {
+ Dwarf_Unsigned exprlen =
+ (_dwarf_decode_u_leb128(attr->ar_debug_info_ptr, NULL));
+ Dwarf_Small * addr = attr->ar_debug_info_ptr;
+ *return_exprlen = exprlen;
+ *block_ptr = addr + exprlen;
+ return DW_DLV_OK;
+
+ }
+ _dwarf_error(dbg, error, DW_DLE_ATTR_EXPRLOC_FORM_BAD);
+ return (DW_DLV_ERROR);
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_frame.c b/usr/src/lib/libdwarf/common/dwarf_frame.c
new file mode 100644
index 0000000000..3a825ee925
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_frame.c
@@ -0,0 +1,2442 @@
+/*
+
+ Copyright (C) 2000-2006 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2007-2010 David Anderson. 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
+
+*/
+/* The address of the Free Software Foundation is
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ SGI has moved from the Crittenden Lane address.
+*/
+
+
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include "dwarf_frame.h"
+#include "dwarf_arange.h" /* Using Arange as a way to build a
+ list */
+
+#define FDE_NULL_CHECKS_AND_SET_DBG(fde,dbg ) \
+ do { \
+ if ((fde) == NULL) { \
+ _dwarf_error(NULL, error, DW_DLE_FDE_NULL); \
+ return (DW_DLV_ERROR); \
+ } \
+ (dbg)= (fde)->fd_dbg; \
+ if ((dbg) == NULL) { \
+ _dwarf_error(NULL, error, DW_DLE_FDE_DBG_NULL);\
+ return (DW_DLV_ERROR); \
+ } } while (0)
+
+
+#define MIN(a,b) (((a) < (b))? a:b)
+
+static void _dwarf_init_regrule_table(struct Dwarf_Reg_Rule_s *t1reg,
+ int last_reg_num,
+ int initial_value);
+static int dwarf_initialize_fde_table(Dwarf_Debug dbg,
+ struct Dwarf_Frame_s *fde_table,
+ unsigned table_real_data_size,
+ Dwarf_Error * error);
+static void dwarf_free_fde_table(struct Dwarf_Frame_s *fde_table);
+
+#if 0
+/* Only used for debugging libdwarf. */
+static void dump_frame_rule(char *msg,
+ struct Dwarf_Reg_Rule_s *reg_rule);
+#endif
+
+
+
+/*
+ This function is the heart of the debug_frame stuff. Don't even
+ think of reading this without reading both the Libdwarf and
+ consumer API carefully first. This function basically executes
+ frame instructions contained in a Cie or an Fde, but does in a
+ number of different ways depending on the information sought.
+ Start_instr_ptr points to the first byte of the frame instruction
+ stream, and final_instr_ptr to the to the first byte after the
+ last.
+
+ The offsets returned in the frame instructions are factored. That
+ is they need to be multiplied by either the code_alignment_factor
+ or the data_alignment_factor, as appropriate to obtain the actual
+ offset. This makes it possible to expand an instruction stream
+ without the corresponding Cie. However, when an Fde frame instr
+ sequence is being expanded there must be a valid Cie with a pointer
+ to an initial table row.
+
+
+ If successful, returns DW_DLV_OK
+ And sets returned_count thru the pointer
+ if make_instr is true.
+ If make_instr is false returned_count
+ should NOT be used by the caller (returned_count
+ is set to 0 thru the pointer by this routine...)
+ If unsuccessful, returns DW_DLV_ERROR
+ and sets returned_error to the error code
+
+ It does not do a whole lot of input validation being a private
+ function. Please make sure inputs are valid.
+
+ (1) If make_instr is true, it makes a list of pointers to
+ Dwarf_Frame_Op structures containing the frame instructions
+ executed. A pointer to this list is returned in ret_frame_instr.
+ Make_instr is true only when a list of frame instructions is to be
+ returned. In this case since we are not interested in the contents
+ of the table, the input Cie can be NULL. This is the only case
+ where the inpute Cie can be NULL.
+
+ (2) If search_pc is true, frame instructions are executed till
+ either a location is reached that is greater than the search_pc_val
+ provided, or all instructions are executed. At this point the
+ last row of the table generated is returned in a structure.
+ A pointer to this structure is supplied in table.
+
+ (3) This function is also used to create the initial table row
+ defined by a Cie. In this case, the Dwarf_Cie pointer cie, is
+ NULL. For an FDE, however, cie points to the associated Cie.
+
+ make_instr - make list of frame instr? 0/1
+ ret_frame_instr - Ptr to list of ptrs to frame instrs
+ search_pc - Search for a pc value? 0/1
+ search_pc_val - Search for this pc value
+ initial_loc - Initial code location value.
+ start_instr_ptr - Ptr to start of frame instrs.
+ final_instr_ptr - Ptr just past frame instrs.
+ table - Ptr to struct with last row.
+ cie - Ptr to Cie used by the Fde.
+ Different cies may have distinct address-sizes, so the cie
+ is used, not de_pointer_size.
+
+*/
+
+int
+_dwarf_exec_frame_instr(Dwarf_Bool make_instr,
+ Dwarf_Frame_Op ** ret_frame_instr,
+ Dwarf_Bool search_pc,
+ Dwarf_Addr search_pc_val,
+ Dwarf_Addr initial_loc,
+ Dwarf_Small * start_instr_ptr,
+ Dwarf_Small * final_instr_ptr,
+ Dwarf_Frame table,
+ Dwarf_Cie cie,
+ Dwarf_Debug dbg,
+ Dwarf_Half reg_num_of_cfa,
+ Dwarf_Sword * returned_count,
+ int *returned_error)
+{
+#define ERROR_IF_REG_NUM_TOO_HIGH(macreg,machigh_reg) \
+ do { \
+ if ((macreg) >= (machigh_reg) || (macreg) < 0) { \
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_REG_NUM_TOO_HIGH); \
+ } \
+ } /*CONSTCOND */ while(0)
+#define SIMPLE_ERROR_RETURN(code) \
+ free(localregtab); \
+ *returned_error = code; \
+ return DW_DLV_ERROR
+
+ /* Sweeps the frame instructions. */
+ Dwarf_Small *instr_ptr;
+
+ /* Register numbers not limited to just 255, thus not using
+ Dwarf_Small. */
+ typedef int reg_num_type;
+
+ Dwarf_Unsigned factored_N_value;
+ Dwarf_Signed signed_factored_N_value;
+ Dwarf_Addr current_loc = initial_loc; /* code location/
+ pc-value
+ corresponding to the
+ frame instructions.
+ Starts at zero when
+ the caller has no
+ value to pass in. */
+
+ /* Must be min de_pointer_size bytes and must be at least sizeof
+ Dwarf_ufixed */
+ Dwarf_Unsigned adv_loc = 0;
+
+ int reg_count = dbg->de_frame_reg_rules_entry_count;
+ struct Dwarf_Reg_Rule_s *localregtab = calloc(reg_count,
+ sizeof(struct
+ Dwarf_Reg_Rule_s));
+
+ struct Dwarf_Reg_Rule_s cfa_reg;
+
+
+ /* This is used to end executing frame instructions. */
+ /* Becomes true when search_pc is true and current_loc */
+ /* is greater than search_pc_val. */
+ Dwarf_Bool search_over = false;
+
+ /* Used by the DW_FRAME_advance_loc instr */
+ /* to hold the increment in pc value. */
+ Dwarf_Addr adv_pc;
+
+ /* Contains the length in bytes of */
+ /* an leb128 encoded number. */
+ Dwarf_Word leb128_length;
+
+ Dwarf_Half address_size = (cie)? cie->ci_address_size:
+ dbg->de_pointer_size;
+
+ /* Counts the number of frame instructions executed. */
+ Dwarf_Word instr_count = 0;
+
+ /*
+ These contain the current fields of the current frame
+ instruction. */
+ Dwarf_Small fp_base_op = 0;
+ Dwarf_Small fp_extended_op;
+ reg_num_type fp_register;
+
+ /* The value in fp_offset may be signed, though we call it
+ unsigned. This works ok for 2-s complement arithmetic. */
+ Dwarf_Unsigned fp_offset;
+ Dwarf_Off fp_instr_offset;
+
+ /*
+ Stack_table points to the row (Dwarf_Frame ie) being pushed or
+ popped by a remember or restore instruction. Top_stack points to
+ the top of the stack of rows. */
+ Dwarf_Frame stack_table = NULL;
+ Dwarf_Frame top_stack = NULL;
+
+ /*
+ These are used only when make_instr is true. Curr_instr is a
+ pointer to the current frame instruction executed.
+ Curr_instr_ptr, head_instr_list, and curr_instr_list are used to
+ form a chain of Dwarf_Frame_Op structs. Dealloc_instr_ptr is
+ used to deallocate the structs used to form the chain.
+ Head_instr_block points to a contiguous list of pointers to the
+ Dwarf_Frame_Op structs executed. */
+ Dwarf_Frame_Op *curr_instr;
+ Dwarf_Chain curr_instr_item, dealloc_instr_item;
+ Dwarf_Chain head_instr_chain = NULL;
+ Dwarf_Chain tail_instr_chain = NULL;
+ Dwarf_Frame_Op *head_instr_block;
+
+ /*
+ These are the alignment_factors taken from the Cie provided.
+ When no input Cie is provided they are set to 1, because only
+ factored offsets are required. */
+ Dwarf_Sword code_alignment_factor = 1;
+ Dwarf_Sword data_alignment_factor = 1;
+
+ /*
+ This flag indicates when an actual alignment factor is needed.
+ So if a frame instruction that computes an offset using an
+ alignment factor is encountered when this flag is set, an error
+ is returned because the Cie did not have a valid augmentation. */
+ Dwarf_Bool need_augmentation = false;
+
+ Dwarf_Word i;
+
+ /* Initialize first row from associated Cie. Using temp regs
+ explicity */
+
+ if (localregtab == 0) {
+ SIMPLE_ERROR_RETURN(DW_DLE_ALLOC_FAIL);
+ }
+ {
+ struct Dwarf_Reg_Rule_s *t1reg = localregtab;
+ struct Dwarf_Reg_Rule_s *t1end = t1reg + reg_count;
+
+ if (cie != NULL && cie->ci_initial_table != NULL) {
+ struct Dwarf_Reg_Rule_s *t2reg =
+ cie->ci_initial_table->fr_reg;
+
+ if (reg_count != cie->ci_initial_table->fr_reg_count) {
+ /* Should never happen, it makes no sense to have the
+ table sizes change. There is no real allowance for
+ the set of registers to change dynamically in a
+ single Dwarf_Debug (except the size can be set near
+ initial Dwarf_Debug creation time). */
+ SIMPLE_ERROR_RETURN
+ (DW_DLE_FRAME_REGISTER_COUNT_MISMATCH);
+ }
+
+ for (; t1reg < t1end; t1reg++, t2reg++) {
+ *t1reg = *t2reg;
+ }
+ cfa_reg = cie->ci_initial_table->fr_cfa_rule;
+ } else {
+ _dwarf_init_regrule_table(t1reg,
+ reg_count,
+ dbg->de_frame_rule_initial_value);
+ _dwarf_init_regrule_table(&cfa_reg, 1,
+ dbg->de_frame_rule_initial_value);
+ }
+ }
+
+ /*
+ The idea here is that the code_alignment_factor and
+ data_alignment_factor which are needed for certain instructions
+ are valid only when the Cie has a proper augmentation string. So
+ if the augmentation is not right, only Frame instruction can be
+ read. */
+ if (cie != NULL && cie->ci_augmentation != NULL) {
+ code_alignment_factor = cie->ci_code_alignment_factor;
+ data_alignment_factor = cie->ci_data_alignment_factor;
+ } else {
+ need_augmentation = !make_instr;
+ }
+
+ instr_ptr = start_instr_ptr;
+ while ((instr_ptr < final_instr_ptr) && (!search_over)) {
+ Dwarf_Small instr = 0;
+ Dwarf_Small opcode = 0;
+ reg_num_type reg_no = 0;
+
+ fp_instr_offset = instr_ptr - start_instr_ptr;
+ instr = *(Dwarf_Small *) instr_ptr;
+ instr_ptr += sizeof(Dwarf_Small);
+
+ fp_base_op = (instr & 0xc0) >> 6;
+ if ((instr & 0xc0) == 0x00) {
+ opcode = instr; /* is really extended op */
+ fp_extended_op = (instr & (~(0xc0))) & 0xff;
+ } else {
+ opcode = instr & 0xc0; /* is base op */
+ fp_extended_op = 0;
+ }
+
+ fp_register = 0;
+ fp_offset = 0;
+ switch (opcode) {
+ case DW_CFA_advance_loc:
+ {
+ /* base op */
+ fp_offset = adv_pc = instr & DW_FRAME_INSTR_OFFSET_MASK;
+
+ if (need_augmentation) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION);
+ }
+ adv_pc = adv_pc * code_alignment_factor;
+
+ search_over = search_pc &&
+ (current_loc + adv_pc > search_pc_val);
+ /* If gone past pc needed, retain old pc. */
+ if (!search_over) {
+ current_loc = current_loc + adv_pc;
+ }
+ break;
+ }
+
+ case DW_CFA_offset:
+ { /* base op */
+ reg_no =
+ (reg_num_type) (instr & DW_FRAME_INSTR_OFFSET_MASK);
+ ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);
+
+ factored_N_value =
+ _dwarf_decode_u_leb128(instr_ptr, &leb128_length);
+ instr_ptr = instr_ptr + leb128_length;
+
+ fp_register = reg_no;
+ fp_offset = factored_N_value;
+
+ if (need_augmentation) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION);
+ }
+
+ localregtab[reg_no].ru_is_off = 1;
+ localregtab[reg_no].ru_value_type = DW_EXPR_OFFSET;
+ localregtab[reg_no].ru_register = reg_num_of_cfa;
+ localregtab[reg_no].ru_offset_or_block_len =
+ factored_N_value * data_alignment_factor;
+
+ break;
+ }
+
+ case DW_CFA_restore:
+ { /* base op */
+ reg_no = (instr & DW_FRAME_INSTR_OFFSET_MASK);
+ ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);
+
+ fp_register = reg_no;
+
+ if (cie != NULL && cie->ci_initial_table != NULL)
+ localregtab[reg_no] =
+ cie->ci_initial_table->fr_reg[reg_no];
+ else if (!make_instr) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_MAKE_INSTR_NO_INIT);
+ }
+
+ break;
+ }
+ case DW_CFA_set_loc:
+ {
+ Dwarf_Addr new_loc = 0;
+
+ READ_UNALIGNED(dbg, new_loc, Dwarf_Addr,
+ instr_ptr, address_size);
+ instr_ptr += address_size;
+ if (new_loc != 0 && current_loc != 0) {
+ /* Pre-relocation or before current_loc is set the
+ test comparing new_loc and current_loc makes no
+ sense. Testing for non-zero (above) is a way
+ (fallible) to check that current_loc, new_loc
+ are already relocated. */
+ if (new_loc <= current_loc) {
+ /* Within a frame, address must increase.
+ Seemingly it has not. Seems to be an error. */
+
+ SIMPLE_ERROR_RETURN
+ (DW_DLE_DF_NEW_LOC_LESS_OLD_LOC);
+ }
+ }
+
+ search_over = search_pc && (new_loc > search_pc_val);
+
+ /* If gone past pc needed, retain old pc. */
+ if (!search_over) {
+ current_loc = new_loc;
+ }
+ fp_offset = new_loc;
+ break;
+ }
+
+ case DW_CFA_advance_loc1:
+ {
+ fp_offset = adv_loc = *(Dwarf_Small *) instr_ptr;
+ instr_ptr += sizeof(Dwarf_Small);
+
+ if (need_augmentation) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION);
+ }
+ adv_loc *= code_alignment_factor;
+
+ search_over = search_pc &&
+ (current_loc + adv_loc > search_pc_val);
+
+ /* If gone past pc needed, retain old pc. */
+ if (!search_over) {
+ current_loc = current_loc + adv_loc;
+ }
+ break;
+ }
+
+ case DW_CFA_advance_loc2:
+ {
+ READ_UNALIGNED(dbg, adv_loc, Dwarf_Unsigned,
+ instr_ptr, sizeof(Dwarf_Half));
+ instr_ptr += sizeof(Dwarf_Half);
+ fp_offset = adv_loc;
+
+ if (need_augmentation) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION);
+ }
+ adv_loc *= code_alignment_factor;
+
+ search_over = search_pc &&
+ (current_loc + adv_loc > search_pc_val);
+
+ /* If gone past pc needed, retain old pc. */
+ if (!search_over) {
+ current_loc = current_loc + adv_loc;
+ }
+ break;
+ }
+
+ case DW_CFA_advance_loc4:
+ {
+ READ_UNALIGNED(dbg, adv_loc, Dwarf_Unsigned,
+ instr_ptr, sizeof(Dwarf_ufixed));
+ instr_ptr += sizeof(Dwarf_ufixed);
+ fp_offset = adv_loc;
+
+ if (need_augmentation) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION);
+ }
+ adv_loc *= code_alignment_factor;
+
+ search_over = search_pc &&
+ (current_loc + adv_loc > search_pc_val);
+
+ /* If gone past pc needed, retain old pc. */
+ if (!search_over) {
+ current_loc = current_loc + adv_loc;
+ }
+ break;
+ }
+
+ case DW_CFA_offset_extended:
+ {
+ Dwarf_Unsigned lreg;
+
+ DECODE_LEB128_UWORD(instr_ptr, lreg);
+ reg_no = (reg_num_type) lreg;
+ ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);;
+ factored_N_value =
+ _dwarf_decode_u_leb128(instr_ptr, &leb128_length);
+ instr_ptr += leb128_length;
+
+ if (need_augmentation) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION);
+ }
+ localregtab[reg_no].ru_is_off = 1;
+ localregtab[reg_no].ru_value_type = DW_EXPR_OFFSET;
+ localregtab[reg_no].ru_register = reg_num_of_cfa;
+ localregtab[reg_no].ru_offset_or_block_len = factored_N_value *
+ data_alignment_factor;
+
+ fp_register = reg_no;
+ fp_offset = factored_N_value;
+ break;
+ }
+
+ case DW_CFA_restore_extended:
+ {
+ Dwarf_Unsigned lreg;
+
+ DECODE_LEB128_UWORD(instr_ptr, lreg);
+ reg_no = (reg_num_type) lreg;
+
+ ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);
+
+ if (cie != NULL && cie->ci_initial_table != NULL) {
+ localregtab[reg_no] = cie->ci_initial_table->fr_reg[reg_no];
+ } else {
+ if (!make_instr) {
+ SIMPLE_ERROR_RETURN
+ (DW_DLE_DF_MAKE_INSTR_NO_INIT);
+ }
+ }
+
+ fp_register = reg_no;
+ break;
+ }
+
+ case DW_CFA_undefined:
+ {
+ Dwarf_Unsigned lreg;
+
+ DECODE_LEB128_UWORD(instr_ptr, lreg);
+ reg_no = (reg_num_type) lreg;
+ ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);
+
+ localregtab[reg_no].ru_is_off = 0;
+ localregtab[reg_no].ru_value_type = DW_EXPR_OFFSET;
+ localregtab[reg_no].ru_register =
+ dbg->de_frame_undefined_value_number;
+ localregtab[reg_no].ru_offset_or_block_len = 0;
+
+ fp_register = reg_no;
+ break;
+ }
+
+ case DW_CFA_same_value:
+ {
+ Dwarf_Unsigned lreg;
+
+ DECODE_LEB128_UWORD(instr_ptr, lreg);
+ reg_no = (reg_num_type) lreg;
+ ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);
+
+ localregtab[reg_no].ru_is_off = 0;
+ localregtab[reg_no].ru_value_type = DW_EXPR_OFFSET;
+ localregtab[reg_no].ru_register =
+ dbg->de_frame_same_value_number;
+ localregtab[reg_no].ru_offset_or_block_len = 0;
+ fp_register = reg_no;
+ break;
+ }
+
+ case DW_CFA_register:
+ {
+ Dwarf_Unsigned lreg;
+ reg_num_type reg_noA = 0;
+ reg_num_type reg_noB = 0;
+
+ DECODE_LEB128_UWORD(instr_ptr, lreg);
+ reg_noA = (reg_num_type) lreg;
+
+ ERROR_IF_REG_NUM_TOO_HIGH(reg_noA, reg_count);
+
+ DECODE_LEB128_UWORD(instr_ptr, lreg);
+ reg_noB = (reg_num_type) lreg;
+
+ if (reg_noB > reg_count) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_REG_NUM_TOO_HIGH);
+ }
+
+
+ localregtab[reg_noA].ru_is_off = 0;
+ localregtab[reg_noA].ru_value_type = DW_EXPR_OFFSET;
+ localregtab[reg_noA].ru_register = reg_noB;
+ localregtab[reg_noA].ru_offset_or_block_len = 0;
+
+ fp_register = reg_noA;
+ fp_offset = reg_noB;
+ break;
+ }
+
+ case DW_CFA_remember_state:
+ {
+ stack_table = (Dwarf_Frame)
+ _dwarf_get_alloc(dbg, DW_DLA_FRAME, 1);
+ if (stack_table == NULL) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_ALLOC_FAIL);
+ }
+
+ for (i = 0; i < reg_count; i++)
+ stack_table->fr_reg[i] = localregtab[i];
+ stack_table->fr_cfa_rule = cfa_reg;
+
+ if (top_stack != NULL)
+ stack_table->fr_next = top_stack;
+ top_stack = stack_table;
+
+ break;
+ }
+
+ case DW_CFA_restore_state:
+ {
+ if (top_stack == NULL) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_POP_EMPTY_STACK);
+ }
+ stack_table = top_stack;
+ top_stack = stack_table->fr_next;
+
+ for (i = 0; i < reg_count; i++)
+ localregtab[i] = stack_table->fr_reg[i];
+ cfa_reg = stack_table->fr_cfa_rule;
+
+ dwarf_dealloc(dbg, stack_table, DW_DLA_FRAME);
+ break;
+ }
+
+ case DW_CFA_def_cfa:
+ {
+ Dwarf_Unsigned lreg;
+
+ DECODE_LEB128_UWORD(instr_ptr, lreg);
+ reg_no = (reg_num_type) lreg;
+
+ ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);
+
+ factored_N_value =
+ _dwarf_decode_u_leb128(instr_ptr, &leb128_length);
+ instr_ptr += leb128_length;
+
+ if (need_augmentation) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION);
+ }
+ cfa_reg.ru_is_off = 1;
+ cfa_reg.ru_value_type = DW_EXPR_OFFSET;
+ cfa_reg.ru_register = reg_no;
+ cfa_reg.ru_offset_or_block_len = factored_N_value;
+
+ fp_register = reg_no;
+ fp_offset = factored_N_value;
+ break;
+ }
+
+ case DW_CFA_def_cfa_register:
+ {
+ Dwarf_Unsigned lreg;
+
+ DECODE_LEB128_UWORD(instr_ptr, lreg);
+ reg_no = (reg_num_type) lreg;
+ ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);
+
+ cfa_reg.ru_register = reg_no;
+ /* Do NOT set ru_offset_or_block_len or ru_is_off here.
+ See dwarf2/3 spec. */
+ fp_register = reg_no;
+ break;
+ }
+
+ case DW_CFA_def_cfa_offset:
+ {
+ factored_N_value =
+ _dwarf_decode_u_leb128(instr_ptr, &leb128_length);
+ instr_ptr += leb128_length;
+
+ if (need_augmentation) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION);
+ }
+ /* Do set ru_is_off here, as here factored_N_value
+ counts. */
+ cfa_reg.ru_is_off = 1;
+ cfa_reg.ru_value_type = DW_EXPR_OFFSET;
+ cfa_reg.ru_offset_or_block_len = factored_N_value;
+
+ fp_offset = factored_N_value;
+ break;
+ }
+ case DW_CFA_nop:
+ {
+ break;
+ }
+ /* DWARF3 ops begin here. */
+ case DW_CFA_def_cfa_expression:
+ {
+ /* A single DW_FORM_block representing a dwarf
+ expression. The form block establishes the way to
+ compute the CFA. */
+ Dwarf_Unsigned block_len = 0;
+
+ DECODE_LEB128_UWORD(instr_ptr, block_len);
+ cfa_reg.ru_is_off = 0; /* arbitrary */
+ cfa_reg.ru_value_type = DW_EXPR_EXPRESSION;
+ cfa_reg.ru_offset_or_block_len = block_len;
+ cfa_reg.ru_block = instr_ptr;
+ fp_offset = (Dwarf_Unsigned)(uintptr_t)instr_ptr;
+ instr_ptr += block_len;
+ }
+ break;
+ case DW_CFA_expression:
+ {
+ /* An unsigned leb128 value is the first operand (a
+ register number). The second operand is single
+ DW_FORM_block representing a dwarf expression. The
+ evaluator pushes the CFA on the evaluation stack
+ then evaluates the expression to compute the value
+ of the register contents. */
+ Dwarf_Unsigned lreg = 0;
+ Dwarf_Unsigned block_len = 0;
+
+ DECODE_LEB128_UWORD(instr_ptr, lreg);
+ reg_no = (reg_num_type) lreg;
+ ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);
+ DECODE_LEB128_UWORD(instr_ptr, block_len);
+ localregtab[lreg].ru_is_off = 0; /* arbitrary */
+ localregtab[lreg].ru_value_type = DW_EXPR_EXPRESSION;
+ localregtab[lreg].ru_offset_or_block_len = block_len;
+ localregtab[lreg].ru_block = instr_ptr;
+ fp_offset = (Dwarf_Unsigned)(uintptr_t)instr_ptr;
+ fp_register = reg_no;
+ instr_ptr += block_len;
+ }
+ break;
+ case DW_CFA_offset_extended_sf:
+ {
+ /* The first operand is an unsigned leb128 register
+ number. The second is a signed factored offset.
+ Identical to DW_CFA_offset_extended except the
+ secondoperand is signed */
+ Dwarf_Unsigned lreg;
+
+ DECODE_LEB128_UWORD(instr_ptr, lreg);
+ reg_no = (reg_num_type) lreg;
+ ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);
+ signed_factored_N_value =
+ _dwarf_decode_s_leb128(instr_ptr, &leb128_length);
+ instr_ptr += leb128_length;
+
+ if (need_augmentation) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION);
+ }
+ localregtab[reg_no].ru_is_off = 1;
+ localregtab[reg_no].ru_value_type = DW_EXPR_OFFSET;
+ localregtab[reg_no].ru_register = reg_num_of_cfa;
+ localregtab[reg_no].ru_offset_or_block_len =
+ signed_factored_N_value * data_alignment_factor;
+
+ fp_register = reg_no;
+ fp_offset = signed_factored_N_value;
+ }
+ break;
+ case DW_CFA_def_cfa_sf:
+ {
+ /* The first operand is an unsigned leb128 register
+ number. The second is a signed leb128 factored
+ offset. Identical to DW_CFA_def_cfa except that the
+ second operand is signed and factored. */
+ Dwarf_Unsigned lreg;
+
+ DECODE_LEB128_UWORD(instr_ptr, lreg);
+ reg_no = (reg_num_type) lreg;
+ ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);
+
+ signed_factored_N_value =
+ _dwarf_decode_s_leb128(instr_ptr, &leb128_length);
+ instr_ptr += leb128_length;
+
+ if (need_augmentation) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION);
+ }
+ cfa_reg.ru_is_off = 1;
+ cfa_reg.ru_value_type = DW_EXPR_OFFSET;
+ cfa_reg.ru_register = reg_no;
+ cfa_reg.ru_offset_or_block_len =
+ signed_factored_N_value * data_alignment_factor;
+
+ fp_register = reg_no;
+ fp_offset = signed_factored_N_value;
+ }
+ break;
+ case DW_CFA_def_cfa_offset_sf:
+ {
+ /* The operand is a signed leb128 operand representing
+ a factored offset. Identical to
+ DW_CFA_def_cfa_offset excep the operand is signed
+ and factored. */
+
+ signed_factored_N_value =
+ _dwarf_decode_s_leb128(instr_ptr, &leb128_length);
+ instr_ptr += leb128_length;
+
+ if (need_augmentation) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION);
+ }
+ /* Do set ru_is_off here, as here factored_N_value
+ counts. */
+ cfa_reg.ru_is_off = 1;
+ cfa_reg.ru_value_type = DW_EXPR_OFFSET;
+ cfa_reg.ru_offset_or_block_len =
+ signed_factored_N_value * data_alignment_factor;
+
+ fp_offset = signed_factored_N_value;
+ }
+ break;
+ case DW_CFA_val_offset:
+ {
+ /* The first operand is an unsigned leb128 register
+ number. The second is a factored unsigned offset.
+ Makes the register be a val_offset(N) rule with N =
+ factored_offset*data_alignment_factor. */
+
+ Dwarf_Unsigned lreg;
+
+ DECODE_LEB128_UWORD(instr_ptr, lreg);
+ reg_no = (reg_num_type) lreg;
+
+ ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);
+
+ factored_N_value =
+ _dwarf_decode_u_leb128(instr_ptr, &leb128_length);
+ instr_ptr += leb128_length;
+
+ if (need_augmentation) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION);
+ }
+ /* Do set ru_is_off here, as here factored_N_value
+ counts. */
+ localregtab[reg_no].ru_is_off = 1;
+ localregtab[reg_no].ru_register = reg_num_of_cfa;
+ localregtab[reg_no].ru_value_type = DW_EXPR_VAL_OFFSET;
+ localregtab[reg_no].ru_offset_or_block_len =
+ factored_N_value * data_alignment_factor;
+
+ fp_offset = factored_N_value;
+ break;
+ }
+ case DW_CFA_val_offset_sf:
+ {
+ /* The first operand is an unsigned leb128 register
+ number. The second is a factored signed offset.
+ Makes the register be a val_offset(N) rule with N =
+ factored_offset*data_alignment_factor. */
+ Dwarf_Unsigned lreg;
+
+ DECODE_LEB128_UWORD(instr_ptr, lreg);
+ reg_no = (reg_num_type) lreg;
+
+ ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);
+ signed_factored_N_value =
+ _dwarf_decode_s_leb128(instr_ptr, &leb128_length);
+ instr_ptr += leb128_length;
+
+ if (need_augmentation) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_NO_CIE_AUGMENTATION);
+ }
+ /* Do set ru_is_off here, as here factored_N_value
+ counts. */
+ localregtab[reg_no].ru_is_off = 1;
+ localregtab[reg_no].ru_value_type = DW_EXPR_VAL_OFFSET;
+ localregtab[reg_no].ru_offset_or_block_len =
+ signed_factored_N_value * data_alignment_factor;
+
+ fp_offset = signed_factored_N_value;
+
+ }
+ break;
+ case DW_CFA_val_expression:
+ {
+ /* The first operand is an unsigned leb128 register
+ number. The second is a DW_FORM_block representing a
+ DWARF expression. The rule for the register number
+ becomes a val_expression(E) rule. */
+ Dwarf_Unsigned lreg = 0;
+ Dwarf_Unsigned block_len = 0;
+
+ DECODE_LEB128_UWORD(instr_ptr, lreg);
+ reg_no = (reg_num_type) lreg;
+ ERROR_IF_REG_NUM_TOO_HIGH(reg_no, reg_count);
+ DECODE_LEB128_UWORD(instr_ptr, block_len);
+ localregtab[lreg].ru_is_off = 0; /* arbitrary */
+ localregtab[lreg].ru_value_type = DW_EXPR_VAL_EXPRESSION;
+ localregtab[lreg].ru_offset_or_block_len = block_len;
+ localregtab[lreg].ru_block = instr_ptr;
+ fp_offset = (Dwarf_Unsigned)(uintptr_t)instr_ptr;
+
+ instr_ptr += block_len;
+ fp_register = reg_no;
+
+ }
+ break;
+
+ /* END DWARF3 new ops. */
+
+
+#ifdef DW_CFA_GNU_window_save
+ case DW_CFA_GNU_window_save:
+ {
+ /* no information: this just tells unwinder to restore
+ the window registers from the previous frame's
+ window save area */
+ break;
+ }
+#endif
+#ifdef DW_CFA_GNU_args_size
+ /* single uleb128 is the current arg area size in bytes. No
+ register exists yet to save this in */
+ case DW_CFA_GNU_args_size:
+ {
+ Dwarf_Unsigned lreg;
+
+ DECODE_LEB128_UWORD(instr_ptr, lreg);
+ reg_no = (reg_num_type) lreg;
+
+ break;
+ }
+#endif
+ default:
+ /* ERROR, we have an opcode we know nothing about. Memory
+ leak here, but an error like this is not supposed to
+ happen so we ignore the leak. These used to be ignored,
+ now we notice and report. */
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_FRAME_DECODING_ERROR);
+
+ }
+
+ if (make_instr) {
+ instr_count++;
+
+ curr_instr = (Dwarf_Frame_Op *)
+ _dwarf_get_alloc(dbg, DW_DLA_FRAME_OP, 1);
+ if (curr_instr == NULL) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_ALLOC_FAIL);
+ }
+
+ curr_instr->fp_base_op = fp_base_op;
+ curr_instr->fp_extended_op = fp_extended_op;
+ curr_instr->fp_register = fp_register;
+ curr_instr->fp_offset = fp_offset;
+ curr_instr->fp_instr_offset = fp_instr_offset;
+
+ curr_instr_item = (Dwarf_Chain)
+ _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
+ if (curr_instr_item == NULL) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_ALLOC_FAIL);
+ }
+
+ curr_instr_item->ch_item = curr_instr;
+ if (head_instr_chain == NULL)
+ head_instr_chain = tail_instr_chain = curr_instr_item;
+ else {
+ tail_instr_chain->ch_next = curr_instr_item;
+ tail_instr_chain = curr_instr_item;
+ }
+ }
+ }
+
+ /*
+ If frame instruction decoding was right we would stop exactly at
+ final_instr_ptr. */
+ if (instr_ptr > final_instr_ptr) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_FRAME_DECODING_ERROR);
+ }
+
+ /* Fill in the actual output table, the space the caller passed in. */
+ if (table != NULL) {
+
+ struct Dwarf_Reg_Rule_s *t2reg = table->fr_reg;
+ struct Dwarf_Reg_Rule_s *t3reg = localregtab;
+ struct Dwarf_Reg_Rule_s *t3end = t3reg + reg_count;
+
+ table->fr_loc = current_loc;
+ for (; t3reg < t3end; t3reg++, t2reg++) {
+ *t2reg = *t3reg;
+ }
+
+ /* CONSTCOND */
+ /* Do not update the main table with the cfa_reg.
+ Just leave cfa_reg as cfa_reg. */
+ table->fr_cfa_rule = cfa_reg;
+ }
+
+ /* Dealloc anything remaining on stack. */
+ for (; top_stack != NULL;) {
+ stack_table = top_stack;
+ top_stack = top_stack->fr_next;
+ dwarf_dealloc(dbg, stack_table, DW_DLA_FRAME);
+ }
+
+ if (make_instr) {
+ /* Allocate list of pointers to Dwarf_Frame_Op's. */
+ head_instr_block = (Dwarf_Frame_Op *)
+ _dwarf_get_alloc(dbg, DW_DLA_FRAME_BLOCK, instr_count);
+ if (head_instr_block == NULL) {
+ SIMPLE_ERROR_RETURN(DW_DLE_DF_ALLOC_FAIL);
+ }
+
+ /*
+ Store pointers to Dwarf_Frame_Op's in this list and
+ deallocate the structs that chain the Dwarf_Frame_Op's. */
+ curr_instr_item = head_instr_chain;
+ for (i = 0; i < instr_count; i++) {
+ *(head_instr_block + i) =
+ *(Dwarf_Frame_Op *) curr_instr_item->ch_item;
+ dealloc_instr_item = curr_instr_item;
+ curr_instr_item = curr_instr_item->ch_next;
+ dwarf_dealloc(dbg, dealloc_instr_item->ch_item,
+ DW_DLA_FRAME_OP);
+ dwarf_dealloc(dbg, dealloc_instr_item, DW_DLA_CHAIN);
+ }
+ *ret_frame_instr = head_instr_block;
+
+ *returned_count = (Dwarf_Sword) instr_count;
+ } else {
+ *returned_count = 0;
+ }
+ free(localregtab);
+ return DW_DLV_OK;
+#undef ERROR_IF_REG_NUM_TOO_HIGH
+#undef SIMPLE_ERROR_RETURN
+}
+
+/* Depending on version, either read the return address register
+ as a ubyte or as an leb number.
+ The form of this value changed for DWARF3.
+*/
+Dwarf_Unsigned
+_dwarf_get_return_address_reg(Dwarf_Small * frame_ptr,
+ int version, unsigned long *size)
+{
+ Dwarf_Unsigned uvalue = 0;
+ Dwarf_Word leb128_length = 0;
+
+ if (version == 1) {
+ *size = 1;
+ uvalue = *(unsigned char *) frame_ptr;
+ return uvalue;
+ }
+ uvalue = _dwarf_decode_u_leb128(frame_ptr, &leb128_length);
+ *size = leb128_length;
+ return uvalue;
+}
+
+
+/* Trivial consumer function.
+*/
+int
+dwarf_get_cie_of_fde(Dwarf_Fde fde,
+ Dwarf_Cie * cie_returned, Dwarf_Error * error)
+{
+ if (fde == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_FDE_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ *cie_returned = fde->fd_cie;
+ return DW_DLV_OK;
+
+}
+
+int dwarf_get_cie_index(
+ Dwarf_Cie cie,
+ Dwarf_Signed* index,
+ Dwarf_Error* error )
+{
+ if( cie == NULL )
+ {
+ _dwarf_error(NULL, error, DW_DLE_CIE_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ *index = cie->ci_index;
+ return (DW_DLV_OK);
+}
+
+
+/*
+ For g++ .eh_frame fde and cie.
+ the cie id is different as the
+ definition of the cie_id in an fde
+ is the distance back from the address of the
+ value to the cie.
+ Or 0 if this is a true cie.
+ Non standard dwarf, designed this way to be
+ convenient at run time for an allocated
+ (mapped into memory as part of the running image) section.
+*/
+int
+dwarf_get_fde_list_eh(Dwarf_Debug dbg,
+ Dwarf_Cie ** cie_data,
+ Dwarf_Signed * cie_element_count,
+ Dwarf_Fde ** fde_data,
+ Dwarf_Signed * fde_element_count,
+ Dwarf_Error * error)
+{
+ int res = _dwarf_load_section(dbg, &dbg->de_debug_frame_eh_gnu,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ res = _dwarf_get_fde_list_internal(dbg,
+ cie_data,
+ cie_element_count,
+ fde_data,
+ fde_element_count,
+ dbg->de_debug_frame_eh_gnu.dss_data,
+ dbg->de_debug_frame_eh_gnu.dss_index,
+ dbg->de_debug_frame_eh_gnu.dss_size,
+ /* cie_id_value */ 0,
+ /* use_gnu_cie_calc= */ 1,
+ error);
+ return res;
+}
+
+
+
+/*
+ For standard dwarf .debug_frame
+ cie_id is -1 in a cie, and
+ is the section offset in the .debug_frame section
+ of the cie otherwise. Standard dwarf
+*/
+int
+dwarf_get_fde_list(Dwarf_Debug dbg,
+ Dwarf_Cie ** cie_data,
+ Dwarf_Signed * cie_element_count,
+ Dwarf_Fde ** fde_data,
+ Dwarf_Signed * fde_element_count,
+ Dwarf_Error * error)
+{
+ int res = _dwarf_load_section(dbg, &dbg->de_debug_frame,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ res = _dwarf_get_fde_list_internal(dbg, cie_data,
+ cie_element_count,
+ fde_data,
+ fde_element_count,
+ dbg->de_debug_frame.dss_data,
+ dbg->de_debug_frame.dss_index,
+ dbg->de_debug_frame.dss_size,
+ DW_CIE_ID,
+ /* use_gnu_cie_calc= */ 0,
+ error);
+
+ return res;
+}
+
+
+/*
+ Only works on dwarf sections, not eh_frame
+ Given a Dwarf_Die, see if it has a
+ DW_AT_MIPS_fde attribute and if so use that
+ to get an fde offset.
+ Then create a Dwarf_Fde to return thru the ret_fde pointer.
+ Also creates a cie (pointed at from the Dwarf_Fde).
+*/
+int
+dwarf_get_fde_for_die(Dwarf_Debug dbg,
+ Dwarf_Die die,
+ Dwarf_Fde * ret_fde, Dwarf_Error * error)
+{
+ Dwarf_Attribute attr;
+ Dwarf_Unsigned fde_offset = 0;
+ Dwarf_Signed signdval = 0;
+ Dwarf_Fde new_fde = 0;
+ unsigned char *fde_ptr = 0;
+ unsigned char *cie_ptr = 0;
+ Dwarf_Unsigned cie_id = 0;
+
+ /* Fields for the current Cie being read. */
+ int res = 0;
+ int resattr = 0;
+ int sdatares = 0;
+
+ struct cie_fde_prefix_s prefix;
+ struct cie_fde_prefix_s prefix_c;
+
+ if (die == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DIE_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ resattr = dwarf_attr(die, DW_AT_MIPS_fde, &attr, error);
+ if (resattr != DW_DLV_OK) {
+ return resattr;
+ }
+
+ /* why is this formsdata? FIX */
+ sdatares = dwarf_formsdata(attr, &signdval, error);
+ if (sdatares != DW_DLV_OK) {
+ return sdatares;
+ }
+
+ res = _dwarf_load_section(dbg, &dbg->de_debug_frame,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ fde_offset = signdval;
+ fde_ptr = (dbg->de_debug_frame.dss_data + fde_offset);
+
+
+ /* First read in the 'common prefix' to figure out what * we are to
+ do with this entry. */
+ memset(&prefix_c, 0, sizeof(prefix_c));
+ memset(&prefix, 0, sizeof(prefix));
+ res = dwarf_read_cie_fde_prefix(dbg, fde_ptr,
+ dbg->de_debug_frame.dss_data,
+ dbg->de_debug_frame.dss_index,
+ dbg->de_debug_frame.dss_size,
+ &prefix,
+ error);
+ if (res == DW_DLV_ERROR) {
+ return res;
+ }
+ if (res == DW_DLV_NO_ENTRY)
+ return res;
+ fde_ptr = prefix.cf_addr_after_prefix;
+ cie_id = prefix.cf_cie_id;
+ /* Pass NULL, not section pointer, for 3rd argument.
+ de_debug_frame.dss_data has no eh_frame relevance. */
+ res = dwarf_create_fde_from_after_start(dbg, &prefix,
+ (Dwarf_Small *) NULL,
+ fde_ptr,
+ /* use_gnu_cie_calc= */ 0,
+ /* Dwarf_Cie = */ 0,
+ &new_fde, error);
+ if (res == DW_DLV_ERROR) {
+ return res;
+ } else if (res == DW_DLV_NO_ENTRY) {
+ return res;
+ }
+ /* DW_DLV_OK */
+
+ /* now read the cie corresponding to the fde */
+ cie_ptr = new_fde->fd_section_ptr + cie_id;
+ res = dwarf_read_cie_fde_prefix(dbg, cie_ptr,
+ dbg->de_debug_frame.dss_data,
+ dbg->de_debug_frame.dss_index,
+ dbg->de_debug_frame.dss_size,
+ &prefix_c, error);
+ if (res == DW_DLV_ERROR) {
+ return res;
+ }
+ if (res == DW_DLV_NO_ENTRY)
+ return res;
+
+ cie_ptr = prefix_c.cf_addr_after_prefix;
+ cie_id = prefix_c.cf_cie_id;
+
+ if (cie_id == DW_CIE_ID) {
+ int res2 = 0;
+ Dwarf_Cie new_cie = 0;
+
+ /* Pass NULL, not section pointer, for 3rd argument.
+ de_debug_frame.dss_data has no eh_frame relevance. */
+ res2 = dwarf_create_cie_from_after_start(dbg,
+ &prefix_c,
+ (Dwarf_Small *) NULL,
+ cie_ptr,
+ /* cie_count= */ 0,
+ /* use_gnu_cie_calc= */
+ 0, &new_cie, error);
+ if (res2 == DW_DLV_ERROR) {
+ dwarf_dealloc(dbg, new_fde, DW_DLA_FDE);
+ return res;
+ } else if (res2 == DW_DLV_NO_ENTRY) {
+ dwarf_dealloc(dbg, new_fde, DW_DLA_FDE);
+ return res;
+ }
+ new_fde->fd_cie = new_cie;
+ } else {
+ _dwarf_error(dbg, error, DW_DLE_NO_CIE_FOR_FDE);
+ return (DW_DLV_ERROR);
+ }
+
+ *ret_fde = new_fde;
+ return DW_DLV_OK;
+}
+
+/* A dwarf consumer operation, see the consumer library documentation.
+*/
+int
+dwarf_get_fde_range(Dwarf_Fde fde,
+ Dwarf_Addr * low_pc,
+ Dwarf_Unsigned * func_length,
+ Dwarf_Ptr * fde_bytes,
+ Dwarf_Unsigned * fde_byte_length,
+ Dwarf_Off * cie_offset,
+ Dwarf_Signed * cie_index,
+ Dwarf_Off * fde_offset, Dwarf_Error * error)
+{
+ Dwarf_Debug dbg;
+
+ if (fde == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_FDE_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ dbg = fde->fd_dbg;
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_FDE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+
+ /* We have always already done the section load here, so no need to
+ load the section. We did the section load in order to create the
+ Dwarf_Fde pointer passed in here. */
+
+
+ if (low_pc != NULL)
+ *low_pc = fde->fd_initial_location;
+ if (func_length != NULL)
+ *func_length = fde->fd_address_range;
+ if (fde_bytes != NULL)
+ *fde_bytes = fde->fd_fde_start;
+ if (fde_byte_length != NULL)
+ *fde_byte_length = fde->fd_length;
+ if (cie_offset != NULL)
+ *cie_offset = fde->fd_cie_offset;
+ if (cie_index != NULL)
+ *cie_index = fde->fd_cie_index;
+ if (fde_offset != NULL)
+ *fde_offset = fde->fd_fde_start - fde->fd_section_ptr;
+
+ return DW_DLV_OK;
+}
+
+/* IRIX specific function. The exception tables
+ have C++ destructor information and are
+ at present undocumented. */
+int
+dwarf_get_fde_exception_info(Dwarf_Fde fde,
+ Dwarf_Signed *
+ offset_into_exception_tables,
+ Dwarf_Error * error)
+{
+ Dwarf_Debug dbg;
+
+ dbg = fde->fd_dbg;
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_FDE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ *offset_into_exception_tables =
+ fde->fd_offset_into_exception_tables;
+ return DW_DLV_OK;
+}
+
+
+/* A consumer code function.
+ Given a CIE pointer, return the normal CIE data thru
+ pointers.
+ Special augmentation data is not returned here.
+*/
+int
+dwarf_get_cie_info(Dwarf_Cie cie,
+ Dwarf_Unsigned * bytes_in_cie,
+ Dwarf_Small * ptr_to_version,
+ char **augmenter,
+ Dwarf_Unsigned * code_alignment_factor,
+ Dwarf_Signed * data_alignment_factor,
+ Dwarf_Half * return_address_register,
+ Dwarf_Ptr * initial_instructions,
+ Dwarf_Unsigned * initial_instructions_length,
+ Dwarf_Error * error)
+{
+ Dwarf_Debug dbg;
+
+ if (cie == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_CIE_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ dbg = cie->ci_dbg;
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_CIE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ if (ptr_to_version != NULL)
+ *ptr_to_version = cie->ci_cie_version_number;
+ if (augmenter != NULL)
+ *augmenter = cie->ci_augmentation;
+ if (code_alignment_factor != NULL)
+ *code_alignment_factor = cie->ci_code_alignment_factor;
+ if (data_alignment_factor != NULL)
+ *data_alignment_factor = cie->ci_data_alignment_factor;
+ if (return_address_register != NULL)
+ *return_address_register = cie->ci_return_address_register;
+ if (initial_instructions != NULL)
+ *initial_instructions = cie->ci_cie_instr_start;
+ if (initial_instructions_length != NULL) {
+ *initial_instructions_length = cie->ci_length +
+ cie->ci_length_size +
+ cie->ci_extension_size -
+ (cie->ci_cie_instr_start - cie->ci_cie_start);
+
+ }
+ *bytes_in_cie = (cie->ci_length);
+ return (DW_DLV_OK);
+}
+
+/* Return the register rules for all registers at a given pc.
+*/
+static int
+_dwarf_get_fde_info_for_a_pc_row(Dwarf_Fde fde,
+ Dwarf_Addr pc_requested,
+ Dwarf_Frame table,
+ Dwarf_Half cfa_reg_col_num,
+ Dwarf_Error * error)
+{
+ Dwarf_Debug dbg = 0;
+ Dwarf_Cie cie = 0;
+ int dw_err = 0;
+ Dwarf_Sword icount = 0;
+ int res = 0;
+
+ if (fde == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_FDE_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ dbg = fde->fd_dbg;
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_FDE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ if (pc_requested < fde->fd_initial_location ||
+ pc_requested >=
+ fde->fd_initial_location + fde->fd_address_range) {
+ _dwarf_error(dbg, error, DW_DLE_PC_NOT_IN_FDE_RANGE);
+ return (DW_DLV_ERROR);
+ }
+
+ cie = fde->fd_cie;
+ if (cie->ci_initial_table == NULL) {
+ cie->ci_initial_table = _dwarf_get_alloc(dbg, DW_DLA_FRAME, 1);
+
+ if (cie->ci_initial_table == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ _dwarf_init_regrule_table(cie->ci_initial_table->fr_reg,
+ dbg->de_frame_reg_rules_entry_count,
+ dbg->de_frame_rule_initial_value);
+ _dwarf_init_regrule_table(&cie->ci_initial_table->fr_cfa_rule,
+ 1, dbg->de_frame_rule_initial_value);
+ res = _dwarf_exec_frame_instr( /* make_instr= */ false,
+ /* ret_frame_instr= */ NULL,
+ /* search_pc */ false,
+ /* search_pc_val */ 0,
+ /* location */ 0,
+ cie->ci_cie_instr_start,
+ cie->ci_cie_instr_start + (cie->ci_length +
+ cie->ci_length_size +
+ cie->ci_extension_size -
+ (cie->ci_cie_instr_start -
+ cie->ci_cie_start)),
+ cie->ci_initial_table, cie, dbg,
+ cfa_reg_col_num, &icount,
+ &dw_err);
+ if (res == DW_DLV_ERROR) {
+ _dwarf_error(dbg, error, dw_err);
+ return (res);
+ } else if (res == DW_DLV_NO_ENTRY) {
+ return res;
+ }
+ }
+
+ {
+ Dwarf_Small *instr_end = fde->fd_fde_instr_start +
+ fde->fd_length +
+ fde->fd_length_size +
+ fde->fd_extension_size - (fde->fd_fde_instr_start -
+ fde->fd_fde_start);
+
+ res = _dwarf_exec_frame_instr( /* make_instr= */ false,
+ /* ret_frame_instr= */ NULL,
+ /* search_pc */ true,
+ /* search_pc_val */ pc_requested,
+ fde->fd_initial_location,
+ fde->fd_fde_instr_start,
+ instr_end,
+ table,
+ cie, dbg,
+ cfa_reg_col_num, &icount,
+ &dw_err);
+ }
+ if (res == DW_DLV_ERROR) {
+ _dwarf_error(dbg, error, dw_err);
+ return (res);
+ } else if (res == DW_DLV_NO_ENTRY) {
+ return res;
+ }
+
+ return DW_DLV_OK;
+}
+
+/* A consumer call for efficiently getting the register info
+ for all registers in one call.
+
+ The output table rules array is size DW_REG_TABLE_SIZE.
+ The frame info rules array in fde_table is of size
+ DW_REG_TABLE_SIZE too.
+
+ This interface really only works well with MIPS/IRIX
+ where DW_FRAME_CFA_COL is zero (in that case it's safe).
+
+ It is also restricted to the case where
+ DW_REG_TABLE_SIZE == DW_FRAME_LAST_REG_NUM ==
+ dbg->de_frame_reg_rules_entry_count (true for MIPS/IRIX).
+ If this condition is not met calling this routine can result in
+ incorrect output or in memory corruption.
+
+ It is much better to use dwarf_get_fde_info_for_all_regs3()
+ instead of this interface.
+*/
+int
+dwarf_get_fde_info_for_all_regs(Dwarf_Fde fde,
+ Dwarf_Addr pc_requested,
+ Dwarf_Regtable * reg_table,
+ Dwarf_Addr * row_pc,
+ Dwarf_Error * error)
+{
+
+ /* Table size: DW_REG_TABLE_SIZE */
+ struct Dwarf_Frame_s fde_table;
+ Dwarf_Sword i = 0;
+ struct Dwarf_Reg_Rule_s *rule = NULL;
+ struct Dwarf_Regtable_Entry_s *out_rule = NULL;
+ int res = 0;
+ Dwarf_Debug dbg = 0;
+
+ /* For this interface the size is fixed at compile time. */
+ int output_table_real_data_size = DW_REG_TABLE_SIZE;
+
+ FDE_NULL_CHECKS_AND_SET_DBG(fde, dbg);
+
+ res = dwarf_initialize_fde_table(dbg, &fde_table,
+ output_table_real_data_size,
+ error);
+ if (res != DW_DLV_OK)
+ return res;
+
+ /* _dwarf_get_fde_info_for_a_pc_row will perform more sanity checks
+ */
+ res = _dwarf_get_fde_info_for_a_pc_row(fde, pc_requested,
+ &fde_table, dbg->de_frame_cfa_col_number, error);
+ if (res != DW_DLV_OK) {
+ dwarf_free_fde_table(&fde_table);
+ return res;
+ }
+
+ out_rule = &reg_table->rules[0];
+ rule = &fde_table.fr_reg[0];
+ for (i = 0; i < output_table_real_data_size;
+ i++, ++out_rule, ++rule) {
+ out_rule->dw_offset_relevant = rule->ru_is_off;
+ out_rule->dw_value_type = rule->ru_value_type;
+ out_rule->dw_regnum = rule->ru_register;
+ out_rule->dw_offset = rule->ru_offset_or_block_len;
+ }
+ for (; i < DW_REG_TABLE_SIZE; ++i, ++out_rule) {
+ out_rule->dw_offset_relevant = 0;
+ out_rule->dw_value_type = DW_EXPR_OFFSET;
+ out_rule->dw_regnum = dbg->de_frame_undefined_value_number;
+ out_rule->dw_offset = 0;
+ }
+
+ /* The test is just in case it's not inside the table. For non-MIPS
+ it could be outside the table and that is just fine, it was
+ really a mistake to put it in the table in 1993. */
+ /* CONSTCOND */
+ if (dbg->de_frame_cfa_col_number < DW_REG_TABLE_SIZE) {
+ out_rule = &reg_table->rules[dbg->de_frame_cfa_col_number];
+ out_rule->dw_offset_relevant = fde_table.fr_cfa_rule.ru_is_off;
+ out_rule->dw_value_type = fde_table.fr_cfa_rule.ru_value_type;
+ out_rule->dw_regnum = fde_table.fr_cfa_rule.ru_register;
+ out_rule->dw_offset =
+ fde_table.fr_cfa_rule.ru_offset_or_block_len;
+ }
+
+ if (row_pc != NULL)
+ *row_pc = fde_table.fr_loc;
+ dwarf_free_fde_table(&fde_table);
+ return DW_DLV_OK;
+}
+
+/* A consumer call for efficiently getting the register info
+ for all registers in one call.
+
+ The output table rules array is size output_table_real_data_size.
+ (normally DW_REG_TABLE_SIZE).
+ The frame info rules array in fde_table is normally of size
+ DW_FRAME_LAST_REG_NUM.
+*/
+int
+dwarf_get_fde_info_for_all_regs3(Dwarf_Fde fde,
+ Dwarf_Addr pc_requested,
+ Dwarf_Regtable3 * reg_table,
+ Dwarf_Addr * row_pc,
+ Dwarf_Error * error)
+{
+
+ struct Dwarf_Frame_s fde_table;
+ Dwarf_Sword i = 0;
+ int res = 0;
+ struct Dwarf_Reg_Rule_s *rule = NULL;
+ struct Dwarf_Regtable_Entry3_s *out_rule = NULL;
+ Dwarf_Debug dbg = 0;
+ int output_table_real_data_size = reg_table->rt3_reg_table_size;
+
+ FDE_NULL_CHECKS_AND_SET_DBG(fde, dbg);
+
+ output_table_real_data_size =
+ MIN(output_table_real_data_size,
+ dbg->de_frame_reg_rules_entry_count);
+
+ res = dwarf_initialize_fde_table(dbg, &fde_table,
+ output_table_real_data_size,
+ error);
+
+ /* _dwarf_get_fde_info_for_a_pc_row will perform more sanity checks
+ */
+ res = _dwarf_get_fde_info_for_a_pc_row(fde, pc_requested,
+ &fde_table,
+ dbg->de_frame_cfa_col_number,
+ error);
+ if (res != DW_DLV_OK) {
+ dwarf_free_fde_table(&fde_table);
+ return res;
+ }
+
+ out_rule = &reg_table->rt3_rules[0];
+ rule = &fde_table.fr_reg[0];
+ for (i = 0; i < output_table_real_data_size;
+ i++, ++out_rule, ++rule) {
+ out_rule->dw_offset_relevant = rule->ru_is_off;
+ out_rule->dw_value_type = rule->ru_value_type;
+ out_rule->dw_regnum = rule->ru_register;
+ out_rule->dw_offset_or_block_len = rule->ru_offset_or_block_len;
+ out_rule->dw_block_ptr = rule->ru_block;
+ }
+ for (; i < reg_table->rt3_reg_table_size; i++, ++out_rule) {
+ out_rule->dw_offset_relevant = 0;
+ out_rule->dw_value_type = DW_EXPR_OFFSET;
+ out_rule->dw_regnum = dbg->de_frame_undefined_value_number;
+ out_rule->dw_offset_or_block_len = 0;
+ out_rule->dw_block_ptr = 0;
+ }
+ reg_table->rt3_cfa_rule.dw_offset_relevant =
+ fde_table.fr_cfa_rule.ru_is_off;
+ reg_table->rt3_cfa_rule.dw_value_type =
+ fde_table.fr_cfa_rule.ru_value_type;
+ reg_table->rt3_cfa_rule.dw_regnum =
+ fde_table.fr_cfa_rule.ru_register;
+ reg_table->rt3_cfa_rule.dw_offset_or_block_len =
+ fde_table.fr_cfa_rule.ru_offset_or_block_len;
+ reg_table->rt3_cfa_rule.dw_block_ptr =
+ fde_table.fr_cfa_rule.ru_block;
+
+ if (row_pc != NULL)
+ *row_pc = fde_table.fr_loc;
+
+ dwarf_free_fde_table(&fde_table);
+ return DW_DLV_OK;
+}
+
+
+/* Gets the register info for a single register at a given PC value
+ for the FDE specified.
+
+ This is the old MIPS interface and should no longer be used.
+ Use dwarf_get_fde_info_for_reg3() instead.
+*/
+int
+dwarf_get_fde_info_for_reg(Dwarf_Fde fde,
+ Dwarf_Half table_column,
+ Dwarf_Addr pc_requested,
+ Dwarf_Signed * offset_relevant,
+ Dwarf_Signed * register_num,
+ Dwarf_Signed * offset,
+ Dwarf_Addr * row_pc, Dwarf_Error * error)
+{
+ struct Dwarf_Frame_s fde_table;
+ int res = DW_DLV_ERROR;
+ Dwarf_Debug dbg = 0;
+ int output_table_real_data_size = 0;
+
+ FDE_NULL_CHECKS_AND_SET_DBG(fde, dbg);
+ output_table_real_data_size = dbg->de_frame_reg_rules_entry_count;
+
+ res = dwarf_initialize_fde_table(dbg, &fde_table,
+ output_table_real_data_size,
+ error);
+ if (res != DW_DLV_OK)
+ return res;
+
+ if (table_column >= output_table_real_data_size) {
+ dwarf_free_fde_table(&fde_table);
+ _dwarf_error(dbg, error, DW_DLE_FRAME_TABLE_COL_BAD);
+ return (DW_DLV_ERROR);
+ }
+
+ /* _dwarf_get_fde_info_for_a_pc_row will perform more sanity checks
+ */
+ res =
+ _dwarf_get_fde_info_for_a_pc_row(fde, pc_requested, &fde_table,
+ dbg->de_frame_cfa_col_number, error);
+ if (res != DW_DLV_OK) {
+ dwarf_free_fde_table(&fde_table);
+ return res;
+ }
+
+ if (fde_table.fr_reg[table_column].ru_value_type != DW_EXPR_OFFSET) {
+ /* The problem here is that this interface cannot deal with
+ other sorts of (newer) dwarf frame values. Code must
+ use dwarf_get_fde_info_for_reg3() to get these
+ values correctly. We error rather than return
+ misleading incomplete data. */
+ dwarf_free_fde_table(&fde_table);
+ _dwarf_error(NULL, error,
+ DW_DLE_FRAME_REGISTER_UNREPRESENTABLE);
+ return (DW_DLV_ERROR);
+ }
+ if(table_column == dbg->de_frame_cfa_col_number) {
+ if (register_num != NULL)
+ *register_num = fde_table.fr_cfa_rule.ru_register;
+ if (offset != NULL)
+ *offset = fde_table.fr_cfa_rule.ru_offset_or_block_len;
+ if (row_pc != NULL)
+ *row_pc = fde_table.fr_loc;
+ *offset_relevant = fde_table.fr_cfa_rule.ru_is_off;
+
+ } else {
+ if (register_num != NULL)
+ *register_num = fde_table.fr_reg[table_column].ru_register;
+ if (offset != NULL)
+ *offset = fde_table.fr_reg[table_column].ru_offset_or_block_len;
+ if (row_pc != NULL)
+ *row_pc = fde_table.fr_loc;
+
+ *offset_relevant = fde_table.fr_reg[table_column].ru_is_off;
+ }
+ dwarf_free_fde_table(&fde_table);
+ return DW_DLV_OK;
+}
+
+/* In this interface, table_column of DW_FRAME_CFA_COL
+ is not meaningful.
+ Use dwarf_get_fde_info_for_cfa_reg3() to get the CFA.
+ Call dwarf_set_frame_cfa_value() to set the correct column
+ after calling dwarf_init()
+ (DW_FRAME_CFA_COL3 is a sensible column to use).
+*/
+int
+dwarf_get_fde_info_for_reg3(Dwarf_Fde fde,
+ Dwarf_Half table_column,
+ Dwarf_Addr pc_requested,
+ Dwarf_Small * value_type,
+ Dwarf_Signed * offset_relevant,
+ Dwarf_Signed * register_num,
+ Dwarf_Signed * offset_or_block_len,
+ Dwarf_Ptr * block_ptr,
+ Dwarf_Addr * row_pc_out,
+ Dwarf_Error * error)
+{
+ struct Dwarf_Frame_s fde_table;
+ int res = DW_DLV_ERROR;
+
+ Dwarf_Debug dbg = 0;
+ int table_real_data_size = 0;
+
+ FDE_NULL_CHECKS_AND_SET_DBG(fde, dbg);
+ table_real_data_size = dbg->de_frame_reg_rules_entry_count;
+ res = dwarf_initialize_fde_table(dbg, &fde_table,
+ table_real_data_size, error);
+ if (res != DW_DLV_OK)
+ return res;
+ if (table_column >= table_real_data_size) {
+ dwarf_free_fde_table(&fde_table);
+ _dwarf_error(dbg, error, DW_DLE_FRAME_TABLE_COL_BAD);
+ return (DW_DLV_ERROR);
+ }
+
+ /* _dwarf_get_fde_info_for_a_pc_row will perform more sanity checks
+ */
+ res = _dwarf_get_fde_info_for_a_pc_row(fde, pc_requested, &fde_table,
+ dbg->de_frame_cfa_col_number,
+ error);
+ if (res != DW_DLV_OK) {
+ dwarf_free_fde_table(&fde_table);
+ return res;
+ }
+
+ if (register_num != NULL)
+ *register_num = fde_table.fr_reg[table_column].ru_register;
+ if (offset_or_block_len != NULL)
+ *offset_or_block_len =
+ fde_table.fr_reg[table_column].ru_offset_or_block_len;
+ if (row_pc_out != NULL)
+ *row_pc_out = fde_table.fr_loc;
+ if (block_ptr)
+ *block_ptr = fde_table.fr_reg[table_column].ru_block;
+
+ /* Without value_type the data cannot be understood, so we insist
+ on it being present, we don't test it. */
+ *value_type = fde_table.fr_reg[table_column].ru_value_type;
+ *offset_relevant = (fde_table.fr_reg[table_column].ru_is_off);
+ dwarf_free_fde_table(&fde_table);
+ return DW_DLV_OK;
+
+}
+
+/* For latest DWARF, this is the preferred interface.
+ It more portably deals with the CFA by not
+ making the CFA a column number, which means
+ DW_FRAME_CFA_COL3 becomes, like DW_CFA_SAME_VALUE,
+ a special value, not something one uses as an index.
+
+ Call dwarf_set_frame_cfa_value() to set the correct column
+ after calling dwarf_init()
+ (DW_FRAME_CFA_COL3 is a sensible column to use, and
+ is the default unless '--enable-oldframecol'
+ is used to configure libdwarf). */
+int
+dwarf_get_fde_info_for_cfa_reg3(Dwarf_Fde fde,
+ Dwarf_Addr pc_requested,
+ Dwarf_Small * value_type,
+ Dwarf_Signed * offset_relevant,
+ Dwarf_Signed * register_num,
+ Dwarf_Signed * offset_or_block_len,
+ Dwarf_Ptr * block_ptr,
+ Dwarf_Addr * row_pc_out,
+ Dwarf_Error * error)
+{
+ struct Dwarf_Frame_s fde_table;
+ int res = DW_DLV_ERROR;
+ Dwarf_Debug dbg = 0;
+
+ int table_real_data_size = 0;
+
+ FDE_NULL_CHECKS_AND_SET_DBG(fde, dbg);
+
+ table_real_data_size = dbg->de_frame_reg_rules_entry_count;
+ res = dwarf_initialize_fde_table(dbg, &fde_table,
+ table_real_data_size, error);
+ if (res != DW_DLV_OK)
+ return res;
+ res = _dwarf_get_fde_info_for_a_pc_row(fde, pc_requested, &fde_table,
+ dbg->de_frame_cfa_col_number,error);
+ if (res != DW_DLV_OK) {
+ dwarf_free_fde_table(&fde_table);
+ return res;
+ }
+
+ if (register_num != NULL)
+ *register_num = fde_table.fr_cfa_rule.ru_register;
+ if (offset_or_block_len != NULL)
+ *offset_or_block_len =
+ fde_table.fr_cfa_rule.ru_offset_or_block_len;
+ if (row_pc_out != NULL)
+ *row_pc_out = fde_table.fr_loc;
+ if (block_ptr)
+ *block_ptr = fde_table.fr_cfa_rule.ru_block;
+
+ /* Without value_type the data cannot be understood, so we insist
+ on it being present, we don't test it. */
+ *value_type = fde_table.fr_cfa_rule.ru_value_type;
+ *offset_relevant = fde_table.fr_cfa_rule.ru_is_off;
+ dwarf_free_fde_table(&fde_table);
+ return DW_DLV_OK;
+}
+
+
+
+/*
+ Return pointer to the instructions in the dwarf
+ fde.
+*/
+int
+dwarf_get_fde_instr_bytes(Dwarf_Fde inFde, Dwarf_Ptr * outinstraddr,
+ Dwarf_Unsigned * outaddrlen,
+ Dwarf_Error * error)
+{
+ Dwarf_Unsigned len = 0;
+ unsigned char *instrs = 0;
+ Dwarf_Debug dbg = 0;
+
+ if (inFde == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_FDE_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ dbg = inFde->fd_dbg;
+ if (dbg == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_FDE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ instrs = inFde->fd_fde_instr_start;
+
+ len = (inFde->fd_fde_start + inFde->fd_length +
+ inFde->fd_length_size + inFde->fd_extension_size) - instrs;
+
+ *outinstraddr = instrs;
+ *outaddrlen = len;
+ return DW_DLV_OK;
+}
+
+/* Allows getting an fde from its table via an index.
+ With more error checking than simply indexing oneself.
+*/
+int
+dwarf_get_fde_n(Dwarf_Fde * fde_data,
+ Dwarf_Unsigned fde_index,
+ Dwarf_Fde * returned_fde, Dwarf_Error * error)
+{
+ Dwarf_Debug dbg = 0;
+ Dwarf_Signed fdecount = 0;
+
+ if (fde_data == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_FDE_PTR_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ FDE_NULL_CHECKS_AND_SET_DBG(*fde_data, dbg);
+ /* Assumes fde_data table has at least one entry. */
+ fdecount = fde_data[0]->fd_is_eh?
+ dbg->de_fde_count_eh:dbg->de_fde_count;
+ if (fde_index >= fdecount) {
+ return (DW_DLV_NO_ENTRY);
+ }
+ *returned_fde = (*(fde_data + fde_index));
+ return DW_DLV_OK;
+}
+
+
+/*
+ Lopc and hipc are extensions to the interface to
+ return the range of addresses that are described
+ by the returned fde.
+*/
+int
+dwarf_get_fde_at_pc(Dwarf_Fde * fde_data,
+ Dwarf_Addr pc_of_interest,
+ Dwarf_Fde * returned_fde,
+ Dwarf_Addr * lopc,
+ Dwarf_Addr * hipc, Dwarf_Error * error)
+{
+ Dwarf_Debug dbg = NULL;
+ Dwarf_Fde fde = NULL;
+ Dwarf_Fde entryfde = NULL;
+ Dwarf_Signed fdecount = 0;
+
+ if (fde_data == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_FDE_PTR_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ /* Assumes fde_data table has at least one entry. */
+ entryfde = *fde_data;
+ FDE_NULL_CHECKS_AND_SET_DBG(entryfde, dbg);
+
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_FDE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ fdecount = entryfde->fd_is_eh?
+ dbg->de_fde_count_eh:dbg->de_fde_count;
+ {
+ /* The fde's are sorted by their addresses. Binary search to
+ find correct fde. */
+ Dwarf_Signed low = 0;
+ Dwarf_Signed high = fdecount - 1L;
+ Dwarf_Signed middle = 0;
+ Dwarf_Fde cur_fde;
+
+ while (low <= high) {
+ middle = (low + high) / 2;
+ cur_fde = fde_data[middle];
+ if (pc_of_interest < cur_fde->fd_initial_location) {
+ high = middle - 1;
+ } else if (pc_of_interest >=
+ (cur_fde->fd_initial_location +
+ cur_fde->fd_address_range)) {
+ low = middle + 1;
+ } else {
+ fde = fde_data[middle];
+ break;
+ }
+ }
+ }
+
+ if (fde) {
+ if (lopc != NULL)
+ *lopc = fde->fd_initial_location;
+ if (hipc != NULL)
+ *hipc =
+ fde->fd_initial_location + fde->fd_address_range - 1;
+ *returned_fde = fde;
+ return (DW_DLV_OK);
+ }
+
+ return (DW_DLV_NO_ENTRY);
+}
+
+
+/* Expands a single frame instruction block
+ from a specific cie
+ into a n array of Dwarf_Frame_Op-s.
+ This depends on having the cfa column set sensibly.
+
+ Call dwarf_set_frame_cfa_value() to set the correct column
+ after calling dwarf_init() unless you are using
+ the old MIPS frame interfaces (in which case the default
+ will be ok). (DW_FRAME_CFA_COL3 is a sensible column to use ).
+*/
+int
+dwarf_expand_frame_instructions(Dwarf_Cie cie,
+ Dwarf_Ptr instruction,
+ Dwarf_Unsigned i_length,
+ Dwarf_Frame_Op ** returned_op_list,
+ Dwarf_Signed * returned_op_count,
+ Dwarf_Error * error)
+{
+ Dwarf_Sword instr_count;
+ int res = DW_DLV_ERROR;
+ int dw_err;
+ Dwarf_Debug dbg = 0;
+
+ if (cie == 0) {
+ _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ dbg = cie->ci_dbg;
+
+ if (returned_op_list == 0 || returned_op_count == 0) {
+ _dwarf_error(dbg, error, DW_DLE_RET_OP_LIST_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ /* The cast to Dwarf_Ptr may get a compiler warning, but it is safe
+ as it is just an i_length offset from 'instruction' itself. A
+ caller has made a big mistake if the result is not a valid
+ pointer. */
+ res = _dwarf_exec_frame_instr( /* make_instr= */ true,
+ returned_op_list,
+ /* search_pc */ false,
+ /* search_pc_val */ 0,
+ /* location */ 0,
+ instruction,
+ (Dwarf_Ptr)((char *)instruction + i_length),
+ /* Dwarf_Frame */ NULL,
+ cie,
+ dbg,
+ dbg->de_frame_cfa_col_number, &instr_count,
+ &dw_err);
+ if (res != DW_DLV_OK) {
+ if (res == DW_DLV_ERROR) {
+ _dwarf_error(dbg, error, dw_err);
+ }
+ return (res);
+ }
+
+ *returned_op_count = instr_count;
+ return DW_DLV_OK;
+}
+
+
+/* Used by dwarfdump -v to print offsets, for debugging
+ dwarf info.
+ The dwarf_ version is preferred over the obsolete _dwarf version.
+ _dwarf version kept for compatibility.
+*/
+/* ARGSUSED 4 */
+int
+_dwarf_fde_section_offset(Dwarf_Debug dbg, Dwarf_Fde in_fde,
+ Dwarf_Off * fde_off, Dwarf_Off * cie_off,
+ Dwarf_Error * err)
+{
+ return dwarf_fde_section_offset(dbg,in_fde,fde_off,
+ cie_off,err);
+}
+/* ARGSUSED 4 */
+int
+dwarf_fde_section_offset(Dwarf_Debug dbg, Dwarf_Fde in_fde,
+ Dwarf_Off * fde_off, Dwarf_Off * cie_off,
+ Dwarf_Error * err)
+{
+ char *start = 0;
+ char *loc = 0;
+
+
+
+ start = (char *) in_fde->fd_section_ptr;
+ loc = (char *) in_fde->fd_fde_start;
+
+ *fde_off = (loc - start);
+ *cie_off = in_fde->fd_cie_offset;
+ return DW_DLV_OK;
+}
+
+/* Used by dwarfdump -v to print offsets, for debugging
+ dwarf info.
+ The dwarf_ version is preferred over the obsolete _dwarf version.
+ _dwarf version kept for compatibility.
+*/
+/* ARGSUSED 4 */
+int
+_dwarf_cie_section_offset(Dwarf_Debug dbg, Dwarf_Cie in_cie,
+ Dwarf_Off * cie_off, Dwarf_Error * err)
+{
+ return dwarf_cie_section_offset(dbg,in_cie,cie_off,err);
+}
+/* ARGSUSED 4 */
+int
+dwarf_cie_section_offset(Dwarf_Debug dbg, Dwarf_Cie in_cie,
+ Dwarf_Off * cie_off, Dwarf_Error * err)
+{
+ char *start = 0;
+ char *loc = 0;
+
+ start = (char *) in_cie->ci_section_ptr;
+ loc = (char *) in_cie->ci_cie_start;
+
+ *cie_off = (loc - start);
+ return DW_DLV_OK;
+}
+
+/* Returns a pointer to target-specific augmentation data thru augdata
+ and returns the length of the data thru augdata_len.
+
+ It's up to the consumer code to know how to interpret the bytes
+ of target-specific data (endian issues apply too, these
+ are just raw bytes pointed to).
+ See Linux Standard Base Core Specification version 3.0 for
+ the details on .eh_frame info.
+
+ Returns DW_DLV_ERROR if fde is NULL or some other serious
+ error.
+ Returns DW_DLV_NO_ENTRY if there is no target-specific
+ augmentation data.
+
+ The bytes pointed to are in the Dwarf_Cie, and as long as that
+ is valid the bytes are there. No 'dealloc' call is needed
+ for the bytes.
+*/
+int
+dwarf_get_cie_augmentation_data(Dwarf_Cie cie,
+ Dwarf_Small ** augdata,
+ Dwarf_Unsigned * augdata_len,
+ Dwarf_Error * error)
+{
+ if (cie == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_CIE_NULL);
+ return (DW_DLV_ERROR);
+ }
+ if (cie->ci_gnu_eh_augmentation_len == 0) {
+ return DW_DLV_NO_ENTRY;
+ }
+ *augdata = (Dwarf_Small *) (cie->ci_gnu_eh_augmentation_bytes);
+ *augdata_len = cie->ci_gnu_eh_augmentation_len;
+ return DW_DLV_OK;
+}
+
+
+/* Returns a pointer to target-specific augmentation data thru augdata
+ and returns the length of the data thru augdata_len.
+
+ It's up to the consumer code to know how to interpret the bytes
+ of target-specific data (endian issues apply too, these
+ are just raw bytes pointed to).
+ See Linux Standard Base Core Specification version 3.0 for
+ the details on .eh_frame info.
+
+ Returns DW_DLV_ERROR if fde is NULL or some other serious
+ error.
+ Returns DW_DLV_NO_ENTRY if there is no target-specific
+ augmentation data.
+
+ The bytes pointed to are in the Dwarf_Fde, and as long as that
+ is valid the bytes are there. No 'dealloc' call is needed
+ for the bytes.
+
+*/
+int
+dwarf_get_fde_augmentation_data(Dwarf_Fde fde,
+ Dwarf_Small * *augdata,
+ Dwarf_Unsigned * augdata_len,
+ Dwarf_Error * error)
+{
+ Dwarf_Cie cie = 0;
+
+ if (fde == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_FDE_NULL);
+ return (DW_DLV_ERROR);
+ }
+ cie = fde->fd_cie;
+ if (cie == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_CIE_NULL);
+ return (DW_DLV_ERROR);
+ }
+ if (cie->ci_gnu_eh_augmentation_len == 0) {
+ return DW_DLV_NO_ENTRY;
+ }
+ *augdata = (Dwarf_Small *) fde->fd_gnu_eh_augmentation_bytes;
+ *augdata_len = fde->fd_gnu_eh_augmentation_len;
+ return DW_DLV_OK;
+}
+
+
+/* Initialize with same_value , a value which makes sense
+ for IRIX/MIPS.
+ The correct value to use is ABI dependent.
+ For register-windows machines most
+ or all registers should get DW_FRAME_UNDEFINED_VAL as the
+ correct initial value.
+ Some think DW_FRAME_UNDEFINED_VAL is always the
+ right value.
+
+ For some ABIs a setting which varies by register
+ would be more appropriate.
+
+ FIXME. */
+
+static void
+_dwarf_init_regrule_table(struct Dwarf_Reg_Rule_s *t1reg,
+ int last_reg_num, int initial_value)
+{
+ struct Dwarf_Reg_Rule_s *t1end = t1reg + last_reg_num;
+
+ for (; t1reg < t1end; t1reg++) {
+ t1reg->ru_is_off = 0;
+ t1reg->ru_value_type = DW_EXPR_OFFSET;
+ t1reg->ru_register = initial_value;
+ t1reg->ru_offset_or_block_len = 0;
+ t1reg->ru_block = 0;
+ }
+}
+
+#if 0
+/* Used solely for debugging libdwarf. */
+static void
+dump_frame_rule(char *msg, struct Dwarf_Reg_Rule_s *reg_rule)
+{
+ printf
+ ("%s type %s (" DW_PR_DUx "), is_off "
+ DW_PR_DUu " reg " DW_PR_DUu " offset " DW_PR_DUx " blockp "
+ DW_PR_DUx "\n",
+ msg,
+ (reg_rule->ru_value_type == DW_EXPR_OFFSET) ?
+ "DW_EXPR_OFFSET" :
+ (reg_rule->ru_value_type == DW_EXPR_VAL_OFFSET) ?
+ "DW_EXPR_VAL_OFFSET" :
+ (reg_rule->ru_value_type == DW_EXPR_VAL_EXPRESSION) ?
+ "DW_EXPR_VAL_EXPRESSION" :
+ (reg_rule->ru_value_type == DW_EXPR_EXPRESSION) ?
+ "DW_EXPR_EXPRESSION" : "Unknown",
+ (Dwarf_Unsigned) reg_rule->ru_value_type,
+ (Dwarf_Unsigned) reg_rule->ru_is_off,
+ (Dwarf_Unsigned) reg_rule->ru_register,
+ (Dwarf_Unsigned) reg_rule->ru_offset_or_block_len,
+ (Dwarf_Unsigned) reg_rule->ru_block);
+ return;
+}
+#endif
+
+/* This allows consumers to set the 'initial value' so that
+ an ISA/ABI specific default can be used, dynamically,
+ at run time. Useful for dwarfdump and non-MIPS architectures..
+ The value defaults to one of
+ DW_FRAME_SAME_VALUE or DW_FRAME_UNKNOWN_VALUE
+ but dwarfdump can dump multiple ISA/ABI objects so
+ we may want to get this set to what the ABI says is correct.
+
+ Returns the value that was present before we changed it here.
+*/
+Dwarf_Half
+dwarf_set_frame_rule_initial_value(Dwarf_Debug dbg, Dwarf_Half value)
+{
+ Dwarf_Half orig = dbg->de_frame_rule_initial_value;
+ dbg->de_frame_rule_initial_value = value;
+ return orig;
+}
+
+/* The following spelling for backwards compatibility. */
+Dwarf_Half
+dwarf_set_frame_rule_inital_value(Dwarf_Debug dbg, Dwarf_Half value)
+{
+ return dwarf_set_frame_rule_initial_value(dbg,value);
+}
+
+/* This allows consumers to set the array size of the reg rules
+ table so that
+ an ISA/ABI specific value can be used, dynamically,
+ at run time. Useful for non-MIPS archtectures.
+ The value defaults to DW_FRAME_LAST_REG_NUM.
+ but dwarfdump can dump multiple ISA/ABI objects so
+ consumers want to get this set to what the ABI says is correct.
+
+ Returns the value that was present before we changed it here.
+*/
+
+Dwarf_Half
+dwarf_set_frame_rule_table_size(Dwarf_Debug dbg, Dwarf_Half value)
+{
+ Dwarf_Half orig = dbg->de_frame_reg_rules_entry_count;
+ dbg->de_frame_reg_rules_entry_count = value;
+ return orig;
+}
+/* This allows consumers to set the CFA register value
+ * so that an ISA/ABI specific value can be used, dynamically,
+ * at run time. Useful for non-MIPS archtectures.
+ * The value defaults to DW_FRAME_CFA_COL3 and should be
+ * higher than any real register in the ABI.
+ * Dwarfdump can dump multiple ISA/ABI objects so
+ * consumers want to get this set to what the ABI says is correct.
+
+ * Returns the value that was present before we changed it here.
+ * */
+
+Dwarf_Half
+dwarf_set_frame_cfa_value(Dwarf_Debug dbg, Dwarf_Half value)
+{
+ Dwarf_Half orig = dbg->de_frame_cfa_col_number;
+ dbg->de_frame_cfa_col_number = value;
+ return orig;
+}
+/* Similar to above, but for the other crucial fields for frames. */
+Dwarf_Half
+dwarf_set_frame_same_value(Dwarf_Debug dbg, Dwarf_Half value)
+{
+ Dwarf_Half orig = dbg->de_frame_same_value_number;
+ dbg->de_frame_same_value_number = value;
+ return orig;
+}
+Dwarf_Half
+dwarf_set_frame_undefined_value(Dwarf_Debug dbg, Dwarf_Half value)
+{
+ Dwarf_Half orig = dbg->de_frame_same_value_number;
+ dbg->de_frame_undefined_value_number = value;
+ return orig;
+}
+
+
+
+
+
+static int
+dwarf_initialize_fde_table(Dwarf_Debug dbg,
+ struct Dwarf_Frame_s *fde_table,
+ unsigned table_real_data_size,
+ Dwarf_Error * error)
+{
+ unsigned entry_size = sizeof(struct Dwarf_Frame_s);
+
+ fde_table->fr_loc = 0;
+ fde_table->fr_reg_count = table_real_data_size;
+ fde_table->fr_next = 0;
+
+ fde_table->fr_reg = (struct Dwarf_Reg_Rule_s *)
+ calloc(entry_size, table_real_data_size);
+ if (fde_table->fr_reg == 0) {
+ _dwarf_error(dbg, error, DW_DLE_DF_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ return DW_DLV_OK;
+
+}
+static void
+dwarf_free_fde_table(struct Dwarf_Frame_s *fde_table)
+{
+ free(fde_table->fr_reg);
+ fde_table->fr_reg_count = 0;
+ fde_table->fr_reg = 0;
+}
+
+
+/* Return DW_DLV_OK if we succeed. else return DW_DLV_ERROR.
+*/
+int
+_dwarf_frame_constructor(Dwarf_Debug dbg, void *frame)
+{
+ struct Dwarf_Frame_s *fp = frame;
+
+ if (!dbg) {
+ return DW_DLV_ERROR;
+ }
+
+ fp->fr_reg = calloc(dbg->de_frame_reg_rules_entry_count,
+ sizeof(struct Dwarf_Reg_Rule_s));
+ if (!fp->fr_reg) {
+ return DW_DLV_ERROR;
+ }
+ fp->fr_reg_count = dbg->de_frame_reg_rules_entry_count;
+ return DW_DLV_OK;
+}
+
+void
+_dwarf_frame_destructor(void *frame)
+{
+ struct Dwarf_Frame_s *fp = frame;
+
+ if (fp->fr_reg) {
+ free(fp->fr_reg);
+ }
+ fp->fr_reg = 0;
+ fp->fr_reg_count = 0;
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_frame.h b/usr/src/lib/libdwarf/common/dwarf_frame.h
new file mode 100644
index 0000000000..ceb686335b
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_frame.h
@@ -0,0 +1,421 @@
+/*
+
+ Copyright (C) 2000, 2004, 2006 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
+
+*/
+
+
+
+/* The dwarf 2.0 standard dictates that only the following
+ * fields can be read when an unexpected augmentation string
+ * (in the cie) is encountered: CIE length, CIE_id, version and
+ * augmentation; FDE: length, CIE pointer, initial location and
+ * address range. Unfortunately, with the above restrictions, it
+ * is impossible to read the instruction table from a CIE or a FDE
+ * when a new augmentation string is encountered.
+ * To fix this problem, the following layout is used, if the
+ * augmentation string starts with the string "z".
+ * CIE FDE
+ * length length
+ * CIE_id CIE_pointer
+ * version initial_location
+ * augmentation address_range
+ * length_of_augmented_fields (*NEW*)
+ * code_alignment_factor Any new fields as necessary
+ * data_alignment_factor instruction_table
+ * return_address
+ * length_of_augmented fields
+ * Any new fields as necessary
+ * initial_instructions
+ *
+ * The type of all the old data items are the same as what is
+ * described in dwarf 2.0 standard. The length_of_augmented_fields
+ * is an LEB128 data item that denotes the size (in bytes) of
+ * the augmented fields (not including the size of
+ * "length_of_augmented_fields" itself).
+
+ * Handling of cie augmentation strings is necessarly a heuristic.
+ * See dwarf_frame.c for the currently known augmentation strings.
+
+
+ ---START SGI-ONLY COMMENT:
+ * SGI-IRIX versions of cie or fde were intended to use "z1", "z2" as the
+ * augmenter strings if required for new augmentation.
+ * However, that never happened (as of March 2005).
+ *
+ * The fde's augmented by the string "z" have a new field
+ * (signed constant, 4 byte field)
+ * called offset_into_exception_tables, following the
+ * length_of_augmented field. This field contains an offset
+ * into the "_MIPS_eh_region", which describes
+ * the IRIX CC exception handling tables.
+ ---END SGI-ONLY COMMENT
+
+
+ * GNU .eh_frame has an augmentation string of z[RLP]* (gcc 3.4)
+ * The similarity to IRIX 'z' (and proposed but never
+ * implemented IRIX z1, z2 etc) was confusing things.
+ * If the section is .eh_frame then 'z' means GNU exception
+ * information 'Augmentation Data' not IRIX 'z'.
+ * See The Linux Standard Base Core Specification version 3.0
+ */
+
+#define DW_DEBUG_FRAME_VERSION 1 /* DWARF2 */
+#define DW_DEBUG_FRAME_VERSION3 3 /* DWARF3 */
+#define DW_DEBUG_FRAME_VERSION4 4 /* DWARF4 */
+/* The following is SGI/IRIX specific, and probably no longer
+ in use anywhere. */
+#define DW_DEBUG_FRAME_AUGMENTER_STRING "mti v1"
+
+/* The value of the offset field for Cie's. */
+#define DW_CIE_OFFSET ~(0x0)
+
+/* The augmentation string may be NULL. */
+#define DW_EMPTY_STRING ""
+
+#define DW_FRAME_INSTR_OPCODE_SHIFT 6
+#define DW_FRAME_INSTR_OFFSET_MASK 0x3f
+
+/*
+ This struct denotes the rule for a register in a row of
+ the frame table. In other words, it is one element of
+ the table.
+*/
+struct Dwarf_Reg_Rule_s {
+
+ /*
+ Is a flag indicating whether the rule includes the offset
+ field, ie whether the ru_offset field is valid or not.
+ Applies only if DW_EXPR_OFFSET or DW_EXPR_VAL_OFFSET.
+ It is important, since reg+offset (offset of 0) is different from
+ just 'register' since the former means 'read memory at address
+ given by the sum of register contents plus offset to get the
+ value'. whereas the latter means 'the value is in the register'.
+
+ The 'register' numbers are either real registers (ie, table
+ columns defined as real registers) or defined entries that are
+ not really hardware registers, such as DW_FRAME_SAME_VAL or
+ DW_FRAME_CFA_COL.
+
+ */
+ Dwarf_Sbyte ru_is_off;
+
+ /* DW_EXPR_OFFSET (0, DWARF2)
+ DW_EXPR_VAL_OFFSET 1 (dwarf2/3)
+ DW_EXPR_EXPRESSION 2 (dwarf2/3)
+ DW_EXPR_VAL_EXPRESSION 3 (dwarf2/3)
+ See dwarf_frame.h. */
+ Dwarf_Sbyte ru_value_type;
+
+ /* Register involved in this rule. */
+ Dwarf_Half ru_register;
+
+ /* Offset to add to register, if indicated by ru_is_offset
+ and if DW_EXPR_OFFSET or DW_EXPR_VAL_OFFSET.
+ If DW_EXPR_EXPRESSION or DW_EXPR_VAL_EXPRESSION
+ this is DW_FORM_block block-length, not offset. */
+ Dwarf_Unsigned ru_offset_or_block_len;
+
+ /* For DW_EXPR_EXPRESSION DW_EXPR_VAL_EXPRESSION these is set,
+ else 0. */
+ Dwarf_Small *ru_block;
+};
+
+typedef struct Dwarf_Frame_s *Dwarf_Frame;
+
+/*
+ This structure represents a row of the frame table.
+ Fr_loc is the pc value for this row, and Fr_reg
+ contains the rule for each column.
+
+ Entry DW_FRAME_CFA_COL of fr_reg was the tradional MIPS
+ way of setting CFA. cfa_rule is the new one.
+*/
+struct Dwarf_Frame_s {
+
+ /* Pc value corresponding to this row of the frame table. */
+ Dwarf_Addr fr_loc;
+
+ /* Rules for all the registers in this row. */
+ struct Dwarf_Reg_Rule_s fr_cfa_rule;
+
+ /* fr_reg_count is the the number of
+ entries of the fr_reg array. */
+ unsigned long fr_reg_count;
+ struct Dwarf_Reg_Rule_s *fr_reg;
+
+ Dwarf_Frame fr_next;
+};
+
+typedef struct Dwarf_Frame_Op_List_s *Dwarf_Frame_Op_List;
+
+/* This is used to chain together Dwarf_Frame_Op structures. */
+struct Dwarf_Frame_Op_List_s {
+ Dwarf_Frame_Op *fl_frame_instr;
+ Dwarf_Frame_Op_List fl_next;
+};
+
+/* See dwarf_frame.c for the heuristics used to set the
+ Dwarf_Cie ci_augmentation_type.
+
+ This succinctly helps interpret the size and meaning of .debug_frame
+ and (for gcc) .eh_frame.
+
+ In the case of gcc .eh_frame (gcc 3.3, 3.4)
+ z may be followed by one or more of
+ L R P.
+
+*/
+enum Dwarf_augmentation_type {
+ aug_empty_string, /* Default empty augmentation string. */
+ aug_irix_exception_table, /* IRIX plain "z",
+ for exception handling, IRIX CC compiler.
+ Proposed z1 z2 ... never implemented. */
+ aug_gcc_eh_z, /* gcc z augmentation, (including
+ L R P variations). gcc 3.3 3.4 exception
+ handling in eh_frame. */
+ aug_irix_mti_v1, /* IRIX "mti v1" augmentation string. Probably
+ never in any released SGI-IRIX compiler. */
+ aug_eh, /* For gcc .eh_frame, "eh" is the string.,
+ gcc 1,2, egcs. Older values. */
+ aug_armcc, /* "armcc+" meaning the cfa calculation
+ is corrected to be standard (output by
+ Arm C RVCT 3.0 SP1 and later). See
+ http://sourceware.org/ml/gdb-patches/2006-12/msg00249.html
+ for details. */
+ aug_unknown, /* Unknown augmentation, we cannot do much. */
+ aug_past_last
+};
+
+
+/*
+ This structure contains all the pertinent info for a Cie. Most
+ of the fields are taken straight from the definition of a Cie.
+ Ci_cie_start points to the address (in .debug_frame) where this
+ Cie begins. Ci_cie_instr_start points to the first byte of the
+ frame instructions for this Cie. Ci_dbg points to the associated
+ Dwarf_Debug structure. Ci_initial_table is a pointer to the table
+ row generated by the instructions for this Cie.
+*/
+struct Dwarf_Cie_s {
+ Dwarf_Unsigned ci_length;
+ char *ci_augmentation;
+ Dwarf_Small ci_code_alignment_factor;
+ Dwarf_Sbyte ci_data_alignment_factor;
+ Dwarf_Small ci_return_address_register;
+ Dwarf_Small *ci_cie_start;
+ Dwarf_Small *ci_cie_instr_start;
+ Dwarf_Debug ci_dbg;
+ Dwarf_Frame ci_initial_table;
+ Dwarf_Cie ci_next;
+ Dwarf_Small ci_length_size;
+ Dwarf_Small ci_extension_size;
+ Dwarf_Half ci_cie_version_number;
+ enum Dwarf_augmentation_type ci_augmentation_type;
+
+ /* The following 2 for GNU .eh_frame exception handling
+ Augmentation Data. Set if ci_augmentation_type
+ is aug_gcc_eh_z. Zero if unused. */
+ Dwarf_Unsigned ci_gnu_eh_augmentation_len;
+ Dwarf_Ptr ci_gnu_eh_augmentation_bytes;
+
+ /* These are extracted from the gnu eh_frame
+ augmentation if the
+ augmentation begins with 'z'. See Linux LSB documents.
+ Otherwize these are zero. */
+ unsigned char ci_gnu_personality_handler_encoding;
+ unsigned char ci_gnu_lsda_encoding;
+ unsigned char ci_gnu_fde_begin_encoding;
+
+ /* If 'P' augmentation present, is handler addr. Else
+ is zero. */
+ Dwarf_Addr ci_gnu_personality_handler_addr;
+
+
+ /* In creating list of cie's (which will become an array)
+ record the position so fde can get it on fde creation. */
+ Dwarf_Unsigned ci_index;
+ Dwarf_Small * ci_section_ptr;
+ /* DWARF4 adds address size and segment size to the CIE: the .debug_info
+ section may not always be present to allow libdwarf to
+ find address_size from the compilation-unit. */
+ Dwarf_Half ci_address_size;
+ Dwarf_Half ci_segment_size;
+
+};
+
+/*
+ This structure contains all the pertinent info for a Fde.
+ Most of the fields are taken straight from the definition.
+ fd_cie_index is the index of the Cie associated with this
+ Fde in the list of Cie's for this debug_frame. Fd_cie
+ points to the corresponsing Dwarf_Cie structure. Fd_fde_start
+ points to the start address of the Fde. Fd_fde_instr_start
+ points to the start of the instructions for this Fde. Fd_dbg
+ points to the associated Dwarf_Debug structure.
+*/
+struct Dwarf_Fde_s {
+ Dwarf_Unsigned fd_length;
+ Dwarf_Addr fd_cie_offset;
+ Dwarf_Unsigned fd_cie_index;
+ Dwarf_Cie fd_cie;
+ Dwarf_Addr fd_initial_location;
+ Dwarf_Small *fd_initial_loc_pos;
+ Dwarf_Addr fd_address_range;
+ Dwarf_Small *fd_fde_start;
+ Dwarf_Small *fd_fde_instr_start;
+ Dwarf_Debug fd_dbg;
+
+ /* fd_offset_into_exception_tables is SGI/IRIX exception table
+ offset. Unused and zero if not IRIX .debug_frame. */
+ Dwarf_Signed fd_offset_into_exception_tables;
+
+ Dwarf_Fde fd_next;
+ Dwarf_Small fd_length_size;
+ Dwarf_Small fd_extension_size;
+ /* So we know from an fde which 'count' of fde-s in
+ Dwarf_Debug applies: eh or standard. */
+ Dwarf_Small fd_is_eh;
+ /* The following 2 for GNU .eh_frame exception handling
+ Augmentation Data. Set if CIE ci_augmentation_type
+ is aug_gcc_eh_z. Zero if unused. */
+ Dwarf_Unsigned fd_gnu_eh_augmentation_len;
+ Dwarf_Ptr fd_gnu_eh_augmentation_bytes;
+ Dwarf_Addr fd_gnu_eh_lsda; /* If 'L' augmentation letter
+ present: is address of the
+ Language Specific Data Area (LSDA). If not 'L" is zero. */
+
+ /* The following 3 are about the Elf section the FDEs come from. */
+ Dwarf_Small * fd_section_ptr;
+ Dwarf_Unsigned fd_section_length;
+ Dwarf_Unsigned fd_section_index;
+
+};
+
+
+int
+ _dwarf_frame_address_offsets(Dwarf_Debug dbg, Dwarf_Addr ** addrlist,
+ Dwarf_Off ** offsetlist,
+ Dwarf_Signed * returncount,
+ Dwarf_Error * err);
+
+int
+_dwarf_get_fde_list_internal(Dwarf_Debug dbg,
+ Dwarf_Cie ** cie_data,
+ Dwarf_Signed * cie_element_count,
+ Dwarf_Fde ** fde_data,
+ Dwarf_Signed * fde_element_count,
+ Dwarf_Small * section_ptr,
+ Dwarf_Unsigned section_index,
+ Dwarf_Unsigned section_length,
+ Dwarf_Unsigned cie_id_value,
+ int use_gnu_cie_calc, /* If non-zero,
+ this is gcc eh_frame. */
+ Dwarf_Error * error);
+
+enum Dwarf_augmentation_type
+_dwarf_get_augmentation_type(Dwarf_Debug dbg,
+ Dwarf_Small *augmentation_string,
+ int is_gcc_eh_frame);
+
+Dwarf_Unsigned _dwarf_get_return_address_reg(Dwarf_Small *frame_ptr,
+ int version,
+ unsigned long *size);
+
+/* Temporary recording of crucial cie/fde prefix data.
+ * Vastly simplifies some argument lists.
+ */
+struct cie_fde_prefix_s {
+ /* cf_start_addr is a pointer to the first byte of this fde/cie
+ we are reading now. */
+ Dwarf_Small * cf_start_addr;
+ Dwarf_Small * cf_addr_after_prefix;
+ Dwarf_Unsigned cf_length;
+ int cf_local_length_size;
+ int cf_local_extension_size;
+ Dwarf_Unsigned cf_cie_id;
+ Dwarf_Small * cf_cie_id_addr; /* used for eh_frame calculations. */
+
+ /* Simplifies passing around these values to create fde having
+ these here. */
+ /* cf_section_ptr is a pointer to the first byte
+ of the object section the prefix is read from. */
+ Dwarf_Small * cf_section_ptr;
+ Dwarf_Unsigned cf_section_index;
+ Dwarf_Unsigned cf_section_length;
+};
+
+int
+_dwarf_exec_frame_instr(Dwarf_Bool make_instr,
+ Dwarf_Frame_Op ** ret_frame_instr,
+ Dwarf_Bool search_pc,
+ Dwarf_Addr search_pc_val,
+ Dwarf_Addr initial_loc,
+ Dwarf_Small * start_instr_ptr,
+ Dwarf_Small * final_instr_ptr,
+ Dwarf_Frame table,
+ Dwarf_Cie cie,
+ Dwarf_Debug dbg,
+ Dwarf_Half reg_num_of_cfa,
+ Dwarf_Sword * returned_count,
+ int *returned_error);
+
+
+int dwarf_read_cie_fde_prefix(Dwarf_Debug dbg,
+ Dwarf_Small *frame_ptr_in,
+ Dwarf_Small *section_ptr_in,
+ Dwarf_Unsigned section_index_in,
+ Dwarf_Unsigned section_length_in,
+ struct cie_fde_prefix_s *prefix_out,
+ Dwarf_Error *error);
+
+int dwarf_create_fde_from_after_start(Dwarf_Debug dbg,
+ struct cie_fde_prefix_s * prefix,
+ Dwarf_Small *section_pointer,
+ Dwarf_Small *frame_ptr,
+ int use_gnu_cie_calc,
+ Dwarf_Cie cie_ptr_in,
+ Dwarf_Fde *fde_ptr_out,
+ Dwarf_Error *error);
+
+int dwarf_create_cie_from_after_start(Dwarf_Debug dbg,
+ struct cie_fde_prefix_s *prefix,
+ Dwarf_Small* section_pointer,
+ Dwarf_Small* frame_ptr,
+ Dwarf_Unsigned cie_count,
+ int use_gnu_cie_calc,
+ Dwarf_Cie *cie_ptr_out,
+ Dwarf_Error *error);
+
+
+int _dwarf_frame_constructor(Dwarf_Debug dbg,void * );
+void _dwarf_frame_destructor (void *);
diff --git a/usr/src/lib/libdwarf/common/dwarf_frame2.c b/usr/src/lib/libdwarf/common/dwarf_frame2.c
new file mode 100644
index 0000000000..01b9ec497b
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_frame2.c
@@ -0,0 +1,1540 @@
+/*
+
+ Copyright (C) 2000-2006 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2007-2010 David Anderson. 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
+
+*/
+/* The address of the Free Software Foundation is
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ SGI has moved from the Crittenden Lane address.
+*/
+
+
+/*
+ This implements _dwarf_get_fde_list_internal()
+ and related helper functions for reading cie/fde data.
+*/
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include "dwarf_frame.h"
+#include "dwarf_arange.h" /* using Arange as a way to build a
+ list */
+
+
+static int dwarf_find_existing_cie_ptr(Dwarf_Small * cie_ptr,
+ Dwarf_Cie cur_cie_ptr,
+ Dwarf_Cie * cie_ptr_to_use_out,
+ Dwarf_Cie head_cie_ptr);
+static void dealloc_fde_cie_list_internal(Dwarf_Fde head_fde_ptr,
+ Dwarf_Cie head_cie_ptr);
+static int dwarf_create_cie_from_start(Dwarf_Debug dbg,
+ Dwarf_Small * cie_ptr_val,
+ Dwarf_Small * section_ptr,
+ Dwarf_Unsigned section_index,
+ Dwarf_Unsigned section_length,
+ Dwarf_Small * frame_ptr_end,
+ Dwarf_Unsigned cie_id_value,
+ Dwarf_Unsigned cie_count,
+ int use_gnu_cie_calc,
+ Dwarf_Cie * cie_ptr_to_use_out,
+ Dwarf_Error * error);
+
+static Dwarf_Small *get_cieptr_given_offset(Dwarf_Unsigned cie_id_value,
+ int use_gnu_cie_calc,
+ Dwarf_Small * section_ptr,
+ Dwarf_Small * cie_id_addr);
+static int get_gcc_eh_augmentation(Dwarf_Debug dbg,
+ Dwarf_Small * frame_ptr,
+ unsigned long
+ *size_of_augmentation_data,
+ enum Dwarf_augmentation_type augtype,
+ Dwarf_Small * section_pointer,
+ Dwarf_Small * fde_eh_encoding_out,
+ char *augmentation);
+
+static int
+ gnu_aug_encodings(Dwarf_Debug dbg, char *augmentation,
+ Dwarf_Small * aug_data, Dwarf_Unsigned aug_data_len,
+ Dwarf_Half address_size,
+ unsigned char *pers_hand_enc_out,
+ unsigned char *lsda_enc_out,
+ unsigned char *fde_begin_enc_out,
+ Dwarf_Addr * gnu_pers_addr_out);
+
+
+static int read_encoded_ptr(Dwarf_Debug dbg,
+ Dwarf_Small * section_pointer,
+ Dwarf_Small * input_field,
+ int gnu_encoding,
+ Dwarf_Half address_size,
+ Dwarf_Unsigned * addr,
+ Dwarf_Small ** input_field_out);
+
+
+
+static int qsort_compare(const void *elem1, const void *elem2);
+
+
+/* Adds 'newone' to the end of the list starting at 'head'
+ and makes the new one 'cur'rent. */
+static void
+chain_up_fde(Dwarf_Fde newone, Dwarf_Fde * head, Dwarf_Fde * cur)
+{
+ if (*head == NULL)
+ *head = newone;
+ else {
+ (*cur)->fd_next = newone;
+ }
+ *cur = newone;
+
+}
+
+/* Adds 'newone' to the end of the list starting at 'head'
+ and makes the new one 'cur'rent. */
+static void
+chain_up_cie(Dwarf_Cie newone, Dwarf_Cie * head, Dwarf_Cie * cur)
+{
+ if (*head == NULL) {
+ *head = newone;
+ } else {
+ (*cur)->ci_next = newone;
+ }
+ *cur = newone;
+}
+
+/* The size of the length field plus the
+ value of length must be an integral
+ multiple of the address size. Dwarf4 standard.
+
+ A constant that gives the number of bytes of the CIE
+ structure, not including the length field itself
+ (where length mod <size of an address> == 0)
+ (see Section 7.2.2). Dwarf3 standard.
+
+ A uword constant that gives the number of bytes of
+ the CIE structure, not including the
+ length field, itself (length mod <addressing unit size> == 0).
+ Dwarf2 standard.*/
+static void
+validate_length(Dwarf_Debug dbg,
+ Dwarf_Cie cieptr, Dwarf_Unsigned length,
+ Dwarf_Unsigned length_size,
+ Dwarf_Unsigned extension_size,
+ Dwarf_Small * section_ptr,
+ Dwarf_Small * ciefde_start,
+ const char * cieorfde)
+{
+ Dwarf_Unsigned address_size = cieptr->ci_address_size;
+ Dwarf_Unsigned length_field_summed = length_size + extension_size;
+ Dwarf_Unsigned total_len = length + length_field_summed;
+ Dwarf_Unsigned mod = total_len % address_size;
+
+ if (mod != 0) {
+ char msg[DW_HARMLESS_ERROR_MSG_STRING_SIZE];
+ Dwarf_Unsigned sectionoffset = ciefde_start - section_ptr;
+ snprintf(msg,sizeof(msg),
+ "DW_DLE_DEBUG_FRAME_LENGTH_NOT_MULTIPLE"
+ " len=0x%" DW_PR_DUx
+ ", len size=0x%" DW_PR_DUx
+ ", extn size=0x%" DW_PR_DUx
+ ", totl length=0x%" DW_PR_DUx
+ ", addr size=0x%" DW_PR_DUx
+ ", mod=0x%" DW_PR_DUx " must be zero"
+ " in %s"
+ ", offset 0x%" DW_PR_DUx ".",
+ length,
+ length_size,
+ extension_size,
+ total_len,address_size, mod,
+ cieorfde,
+ sectionoffset);
+ dwarf_insert_harmless_error(dbg,msg);
+ }
+ return;
+}
+
+
+#if 0
+/* For debugging only. */
+static void
+print_prefix(struct cie_fde_prefix_s *prefix, int line)
+{
+ printf("prefix-print, prefix at 0x%lx, line %d\n",
+ (long) prefix, line);
+ printf(" start addr 0x%lx after prefix 0x%lx\n",
+ (long) prefix->cf_start_addr,
+ (long) prefix->cf_addr_after_prefix);
+ printf(" length 0x%" DW_PR_DUx ", len size %d ext size %d\n",
+ (Dwarf_Unsigned) prefix->cf_length,
+ prefix->cf_local_length_size,
+ prefix->cf_local_extension_size);
+ printf(" cie_id 0x%" DW_PR_DUx " cie_id cie_id_addr 0x%lx\n",
+ (Dwarf_Unsigned) prefix->cf_cie_id,
+ (long) prefix->cf_cie_id_addr);
+ printf
+ (" sec ptr 0x%lx sec index %" DW_PR_DSd " sec len 0x%" DW_PR_DUx " sec past end 0x%lx\n",
+ (long) prefix->cf_section_ptr,
+ (Dwarf_Signed) prefix->cf_section_index,
+ (Dwarf_Unsigned) prefix->cf_section_length,
+ (long) prefix->cf_section_ptr + prefix->cf_section_length);
+}
+#endif
+
+
+
+/* Internal function called from various places to create
+ lists of CIEs and FDEs. Not directly called
+ by consumer code */
+int
+_dwarf_get_fde_list_internal(Dwarf_Debug dbg, Dwarf_Cie ** cie_data,
+ Dwarf_Signed * cie_element_count,
+ Dwarf_Fde ** fde_data,
+ Dwarf_Signed * fde_element_count,
+ Dwarf_Small * section_ptr,
+ Dwarf_Unsigned section_index,
+ Dwarf_Unsigned section_length,
+ Dwarf_Unsigned cie_id_value,
+ int use_gnu_cie_calc, Dwarf_Error * error)
+{
+ /* Scans the debug_frame section. */
+ Dwarf_Small *frame_ptr = section_ptr;
+ Dwarf_Small *frame_ptr_end = section_ptr + section_length;
+
+
+
+ /*
+ New_cie points to the Cie being read, and head_cie_ptr and
+ cur_cie_ptr are used for chaining them up in sequence.
+ In case cie's are reused aggressively we need tail_cie_ptr
+ to add to the chain. If we re-use an early cie
+ later on, that does not mean we chain a new cie to the early one,
+ we always chain it to the tail. */
+ Dwarf_Cie head_cie_ptr = NULL;
+ Dwarf_Cie cur_cie_ptr = NULL;
+ Dwarf_Cie tail_cie_ptr = NULL;
+ Dwarf_Word cie_count = 0;
+
+ /*
+ Points to a list of contiguous pointers to Dwarf_Cie structures.
+ */
+ Dwarf_Cie *cie_list_ptr = 0;
+
+
+ /*
+ New_fde points to the Fde being created, and head_fde_ptr and
+ cur_fde_ptr are used to chain them up. */
+ Dwarf_Fde head_fde_ptr = NULL;
+ Dwarf_Fde cur_fde_ptr = NULL;
+ Dwarf_Word fde_count = 0;
+
+ /*
+ Points to a list of contiguous pointers to Dwarf_Fde structures.
+ */
+ Dwarf_Fde *fde_list_ptr = NULL;
+
+ Dwarf_Word i = 0;
+ int res = DW_DLV_ERROR;
+
+ if (frame_ptr == 0) {
+ return DW_DLV_NO_ENTRY;
+ }
+
+ /* We create the fde and cie arrays. Processing each CIE as we come
+ to it or as an FDE refers to it. We cannot process 'late' CIEs
+ late as GNU .eh_frame complexities mean we need the whole CIE
+ before we can process the FDE correctly. */
+ while (frame_ptr < frame_ptr_end) {
+
+ struct cie_fde_prefix_s prefix;
+
+ /* First read in the 'common prefix' to figure out what we are
+ to do with this entry. */
+ memset(&prefix, 0, sizeof(prefix));
+ res = dwarf_read_cie_fde_prefix(dbg,
+ frame_ptr, section_ptr,
+ section_index,
+ section_length, &prefix, error);
+ if (res == DW_DLV_ERROR) {
+ dealloc_fde_cie_list_internal(head_fde_ptr, head_cie_ptr);
+ return res;
+ }
+ if (res == DW_DLV_NO_ENTRY)
+ break;
+ frame_ptr = prefix.cf_addr_after_prefix;
+ if (frame_ptr >= frame_ptr_end) {
+ dealloc_fde_cie_list_internal(head_fde_ptr, head_cie_ptr);
+ _dwarf_error(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD);
+ return DW_DLV_ERROR;
+
+ }
+
+ if (prefix.cf_cie_id == cie_id_value) {
+ /* This is a CIE. */
+ Dwarf_Cie cie_ptr_to_use = 0;
+
+ int res = dwarf_find_existing_cie_ptr(prefix.cf_start_addr,
+ cur_cie_ptr,
+ &cie_ptr_to_use,
+ head_cie_ptr);
+
+ if (res == DW_DLV_OK) {
+ cur_cie_ptr = cie_ptr_to_use;
+ /* Ok. Seen already. */
+ } else if (res == DW_DLV_NO_ENTRY) {
+ /* CIE before its FDE in this case. */
+ res = dwarf_create_cie_from_after_start(dbg,
+ &prefix,
+ section_ptr,
+ frame_ptr,
+ cie_count,
+ use_gnu_cie_calc,
+ &cie_ptr_to_use,
+ error);
+ /* ASSERT: res==DW_DLV_NO_ENTRY impossible. */
+ if (res == DW_DLV_ERROR) {
+ dealloc_fde_cie_list_internal(head_fde_ptr,
+ head_cie_ptr);
+ return res;
+ }
+ /* ASSERT res != DW_DLV_NO_ENTRY */
+ cie_count++;
+ chain_up_cie(cie_ptr_to_use, &head_cie_ptr,
+ &tail_cie_ptr);
+ cur_cie_ptr = tail_cie_ptr;
+ } else { /* res == DW_DLV_ERROR */
+
+ dealloc_fde_cie_list_internal(head_fde_ptr,
+ head_cie_ptr);
+ return res;
+ }
+ frame_ptr = cie_ptr_to_use->ci_cie_start +
+ cie_ptr_to_use->ci_length +
+ cie_ptr_to_use->ci_length_size +
+ cie_ptr_to_use->ci_extension_size;
+ continue;
+ } else {
+ /* this is an FDE, Frame Description Entry, see the Dwarf
+ Spec, section 6.4.1 */
+ int res = DW_DLV_ERROR;
+ Dwarf_Cie cie_ptr_to_use = 0;
+ Dwarf_Fde fde_ptr_to_use = 0;
+
+ /* Do not call this twice on one prefix, as
+ prefix.cf_cie_id_addr is altered as a side effect. */
+ Dwarf_Small *cieptr_val =
+ get_cieptr_given_offset(prefix.cf_cie_id,
+ use_gnu_cie_calc,
+ section_ptr,
+ prefix.cf_cie_id_addr);
+
+ res = dwarf_find_existing_cie_ptr(cieptr_val,
+ cur_cie_ptr,
+ &cie_ptr_to_use,
+ head_cie_ptr);
+ if (res == DW_DLV_OK) {
+ cur_cie_ptr = cie_ptr_to_use;
+ /* Ok. Seen CIE already. */
+ } else if (res == DW_DLV_NO_ENTRY) {
+ res = dwarf_create_cie_from_start(dbg,
+ cieptr_val,
+ section_ptr,
+ section_index,
+ section_length,
+ frame_ptr_end,
+ cie_id_value,
+ cie_count,
+ use_gnu_cie_calc,
+ &cie_ptr_to_use,
+ error);
+ if (res == DW_DLV_ERROR) {
+ dealloc_fde_cie_list_internal(head_fde_ptr,
+ head_cie_ptr);
+ return res;
+ } else if (res == DW_DLV_NO_ENTRY) {
+ return res;
+ }
+ ++cie_count;
+ chain_up_cie(cie_ptr_to_use, &head_cie_ptr,
+ &tail_cie_ptr);
+ cur_cie_ptr = tail_cie_ptr;
+
+ } else {
+ /* DW_DLV_ERROR */
+ return res;
+ }
+
+ res = dwarf_create_fde_from_after_start(dbg,
+ &prefix,
+ section_ptr,
+ frame_ptr,
+ use_gnu_cie_calc,
+ cie_ptr_to_use,
+ &fde_ptr_to_use,
+ error);
+ if (res == DW_DLV_ERROR) {
+ return res;
+ }
+ chain_up_fde(fde_ptr_to_use, &head_fde_ptr, &cur_fde_ptr);
+ fde_count++;
+ /* ASSERT: DW_DLV_OK. */
+ frame_ptr = fde_ptr_to_use->fd_fde_start +
+ fde_ptr_to_use->fd_length +
+ fde_ptr_to_use->fd_length_size +
+ fde_ptr_to_use->fd_extension_size;
+ continue;
+
+ }
+
+ }
+
+ /* Now build list of CIEs from the list. If there are no CIEs
+ there should be no FDEs. */
+ if (cie_count > 0) {
+ cie_list_ptr = (Dwarf_Cie *)
+ _dwarf_get_alloc(dbg, DW_DLA_LIST, cie_count);
+ } else {
+ if(fde_count > 0) {
+ dealloc_fde_cie_list_internal(head_fde_ptr, head_cie_ptr);
+ _dwarf_error(dbg, error, DW_DLE_ORPHAN_FDE);
+ return DW_DLV_ERROR;
+ }
+ dealloc_fde_cie_list_internal(head_fde_ptr, head_cie_ptr);
+ return DW_DLV_NO_ENTRY;
+ }
+ if (cie_list_ptr == NULL) {
+ dealloc_fde_cie_list_internal(head_fde_ptr, head_cie_ptr);
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return DW_DLV_ERROR;
+ }
+ cur_cie_ptr = head_cie_ptr;
+ for (i = 0; i < cie_count; i++) {
+ *(cie_list_ptr + i) = cur_cie_ptr;
+ cur_cie_ptr = cur_cie_ptr->ci_next;
+ }
+
+
+
+ /* Now build array of FDEs from the list.
+ With orphan CIEs (meaning no FDEs) lets not return DW_DLV_NO_ENTRY */
+ if (fde_count > 0) {
+ fde_list_ptr = (Dwarf_Fde *)
+ _dwarf_get_alloc(dbg, DW_DLA_LIST, fde_count);
+ }
+
+ /* It is ok if fde_list_ptr is NULL, we just have no fdes. */
+ cur_fde_ptr = head_fde_ptr;
+ for (i = 0; i < fde_count; i++) {
+ *(fde_list_ptr + i) = cur_fde_ptr;
+ cur_fde_ptr = cur_fde_ptr->fd_next;
+ }
+
+
+ /* Return arguments. */
+ *cie_data = cie_list_ptr;
+ *cie_element_count = cie_count;
+
+ *fde_data = fde_list_ptr;
+ *fde_element_count = fde_count;
+ if(use_gnu_cie_calc) {
+ dbg->de_fde_data_eh = fde_list_ptr;
+ dbg->de_fde_count_eh = fde_count;
+ dbg->de_cie_data_eh = cie_list_ptr;
+ dbg->de_cie_count_eh = cie_count;
+ } else {
+ dbg->de_fde_data = fde_list_ptr;
+ dbg->de_fde_count = fde_count;
+ dbg->de_cie_data = cie_list_ptr;
+ dbg->de_cie_count = cie_count;
+ }
+
+ /* Sort the list by the address so that dwarf_get_fde_at_pc() can
+ binary search this list. */
+ if(fde_count > 0) {
+ qsort((void *) fde_list_ptr, fde_count, sizeof(Dwarf_Ptr),
+ qsort_compare);
+ }
+
+ return (DW_DLV_OK);
+}
+
+/* Internal function, not called by consumer code.
+ 'prefix' has accumulated the info up thru the cie-id
+ and now we consume the rest and build a Dwarf_Cie_s structure.
+*/
+int
+dwarf_create_cie_from_after_start(Dwarf_Debug dbg,
+ struct cie_fde_prefix_s *prefix,
+ Dwarf_Small * section_pointer,
+ Dwarf_Small * frame_ptr,
+ Dwarf_Unsigned cie_count,
+ int use_gnu_cie_calc,
+ Dwarf_Cie * cie_ptr_out,
+ Dwarf_Error * error)
+{
+ Dwarf_Cie new_cie = 0;
+
+ /* egcs-1.1.2 .eh_frame uses 0 as the distinguishing id. sgi uses
+ -1 (in .debug_frame). .eh_frame not quite identical to
+ .debug_frame */
+ /* We here default the address size as it is not present
+ in DWARF2 or DWARF3 cie data, below we set it right if
+ it is present. */
+ Dwarf_Half address_size = dbg->de_pointer_size;
+ Dwarf_Small eh_fde_encoding = 0;
+ Dwarf_Small *augmentation = 0;
+ Dwarf_Half segment_size = 0;
+ Dwarf_Sword data_alignment_factor = -1;
+ Dwarf_Word code_alignment_factor = 4;
+ Dwarf_Unsigned return_address_register = 31;
+ int local_length_size = 0;
+ Dwarf_Word leb128_length = 0;
+ Dwarf_Unsigned cie_aug_data_len = 0;
+ Dwarf_Small *cie_aug_data = 0;
+ Dwarf_Addr gnu_personality_handler_addr = 0;
+ unsigned char gnu_personality_handler_encoding = 0;
+ unsigned char gnu_lsda_encoding = 0;
+ unsigned char gnu_fde_begin_encoding = 0;
+
+
+ enum Dwarf_augmentation_type augt = aug_unknown;
+
+
+ /* this is a CIE, Common Information Entry: See the dwarf spec,
+ section 6.4.1 */
+ Dwarf_Small version = *(Dwarf_Small *) frame_ptr;
+
+ frame_ptr++;
+ if (version != DW_CIE_VERSION && version != DW_CIE_VERSION3 &&
+ version != DW_CIE_VERSION4) {
+ _dwarf_error(dbg, error, DW_DLE_FRAME_VERSION_BAD);
+ return (DW_DLV_ERROR);
+ }
+
+ augmentation = frame_ptr;
+ frame_ptr = frame_ptr + strlen((char *) frame_ptr) + 1;
+ augt = _dwarf_get_augmentation_type(dbg,
+ augmentation, use_gnu_cie_calc);
+ if (augt == aug_eh) {
+ /* REFERENCED *//* Not used in this instance */
+ Dwarf_Unsigned exception_table_addr;
+
+ /* this is per egcs-1.1.2 as on RH 6.0 */
+ READ_UNALIGNED(dbg, exception_table_addr,
+ Dwarf_Unsigned, frame_ptr, local_length_size);
+ frame_ptr += local_length_size;
+ }
+ {
+ Dwarf_Unsigned lreg = 0;
+ unsigned long size = 0;
+
+ if( version == DW_CIE_VERSION4) {
+ address_size = *((unsigned char *)frame_ptr);
+ ++frame_ptr;
+ segment_size = *((unsigned char *)frame_ptr);
+ ++frame_ptr;
+ }
+
+ DECODE_LEB128_UWORD(frame_ptr, lreg);
+ code_alignment_factor = (Dwarf_Word) lreg;
+
+ data_alignment_factor =
+ (Dwarf_Sword) _dwarf_decode_s_leb128(frame_ptr,
+ &leb128_length);
+
+ frame_ptr = frame_ptr + leb128_length;
+
+ return_address_register =
+ _dwarf_get_return_address_reg(frame_ptr, version, &size);
+ if (return_address_register > dbg->de_frame_reg_rules_entry_count) {
+ _dwarf_error(dbg, error, DW_DLE_CIE_RET_ADDR_REG_ERROR);
+ return (DW_DLV_ERROR);
+ }
+ frame_ptr += size;
+ }
+ switch (augt) {
+ case aug_empty_string:
+ break;
+ case aug_irix_mti_v1:
+ break;
+ case aug_irix_exception_table:{
+ Dwarf_Unsigned lreg = 0;
+ Dwarf_Word length_of_augmented_fields;
+
+ /* Decode the length of augmented fields. */
+ DECODE_LEB128_UWORD(frame_ptr, lreg);
+ length_of_augmented_fields = (Dwarf_Word) lreg;
+
+
+ /* set the frame_ptr to point at the instruction start. */
+ frame_ptr += length_of_augmented_fields;
+ }
+ break;
+
+ case aug_eh:{
+
+ int err = 0;
+ unsigned long increment = 0;
+
+ if (!use_gnu_cie_calc) {
+ /* This should be impossible. */
+ _dwarf_error(dbg, error,
+ DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
+ return DW_DLV_ERROR;
+ }
+
+ err = get_gcc_eh_augmentation(dbg, frame_ptr, &increment,
+ augt,
+ prefix->cf_section_ptr,
+ &eh_fde_encoding,
+ (char *) augmentation);
+ if (err == DW_DLV_ERROR) {
+ _dwarf_error(dbg, error,
+ DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
+ return DW_DLV_ERROR;
+ }
+ frame_ptr += increment;
+ break;
+ }
+ case aug_gcc_eh_z:{
+ /* Here we have Augmentation Data Length (uleb128) followed
+ by Augmentation Data bytes. */
+ int res = DW_DLV_ERROR;
+ Dwarf_Unsigned adlen = 0;
+
+ DECODE_LEB128_UWORD(frame_ptr, adlen);
+ cie_aug_data_len = adlen;
+ cie_aug_data = frame_ptr;
+ res = gnu_aug_encodings(dbg,
+ (char *) augmentation,
+ cie_aug_data,
+ cie_aug_data_len,
+ address_size,
+ &gnu_personality_handler_encoding,
+ &gnu_lsda_encoding,
+ &gnu_fde_begin_encoding,
+ &gnu_personality_handler_addr);
+ if (res != DW_DLV_OK) {
+ _dwarf_error(dbg, error,
+ DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
+ return res;
+ }
+
+
+ frame_ptr += adlen;
+ break;
+ }
+ case aug_armcc:
+ break;
+ default:{
+ /* We do not understand the augmentation string. No
+ assumption can be made about any fields other than what
+ we have already read. */
+ frame_ptr = prefix->cf_start_addr +
+ prefix->cf_length + prefix->cf_local_length_size
+ + prefix->cf_local_extension_size;
+ /* FIX -- What are the values of data_alignment_factor,
+ code_alignement_factor, return_address_register and
+ instruction start? They were clearly uninitalized in the
+ previous version and I am leaving them the same way. */
+ break;
+ }
+ } /* End switch on augmentation type. */
+
+ new_cie = (Dwarf_Cie) _dwarf_get_alloc(dbg, DW_DLA_CIE, 1);
+ if (new_cie == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ new_cie->ci_cie_version_number = version;
+ new_cie->ci_initial_table = NULL;
+ new_cie->ci_length = (Dwarf_Word) prefix->cf_length;
+ new_cie->ci_length_size = prefix->cf_local_length_size;
+ new_cie->ci_extension_size = prefix->cf_local_extension_size;
+ new_cie->ci_augmentation = (char *) augmentation;
+
+ new_cie->ci_data_alignment_factor =
+ (Dwarf_Sbyte) data_alignment_factor;
+ new_cie->ci_code_alignment_factor =
+ (Dwarf_Small) code_alignment_factor;
+ new_cie->ci_return_address_register = return_address_register;
+ new_cie->ci_cie_start = prefix->cf_start_addr;
+ new_cie->ci_cie_instr_start = frame_ptr;
+ new_cie->ci_dbg = dbg;
+ new_cie->ci_augmentation_type = augt;
+ new_cie->ci_gnu_eh_augmentation_len = cie_aug_data_len;
+ new_cie->ci_gnu_eh_augmentation_bytes = cie_aug_data;
+ new_cie->ci_gnu_personality_handler_encoding =
+ gnu_personality_handler_encoding;
+ new_cie->ci_gnu_personality_handler_addr =
+ gnu_personality_handler_addr;
+ new_cie->ci_gnu_lsda_encoding = gnu_lsda_encoding;
+ new_cie->ci_gnu_fde_begin_encoding = gnu_fde_begin_encoding;
+
+ new_cie->ci_index = cie_count;
+ new_cie->ci_section_ptr = prefix->cf_section_ptr;
+ /* The Following new in DWARF4 */
+ new_cie->ci_address_size = address_size;
+ new_cie->ci_segment_size = segment_size;
+ validate_length(dbg,new_cie,new_cie->ci_length,
+ new_cie->ci_length_size, new_cie->ci_extension_size,
+ new_cie->ci_section_ptr,
+ new_cie->ci_cie_start,"cie");
+
+ *cie_ptr_out = new_cie;
+ return DW_DLV_OK;
+
+}
+
+
+/* Internal function, not called by consumer code.
+ 'prefix' has accumulated the info up thru the cie-id
+ and now we consume the rest and build a Dwarf_Fde_s structure.
+*/
+
+int
+dwarf_create_fde_from_after_start(Dwarf_Debug dbg,
+ struct cie_fde_prefix_s *prefix,
+ Dwarf_Small * section_pointer,
+ Dwarf_Small * frame_ptr,
+ int use_gnu_cie_calc,
+ Dwarf_Cie cie_ptr_in,
+ Dwarf_Fde * fde_ptr_out,
+ Dwarf_Error * error)
+{
+ Dwarf_Fde new_fde = 0;
+ Dwarf_Cie cieptr = cie_ptr_in;
+ Dwarf_Small *saved_frame_ptr = 0;
+
+ Dwarf_Small *initloc = frame_ptr;
+ Dwarf_Signed offset_into_exception_tables
+ /* must be min dwarf_sfixed in size */
+ = (Dwarf_Signed) DW_DLX_NO_EH_OFFSET;
+ Dwarf_Small *fde_aug_data = 0;
+ Dwarf_Unsigned fde_aug_data_len = 0;
+ Dwarf_Addr cie_base_offset = prefix->cf_cie_id;
+ Dwarf_Addr initial_location = 0; /* must be min de_pointer_size
+ bytes in size */
+ Dwarf_Addr address_range = 0; /* must be min de_pointer_size
+ bytes in size */
+ Dwarf_Half address_size = cie_ptr_in->ci_address_size;
+
+ enum Dwarf_augmentation_type augt = cieptr->ci_augmentation_type;
+
+ if (augt == aug_gcc_eh_z) {
+ /* If z augmentation this is eh_frame, and initial_location and
+ address_range in the FDE are read according to the CIE
+ augmentation string instructions. */
+
+ {
+ Dwarf_Small *fp_updated = 0;
+ int res = read_encoded_ptr(dbg,
+ section_pointer,
+ frame_ptr,
+ cieptr-> ci_gnu_fde_begin_encoding,
+ address_size,
+ &initial_location,
+ &fp_updated);
+ if (res != DW_DLV_OK) {
+ _dwarf_error(dbg, error,
+ DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
+ return DW_DLV_ERROR;
+ }
+ frame_ptr = fp_updated;
+ /* For the address-range it makes no sense to be
+ pc-relative, so we turn it off with a section_pointer of
+ NULL. Masking off DW_EH_PE_pcrel from the
+ ci_gnu_fde_begin_encoding in this call would also work
+ to turn off DW_EH_PE_pcrel. */
+ res = read_encoded_ptr(dbg, (Dwarf_Small *) NULL,
+ frame_ptr,
+ cieptr->ci_gnu_fde_begin_encoding,
+ address_size,
+ &address_range, &fp_updated);
+ if (res != DW_DLV_OK) {
+ _dwarf_error(dbg, error,
+ DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
+ return DW_DLV_ERROR;
+ }
+ frame_ptr = fp_updated;
+ }
+ {
+ Dwarf_Unsigned adlen = 0;
+
+ DECODE_LEB128_UWORD(frame_ptr, adlen);
+ fde_aug_data_len = adlen;
+ fde_aug_data = frame_ptr;
+ frame_ptr += adlen;
+ }
+
+ } else {
+ READ_UNALIGNED(dbg, initial_location, Dwarf_Addr,
+ frame_ptr, address_size);
+ frame_ptr += address_size;
+
+ READ_UNALIGNED(dbg, address_range, Dwarf_Addr,
+ frame_ptr, address_size);
+ frame_ptr += address_size;
+ }
+
+
+
+
+
+ switch (augt) {
+ case aug_irix_mti_v1:
+ case aug_empty_string:
+ break;
+ case aug_irix_exception_table:{
+ Dwarf_Unsigned lreg = 0;
+ Dwarf_Word length_of_augmented_fields = 0;
+
+ DECODE_LEB128_UWORD(frame_ptr, lreg);
+ length_of_augmented_fields = (Dwarf_Word) lreg;
+
+ saved_frame_ptr = frame_ptr;
+ /* The first word is an offset into exception tables.
+ Defined as a 32bit offset even for CC -64. */
+ READ_UNALIGNED(dbg, offset_into_exception_tables,
+ Dwarf_Addr, frame_ptr, sizeof(Dwarf_sfixed));
+ SIGN_EXTEND(offset_into_exception_tables,
+ sizeof(Dwarf_sfixed));
+ frame_ptr = saved_frame_ptr + length_of_augmented_fields;
+ }
+ break;
+ case aug_eh:{
+ Dwarf_Unsigned eh_table_value = 0;
+
+ if (!use_gnu_cie_calc) {
+ /* This should be impossible. */
+ _dwarf_error(dbg, error,
+ DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
+ return DW_DLV_ERROR;
+ }
+
+ /* gnu eh fde case. we do not need to do anything */
+ /*REFERENCED*/ /* Not used in this instance of the
+ macro */
+ READ_UNALIGNED(dbg, eh_table_value,
+ Dwarf_Unsigned, frame_ptr,
+ address_size);
+ frame_ptr += address_size;
+ }
+ break;
+
+ case aug_gcc_eh_z:{
+ /* The Augmentation Data Length is here, followed by the
+ Augmentation Data bytes themselves. */
+ }
+ break;
+ case aug_armcc:
+ break;
+ case aug_past_last:
+ break;
+ case aug_unknown:
+ _dwarf_error(dbg, error, DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
+ return DW_DLV_ERROR;
+ } /* End switch on augmentation type */
+ new_fde = (Dwarf_Fde) _dwarf_get_alloc(dbg, DW_DLA_FDE, 1);
+ if (new_fde == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ new_fde->fd_length = prefix->cf_length;
+ new_fde->fd_length_size = prefix->cf_local_length_size;
+ new_fde->fd_extension_size = prefix->cf_local_extension_size;
+ new_fde->fd_is_eh = use_gnu_cie_calc;
+ new_fde->fd_cie_offset = cie_base_offset;
+ new_fde->fd_cie_index = cieptr->ci_index;
+ new_fde->fd_cie = cieptr;
+ new_fde->fd_initial_location = initial_location;
+ new_fde->fd_initial_loc_pos = initloc;
+ new_fde->fd_address_range = address_range;
+ new_fde->fd_fde_start = prefix->cf_start_addr;
+ new_fde->fd_fde_instr_start = frame_ptr;
+ new_fde->fd_dbg = dbg;
+ new_fde->fd_offset_into_exception_tables =
+ offset_into_exception_tables;
+
+ new_fde->fd_section_ptr = prefix->cf_section_ptr;
+ new_fde->fd_section_index = prefix->cf_section_index;
+ new_fde->fd_section_length = prefix->cf_section_length;
+
+ new_fde->fd_gnu_eh_augmentation_bytes = fde_aug_data;
+ new_fde->fd_gnu_eh_augmentation_len = fde_aug_data_len;
+ validate_length(dbg,cieptr,new_fde->fd_length,
+ new_fde->fd_length_size, new_fde->fd_extension_size,
+ new_fde->fd_section_ptr,new_fde->fd_fde_start,"fde");
+
+
+ *fde_ptr_out = new_fde;
+ return DW_DLV_OK;
+}
+
+/* called by qsort to compare FDE entries.
+ Consumer code expects the array of FDE pointers to be in address order.
+*/
+static int
+qsort_compare(const void *elem1, const void *elem2)
+{
+ Dwarf_Fde fde1 = *(Dwarf_Fde *) elem1;
+ Dwarf_Fde fde2 = *(Dwarf_Fde *) elem2;
+ Dwarf_Addr addr1 = fde1->fd_initial_location;
+ Dwarf_Addr addr2 = fde2->fd_initial_location;
+
+ if (addr1 < addr2) {
+ return -1;
+ } else if (addr1 > addr2) {
+ return 1;
+ }
+ return 0;
+}
+
+
+/* Read in the common cie/fde prefix, including reading
+ * the cie-value which shows which this is: cie or fde.
+ * */
+int
+dwarf_read_cie_fde_prefix(Dwarf_Debug dbg,
+ Dwarf_Small * frame_ptr_in,
+ Dwarf_Small * section_ptr_in,
+ Dwarf_Unsigned section_index_in,
+ Dwarf_Unsigned section_length_in,
+ struct cie_fde_prefix_s *data_out,
+ Dwarf_Error * error)
+{
+ Dwarf_Unsigned length = 0;
+ int local_length_size = 0;
+ int local_extension_size = 0;
+ Dwarf_Small *frame_ptr = frame_ptr_in;
+ Dwarf_Small *cie_ptr_addr = 0;
+ Dwarf_Unsigned cie_id = 0;
+
+ /* READ_AREA_LENGTH updates frame_ptr for consumed bytes */
+ READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned,
+ frame_ptr, local_length_size,
+ local_extension_size);
+
+ if (length == 0) {
+ /* nul bytes at end of section, seen at end of egcs eh_frame
+ sections (in a.out). Take this as meaning no more CIE/FDE
+ data. We should be very close to end of section. */
+ return DW_DLV_NO_ENTRY;
+ }
+
+ cie_ptr_addr = frame_ptr;
+ READ_UNALIGNED(dbg, cie_id, Dwarf_Unsigned,
+ frame_ptr, local_length_size);
+ SIGN_EXTEND(cie_id, local_length_size);
+ frame_ptr += local_length_size;
+
+ data_out->cf_start_addr = frame_ptr_in;
+ data_out->cf_addr_after_prefix = frame_ptr;
+
+ data_out->cf_length = length;
+ data_out->cf_local_length_size = local_length_size;
+ data_out->cf_local_extension_size = local_extension_size;
+ data_out->cf_cie_id = cie_id;
+ data_out->cf_cie_id_addr = cie_ptr_addr;
+ data_out->cf_section_ptr = section_ptr_in;
+ data_out->cf_section_index = section_index_in;
+ data_out->cf_section_length = section_length_in;
+ return DW_DLV_OK;
+}
+
+/* On various errors previously-allocated CIEs and FDEs
+ must be cleaned up.
+ This helps avoid leaks in case of errors.
+*/
+static void
+dealloc_fde_cie_list_internal(Dwarf_Fde head_fde_ptr,
+ Dwarf_Cie head_cie_ptr)
+{
+ Dwarf_Fde curfde = 0;
+ Dwarf_Cie curcie = 0;
+ Dwarf_Fde nextfde = 0;
+ Dwarf_Cie nextcie = 0;
+
+ for (curfde = head_fde_ptr; curfde; curfde = nextfde) {
+ nextfde = curfde->fd_next;
+ dwarf_dealloc(curfde->fd_dbg, curfde, DW_DLA_FDE);
+ }
+ for (curcie = head_cie_ptr; curcie; curcie = nextcie) {
+ Dwarf_Frame frame = curcie->ci_initial_table;
+
+ nextcie = curcie->ci_next;
+ if (frame)
+ dwarf_dealloc(curcie->ci_dbg, frame, DW_DLA_FRAME);
+ dwarf_dealloc(curcie->ci_dbg, curcie, DW_DLA_CIE);
+ }
+}
+
+/* Find the cie whose id value is given: the id
+ * value is, per DWARF2/3, an offset in the section.
+ * For .debug_frame, zero is a legal offset. For
+ * GNU .eh_frame it is not a legal offset.
+ * 'cie_ptr' is a pointer into our section, not an offset. */
+static int
+dwarf_find_existing_cie_ptr(Dwarf_Small * cie_ptr,
+ Dwarf_Cie cur_cie_ptr,
+ Dwarf_Cie * cie_ptr_to_use_out,
+ Dwarf_Cie head_cie_ptr)
+{
+ Dwarf_Cie next = 0;
+
+ if (cur_cie_ptr && cie_ptr == cur_cie_ptr->ci_cie_start) {
+ /* Usually, we use the same cie again and again. */
+ *cie_ptr_to_use_out = cur_cie_ptr;
+ return DW_DLV_OK;
+ }
+ for (next = head_cie_ptr; next; next = next->ci_next) {
+ if (cie_ptr == next->ci_cie_start) {
+ *cie_ptr_to_use_out = next;
+ return DW_DLV_OK;
+ }
+ }
+ return DW_DLV_NO_ENTRY;
+}
+
+
+/* We have a valid cie_ptr_val that has not been
+ * turned into an internal Cie yet. Do so now.
+ * Returns DW_DLV_OK or DW_DLV_ERROR, never
+ * DW_DLV_NO_ENTRY.
+
+ 'section_ptr' - Points to first byte of section data.
+ 'section_length' - Length of the section, in bytes.
+ 'frame_ptr_end' - Points 1-past last byte of section data.
+ * */
+static int
+dwarf_create_cie_from_start(Dwarf_Debug dbg,
+ Dwarf_Small * cie_ptr_val,
+ Dwarf_Small * section_ptr,
+ Dwarf_Unsigned section_index,
+ Dwarf_Unsigned section_length,
+ Dwarf_Small * frame_ptr_end,
+ Dwarf_Unsigned cie_id_value,
+ Dwarf_Unsigned cie_count,
+ int use_gnu_cie_calc,
+ Dwarf_Cie * cie_ptr_to_use_out,
+ Dwarf_Error * error)
+{
+ struct cie_fde_prefix_s prefix;
+ int res = DW_DLV_ERROR;
+ Dwarf_Small *frame_ptr = cie_ptr_val;
+
+ if (frame_ptr < section_ptr || frame_ptr > frame_ptr_end) {
+ _dwarf_error(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD);
+ return DW_DLV_ERROR;
+ }
+ /* First read in the 'common prefix' to figure out what * we are to
+ do with this entry. If it is not a cie * we are in big trouble. */
+ memset(&prefix, 0, sizeof(prefix));
+ res = dwarf_read_cie_fde_prefix(dbg, frame_ptr, section_ptr,
+ section_index, section_length,
+ &prefix, error);
+ if (res == DW_DLV_ERROR) {
+ return res;
+ }
+ if (res == DW_DLV_NO_ENTRY) {
+ /* error. */
+ _dwarf_error(dbg, error, DW_DLE_FRAME_CIE_DECODE_ERROR);
+ return DW_DLV_ERROR;
+
+ }
+
+ if (prefix.cf_cie_id != cie_id_value) {
+ _dwarf_error(dbg, error, DW_DLE_FRAME_CIE_DECODE_ERROR);
+ return DW_DLV_ERROR;
+ }
+ frame_ptr = prefix.cf_addr_after_prefix;
+ res = dwarf_create_cie_from_after_start(dbg,
+ &prefix,
+ section_ptr,
+ frame_ptr,
+ cie_count,
+ use_gnu_cie_calc,
+ cie_ptr_to_use_out, error);
+ return res;
+
+}
+
+
+/* This is for gnu eh frames, the 'z' case.
+ We find the letter involved
+ Return the augmentation character and, if applicable,
+ the personality routine address.
+
+ personality_routine_out -
+ if 'P' is augchar, is personality handler addr.
+ Otherwise is not set.
+ aug_data - if 'P' points to data space of the
+ aug_data_len - length of areas aug_data points to.
+
+*/
+#if 0
+/* For debugging only. */
+void
+dump_bytes(Dwarf_Small * start, long len)
+{
+ Dwarf_Small *end = start + len;
+ Dwarf_Small *cur = start;
+
+ for (; cur < end; cur++) {
+ printf(" byte %d, data %02x\n", (int) (cur - start), *cur);
+ }
+
+}
+#endif
+static int
+gnu_aug_encodings(Dwarf_Debug dbg, char *augmentation,
+ Dwarf_Small * aug_data, Dwarf_Unsigned aug_data_len,
+ Dwarf_Half address_size,
+ unsigned char *pers_hand_enc_out,
+ unsigned char *lsda_enc_out,
+ unsigned char *fde_begin_enc_out,
+ Dwarf_Addr * gnu_pers_addr_out)
+{
+ char *nc = 0;
+ Dwarf_Small *cur_aug_p = aug_data;
+ Dwarf_Small *end_aug_p = aug_data + aug_data_len;
+
+ for (nc = augmentation; *nc; ++nc) {
+ char c = *nc;
+
+ switch (c) {
+ case 'z':
+ /* Means that the augmentation data is present. */
+ continue;
+
+ case 'S':
+ /* Indicates this is a signal stack frame. Debuggers have to do
+ special handling. We don't need to do more than print this flag at
+ the right time, though (see dwarfdump where it prints the augmentation
+ string).
+ A signal stack frame (in some OS's) can only be
+ unwound (backtraced) by knowing it is a signal stack frame
+ (perhaps by noticing the name of the function for the stack frame
+ if the name can be found somehow) and figuring
+ out (or knowing) how the kernel and libc pushed a structure
+ onto the stack and loading registers from that structure.
+ Totally different from normal stack unwinding.
+ This flag gives an unwinder a big leg up by decoupling the
+ 'hint: this is a stack frame' from knowledge like
+ the function name (the name might be unavailable at unwind time).
+ */
+ break;
+
+ case 'L':
+ if (cur_aug_p > end_aug_p) {
+ return DW_DLV_ERROR;
+ }
+ *lsda_enc_out = *(unsigned char *) cur_aug_p;
+ ++cur_aug_p;
+ break;
+ case 'R':
+ /* Followed by a one byte argument giving the
+ pointer encoding for the address pointers in the fde. */
+ if (cur_aug_p >= end_aug_p) {
+ return DW_DLV_ERROR;
+ }
+ *fde_begin_enc_out = *(unsigned char *) cur_aug_p;
+ ++cur_aug_p;
+ break;
+ case 'P':{
+ int res = DW_DLV_ERROR;
+ Dwarf_Small *updated_aug_p = 0;
+ unsigned char encoding = 0;
+
+ if (cur_aug_p >= end_aug_p) {
+ return DW_DLV_ERROR;
+ }
+ encoding = *(unsigned char *) cur_aug_p;
+ *pers_hand_enc_out = encoding;
+ ++cur_aug_p;
+ if (cur_aug_p > end_aug_p) {
+ return DW_DLV_ERROR;
+ }
+ /* DW_EH_PE_pcrel makes no sense here, so we turn it
+ off via a section pointer of NULL. */
+ res = read_encoded_ptr(dbg,
+ (Dwarf_Small *) NULL,
+ cur_aug_p,
+ encoding,
+ address_size,
+ gnu_pers_addr_out,
+ &updated_aug_p);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ cur_aug_p = updated_aug_p;
+ if (cur_aug_p > end_aug_p) {
+ return DW_DLV_ERROR;
+ }
+ }
+ break;
+ default:
+ return DW_DLV_ERROR;
+
+ }
+ }
+
+ return DW_DLV_OK;
+}
+
+/* Given augmentation character (the encoding) giving the
+address format, read the address from input_field
+and return an incremented value 1 past the input bytes of the
+address.
+Push the address read back thru the *addr pointer.
+See LSB (Linux Standar Base) exception handling documents.
+*/
+static int
+read_encoded_ptr(Dwarf_Debug dbg,
+ Dwarf_Small * section_pointer,
+ Dwarf_Small * input_field,
+ int gnu_encoding,
+ Dwarf_Half address_size,
+ Dwarf_Unsigned * addr,
+ Dwarf_Small ** input_field_updated)
+{
+ Dwarf_Word length = 0;
+ int value_type = gnu_encoding & 0xf;
+ Dwarf_Small *input_field_original = input_field;
+
+ if (gnu_encoding == 0xff) {
+ /* There is no data here. */
+
+ *addr = 0;
+ *input_field_updated = input_field;
+ /* Should we return DW_DLV_NO_ENTRY? */
+ return DW_DLV_OK;
+ }
+ switch (value_type) {
+ case DW_EH_PE_absptr:{
+ /* value_type is zero. Treat as pointer size of the object.
+ */
+ Dwarf_Unsigned ret_value = 0;
+
+ READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
+ input_field, address_size);
+ *addr = ret_value;
+ *input_field_updated = input_field + address_size;
+ }
+ break;
+ case DW_EH_PE_uleb128:{
+ Dwarf_Unsigned val = _dwarf_decode_u_leb128(input_field,
+ &length);
+
+ *addr = val;
+ *input_field_updated = input_field + length;
+ }
+ break;
+ case DW_EH_PE_udata2:{
+ Dwarf_Unsigned ret_value = 0;
+
+ READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
+ input_field, 2);
+ *addr = ret_value;
+ *input_field_updated = input_field + 2;
+ }
+ break;
+
+ case DW_EH_PE_udata4:{
+
+ Dwarf_Unsigned ret_value = 0;
+
+ /* ASSERT: sizeof(Dwarf_ufixed) == 4 */
+ READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
+ input_field, sizeof(Dwarf_ufixed));
+ *addr = ret_value;
+ *input_field_updated = input_field + sizeof(Dwarf_ufixed);
+ }
+ break;
+
+ case DW_EH_PE_udata8:{
+ Dwarf_Unsigned ret_value = 0;
+
+ /* ASSERT: sizeof(Dwarf_Unsigned) == 8 */
+ READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
+ input_field, sizeof(Dwarf_Unsigned));
+ *addr = ret_value;
+ *input_field_updated = input_field + sizeof(Dwarf_Unsigned);
+ }
+ break;
+
+ case DW_EH_PE_sleb128:{
+ Dwarf_Signed val = _dwarf_decode_s_leb128(input_field,
+ &length);
+
+ *addr = (Dwarf_Unsigned) val;
+ *input_field_updated = input_field + length;
+ }
+ break;
+ case DW_EH_PE_sdata2:{
+ Dwarf_Unsigned val = 0;
+
+ READ_UNALIGNED(dbg, val, Dwarf_Unsigned, input_field, 2);
+ SIGN_EXTEND(val, 2);
+ *addr = (Dwarf_Unsigned) val;
+ *input_field_updated = input_field + 2;
+ }
+ break;
+
+ case DW_EH_PE_sdata4:{
+ Dwarf_Unsigned val = 0;
+
+ /* ASSERT: sizeof(Dwarf_ufixed) == 4 */
+ READ_UNALIGNED(dbg, val,
+ Dwarf_Unsigned, input_field,
+ sizeof(Dwarf_ufixed));
+ SIGN_EXTEND(val, sizeof(Dwarf_ufixed));
+ *addr = (Dwarf_Unsigned) val;
+ *input_field_updated = input_field + sizeof(Dwarf_ufixed);
+ }
+ break;
+ case DW_EH_PE_sdata8:{
+ Dwarf_Unsigned val = 0;
+
+ /* ASSERT: sizeof(Dwarf_Unsigned) == 8 */
+ READ_UNALIGNED(dbg, val,
+ Dwarf_Unsigned, input_field,
+ sizeof(Dwarf_Unsigned));
+ *addr = (Dwarf_Unsigned) val;
+ *input_field_updated = input_field + sizeof(Dwarf_Unsigned);
+ }
+ break;
+ default:
+ return DW_DLV_ERROR;
+
+ };
+ /* The ELF ABI for gnu does not document the meaning of
+ DW_EH_PE_pcrel, which is awkward. It apparently means the value
+ we got above is pc-relative (meaning section-relative), so we
+ adjust the value. Section_pointer may be null if it is known
+ DW_EH_PE_pcrel cannot apply, such as for .debug_frame or for an
+ address-range value. */
+ if (section_pointer && ((gnu_encoding & 0x70) == DW_EH_PE_pcrel)) {
+ /* Address (*addr) above is pc relative with respect to a
+ section. Add to the offset the base address (from elf) of
+ section and the distance of the field we are reading from
+ the section-beginning to get the actual address. */
+ /* ASSERT: input_field_original >= section_pointer */
+ Dwarf_Unsigned distance =
+ input_field_original - section_pointer;
+ *addr += dbg->de_debug_frame_eh_gnu.dss_addr + distance;
+ }
+
+ return DW_DLV_OK;
+}
+
+
+
+
+/*
+ All augmentation string checking done here now.
+
+ For .eh_frame, gcc from 3.3 uses the z style, earlier used
+ only "eh" as augmentation. We don't yet handle
+ decoding .eh_frame with the z style extensions like L P.
+
+ These are nasty heuristics, but then that's life
+ as augmentations are implementation specific.
+*/
+/* ARGSUSED */
+enum Dwarf_augmentation_type
+_dwarf_get_augmentation_type(Dwarf_Debug dbg,
+ Dwarf_Small * augmentation_string,
+ int is_gcc_eh_frame)
+{
+ enum Dwarf_augmentation_type t = aug_unknown;
+ char *ag_string = (char *) augmentation_string;
+
+ if (ag_string[0] == 0) {
+ /* Empty string. We'll just guess that we know what this means:
+ standard dwarf2/3 with no implementation-defined fields. */
+ t = aug_empty_string;
+ } else if (strcmp(ag_string, DW_DEBUG_FRAME_AUGMENTER_STRING) == 0) {
+ /* The string is "mti v1". Used internally at SGI, probably
+ never shipped. Replaced by "z". Treat like 'nothing
+ special'. */
+ t = aug_irix_mti_v1;
+ } else if (ag_string[0] == 'z') {
+ /* If it's IRIX cc, z means aug_irix_exception_table. z1 z2
+ were designed as for IRIX CC, but never implemented */
+ /* If it's gcc, z may be any of several things. "z" or z
+ followed optionally followed by one or more of L R P, each
+ of which means a value may be present. Should be in eh_frame
+ only, I think. */
+ if (is_gcc_eh_frame) {
+ t = aug_gcc_eh_z;
+ } else if (ag_string[1] == 0) {
+ /* This is the normal IRIX C++ case, where there is an
+ offset into a table in each fde. The table being for
+ IRIX CC exception handling. */
+ /* DW_CIE_AUGMENTER_STRING_V0 "z" */
+ t = aug_irix_exception_table;
+ } /* Else unknown. */
+ } else if (strncmp(ag_string, "eh", 2) == 0) {
+ /* gcc .eh_frame augmentation for egcs and gcc 2.x, at least
+ for x86. */
+ t = aug_eh;
+ } else if (strcmp(ag_string, "armcc+") == 0) {
+ /* Arm uses this string to mean a bug in
+ in Arm compilers was fixed, changing to the standard
+ calculation of the CFA. See
+ http://sourceware.org/ml/gdb-patches/2006-12/msg00249.html
+ for details. */
+ t = aug_armcc;
+ } else {
+
+ }
+ return t;
+}
+
+/* Using augmentation, and version
+ read in the augmentation data for GNU eh.
+
+ Return DW_DLV_OK if we succeeded,
+ DW_DLV_ERR if we fail.
+
+ On success, update 'size_of_augmentation_data' with
+ the length of the fields that are part of augmentation (so the
+ caller can increment frame_ptr appropriately).
+
+ 'frame_ptr' points within section.
+ 'section_pointer' points to section base address in memory.
+*/
+/* ARGSUSED */
+static int
+get_gcc_eh_augmentation(Dwarf_Debug dbg, Dwarf_Small * frame_ptr,
+ unsigned long *size_of_augmentation_data,
+ enum Dwarf_augmentation_type augtype,
+ Dwarf_Small * section_pointer,
+ Dwarf_Small * fde_eh_encoding_out,
+ char *augmentation)
+{
+ char *suffix = 0;
+ unsigned long augdata_size = 0;
+
+ if (augtype == aug_gcc_eh_z) {
+ /* Has leading 'z'. */
+ Dwarf_Word leb128_length = 0;
+
+ /* Dwarf_Unsigned eh_value = */
+ _dwarf_decode_u_leb128(frame_ptr, &leb128_length);
+ augdata_size += leb128_length;
+ frame_ptr += leb128_length;
+ suffix = augmentation + 1;
+ } else {
+ /* Prefix is 'eh'. As in gcc 3.2. No suffix present
+ apparently. */
+ suffix = augmentation + 2;
+ }
+ for (; *suffix; ++suffix) {
+ /* We have no idea what this is as yet. Some extensions beyond
+ dwarf exist which we do not yet handle. */
+ return DW_DLV_ERROR;
+
+ }
+
+ *size_of_augmentation_data = augdata_size;
+ return DW_DLV_OK;
+}
+
+
+/* Make the 'cie_id_addr' consistent across .debug_frame and .eh_frame.
+ Calculate a pointer into section bytes given a cie_id, which is
+ trivial for .debug_frame, but a bit more work for .eh_frame.
+*/
+static Dwarf_Small *
+get_cieptr_given_offset(Dwarf_Unsigned cie_id_value,
+ int use_gnu_cie_calc,
+ Dwarf_Small * section_ptr,
+ Dwarf_Small * cie_id_addr)
+{
+ Dwarf_Small *cieptr = 0;
+
+ if (use_gnu_cie_calc) {
+ /* cie_id value is offset, in section, of the cie_id itself, to
+ use vm ptr of the value, less the value, to get to the cie
+ itself. In addition, munge *cie_id_addr to look *as if* it
+ was from real dwarf. */
+ cieptr = (Dwarf_Small *)(uintptr_t)
+ ((Dwarf_Unsigned)(uintptr_t)cie_id_addr) -
+ ((Dwarf_Unsigned) cie_id_value);
+ } else {
+ /* Traditional dwarf section offset is in cie_id */
+ cieptr = (section_ptr + cie_id_value);
+ }
+ return cieptr;
+}
+
+/* To properly release all spaced used.
+ Earlier approaches (before July 15, 2005)
+ letting client do the dealloc directly left
+ some data allocated.
+ This is directly called by consumer code.
+*/
+void
+dwarf_fde_cie_list_dealloc(Dwarf_Debug dbg,
+ Dwarf_Cie * cie_data,
+ Dwarf_Signed cie_element_count,
+ Dwarf_Fde * fde_data,
+ Dwarf_Signed fde_element_count)
+{
+ Dwarf_Signed i = 0;
+
+ for (i = 0; i < cie_element_count; ++i) {
+ Dwarf_Frame frame = cie_data[i]->ci_initial_table;
+
+ if (frame)
+ dwarf_dealloc(dbg, frame, DW_DLA_FRAME);
+ dwarf_dealloc(dbg, cie_data[i], DW_DLA_CIE);
+ }
+ for (i = 0; i < fde_element_count; ++i) {
+ dwarf_dealloc(dbg, fde_data[i], DW_DLA_FDE);
+ }
+ if (cie_data)
+ dwarf_dealloc(dbg, cie_data, DW_DLA_LIST);
+ if (fde_data)
+ dwarf_dealloc(dbg, fde_data, DW_DLA_LIST);
+
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_frame3.c b/usr/src/lib/libdwarf/common/dwarf_frame3.c
new file mode 100644
index 0000000000..7bd8ec86d5
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_frame3.c
@@ -0,0 +1,290 @@
+/*
+
+ Copyright (C) 2000-2006 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2009-2010 David Anderson. 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
+
+*/
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include "dwarf_frame.h"
+#include "dwarf_arange.h" /* using Arange as a way to build a list */
+
+/*
+ Used by rqs (an IRIX application).
+ Not needed except for that one application.
+ Should be moved to its own source file since
+ it is so rarely needed.
+ Returns DW_DLV_OK if returns the arrays.
+ Returns DW_DLV_NO_ENTRY if no section. ?? (How do I tell?)
+ Returns DW_DLV_ERROR if there is an error.
+
+ Uses DW_FRAME_CFA_COL because IRIX is only DWARF2
+ and that is what IRIX compilers and compatible
+ compilers support on IRIX.
+*/
+int
+_dwarf_frame_address_offsets(Dwarf_Debug dbg, Dwarf_Addr ** addrlist,
+ Dwarf_Off ** offsetlist,
+ Dwarf_Signed * returncount,
+ Dwarf_Error * err)
+{
+ int retval = DW_DLV_OK;
+ int res = DW_DLV_ERROR;
+ Dwarf_Cie *cie_data;
+ Dwarf_Signed cie_count;
+ Dwarf_Fde *fde_data;
+ Dwarf_Signed fde_count;
+ Dwarf_Signed i;
+ Dwarf_Frame_Op *frame_inst;
+ Dwarf_Fde fdep;
+ Dwarf_Cie ciep;
+ Dwarf_Chain curr_chain = 0;
+ Dwarf_Chain head_chain = 0;
+ Dwarf_Chain prev_chain = 0;
+ Dwarf_Arange arange;
+ Dwarf_Unsigned arange_count = 0;
+ Dwarf_Addr *arange_addrs = 0;
+ Dwarf_Off *arange_offsets = 0;
+
+ res = dwarf_get_fde_list(dbg, &cie_data, &cie_count,
+ &fde_data, &fde_count, err);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ res = _dwarf_load_section(dbg, &dbg->de_debug_frame, err);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ for (i = 0; i < cie_count; i++) {
+ Dwarf_Off instoff = 0;
+ Dwarf_Signed initial_instructions_length = 0;
+ Dwarf_Small *instr_end = 0;
+ Dwarf_Sword icount = 0;
+ int j = 0;
+ int dw_err;
+
+ ciep = cie_data[i];
+ instoff = ciep->ci_cie_instr_start - dbg->de_debug_frame.dss_data;
+ initial_instructions_length = ciep->ci_length +
+ ciep->ci_length_size + ciep->ci_extension_size -
+ (ciep->ci_cie_instr_start - ciep->ci_cie_start);
+ instr_end = ciep->ci_cie_instr_start +
+ initial_instructions_length;
+ res = _dwarf_exec_frame_instr( /* make_instr */ true,
+ &frame_inst,
+ /* search_pc= */ false,
+ /* search_pc_val= */ 0,
+ /* location */ 0,
+ ciep->ci_cie_instr_start,
+ instr_end,
+ /* Dwarf_frame= */ 0,
+ /* cie= */ 0,
+ dbg,
+ DW_FRAME_CFA_COL,
+ &icount, &dw_err);
+ if (res == DW_DLV_ERROR) {
+ _dwarf_error(dbg, err, dw_err);
+ return (res);
+ } else if (res == DW_DLV_NO_ENTRY) {
+ continue;
+ }
+
+ for (j = 0; j < icount; ++j) {
+ Dwarf_Frame_Op *finst = frame_inst + j;
+
+ if (finst->fp_base_op == 0 && finst->fp_extended_op == 1) {
+ /* is DW_CFA_set_loc */
+ Dwarf_Addr add = (Dwarf_Addr) finst->fp_offset;
+ Dwarf_Off off = finst->fp_instr_offset + instoff;
+
+ arange = (Dwarf_Arange)
+ _dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1);
+ if (arange == NULL) {
+ _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ arange->ar_address = add;
+ arange->ar_info_offset = off;
+ arange_count++;
+ curr_chain = (Dwarf_Chain)
+ _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
+ if (curr_chain == NULL) {
+ _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ curr_chain->ch_item = arange;
+ if (head_chain == NULL)
+ head_chain = prev_chain = curr_chain;
+ else {
+ prev_chain->ch_next = curr_chain;
+ prev_chain = curr_chain;
+ }
+ }
+ }
+ dwarf_dealloc(dbg, frame_inst, DW_DLA_FRAME_BLOCK);
+
+ }
+ for (i = 0; i < fde_count; i++) {
+ Dwarf_Small *instr_end = 0;
+ Dwarf_Sword icount = 0;
+ Dwarf_Signed instructions_length = 0;
+ Dwarf_Off instoff = 0;
+ Dwarf_Off off = 0;
+ Dwarf_Addr addr = 0;
+ int j = 0;
+ int dw_err;
+
+ fdep = fde_data[i];
+ off = fdep->fd_initial_loc_pos - dbg->de_debug_frame.dss_data;
+ addr = fdep->fd_initial_location;
+ arange = (Dwarf_Arange)
+ _dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1);
+ if (arange == NULL) {
+ _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ arange->ar_address = addr;
+ arange->ar_info_offset = off;
+ arange_count++;
+ curr_chain = (Dwarf_Chain)
+ _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
+ if (curr_chain == NULL) {
+ _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ curr_chain->ch_item = arange;
+ if (head_chain == NULL)
+ head_chain = prev_chain = curr_chain;
+ else {
+ prev_chain->ch_next = curr_chain;
+ prev_chain = curr_chain;
+ }
+
+
+ instoff = fdep->fd_fde_instr_start - dbg->de_debug_frame.dss_data;
+ instructions_length = fdep->fd_length +
+ fdep->fd_length_size + fdep->fd_extension_size -
+ (fdep->fd_fde_instr_start - fdep->fd_fde_start);
+ instr_end = fdep->fd_fde_instr_start + instructions_length;
+ res = _dwarf_exec_frame_instr( /* make_instr */ true,
+ &frame_inst,
+ /* search_pc= */ false,
+ /* search_pc_val= */ 0,
+ /* location */ 0,
+ fdep->fd_fde_instr_start,
+ instr_end,
+ /* Dwarf_frame= */ 0,
+ /* cie= */ 0,
+ dbg,
+ DW_FRAME_CFA_COL,
+ &icount, &dw_err);
+ if (res == DW_DLV_ERROR) {
+ _dwarf_error(dbg, err, dw_err);
+ return (res);
+ } else if (res == DW_DLV_NO_ENTRY) {
+ continue;
+ }
+
+ for (j = 0; j < icount; ++j) {
+ Dwarf_Frame_Op *finst2 = frame_inst + j;
+
+ if (finst2->fp_base_op == 0 && finst2->fp_extended_op == 1) {
+ /* is DW_CFA_set_loc */
+ Dwarf_Addr add = (Dwarf_Addr) finst2->fp_offset;
+ Dwarf_Off off = finst2->fp_instr_offset + instoff;
+
+ arange = (Dwarf_Arange)
+ _dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1);
+ if (arange == NULL) {
+ _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ arange->ar_address = add;
+ arange->ar_info_offset = off;
+ arange_count++;
+ curr_chain = (Dwarf_Chain)
+ _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
+ if (curr_chain == NULL) {
+ _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ curr_chain->ch_item = arange;
+ if (head_chain == NULL)
+ head_chain = prev_chain = curr_chain;
+ else {
+ prev_chain->ch_next = curr_chain;
+ prev_chain = curr_chain;
+ }
+
+ }
+ }
+ dwarf_dealloc(dbg, frame_inst, DW_DLA_FRAME_BLOCK);
+
+ }
+ dwarf_dealloc(dbg, fde_data, DW_DLA_LIST);
+ dwarf_dealloc(dbg, cie_data, DW_DLA_LIST);
+ arange_addrs = (Dwarf_Addr *)
+ _dwarf_get_alloc(dbg, DW_DLA_ADDR, arange_count);
+ if (arange_addrs == NULL) {
+ _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ arange_offsets = (Dwarf_Off *)
+ _dwarf_get_alloc(dbg, DW_DLA_ADDR, arange_count);
+ if (arange_offsets == NULL) {
+ _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ curr_chain = head_chain;
+ for (i = 0; i < arange_count; i++) {
+ Dwarf_Arange ar = curr_chain->ch_item;
+
+ arange_addrs[i] = ar->ar_address;
+ arange_offsets[i] = ar->ar_info_offset;
+ prev_chain = curr_chain;
+ curr_chain = curr_chain->ch_next;
+ dwarf_dealloc(dbg, ar, DW_DLA_ARANGE);
+ dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN);
+ }
+ *returncount = arange_count;
+ *offsetlist = arange_offsets;
+ *addrlist = arange_addrs;
+ return retval;
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_funcs.c b/usr/src/lib/libdwarf/common/dwarf_funcs.c
new file mode 100644
index 0000000000..8d725ae33f
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_funcs.c
@@ -0,0 +1,130 @@
+/*
+
+ Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2009-2010 David Anderson. 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
+
+*/
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+#include "dwarf_funcs.h"
+#include "dwarf_global.h"
+
+int
+dwarf_get_funcs(Dwarf_Debug dbg,
+ Dwarf_Func ** funcs,
+ Dwarf_Signed * ret_func_count, Dwarf_Error * error)
+{
+ int res = _dwarf_load_section(dbg, &dbg->de_debug_funcnames,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ return _dwarf_internal_get_pubnames_like_data(dbg,
+ dbg->de_debug_funcnames.dss_data,
+ dbg->de_debug_funcnames.dss_size,
+ (Dwarf_Global **) funcs, /* Type punning for sections with identical format. */
+ ret_func_count,
+ error,
+ DW_DLA_FUNC_CONTEXT,
+ DW_DLA_FUNC,
+ DW_DLE_DEBUG_FUNCNAMES_LENGTH_BAD,
+ DW_DLE_DEBUG_FUNCNAMES_VERSION_ERROR);
+}
+
+/* Deallocating fully requires deallocating the list
+ and all entries. But some internal data is
+ not exposed, so we need a function with internal knowledge.
+*/
+
+void
+dwarf_funcs_dealloc(Dwarf_Debug dbg, Dwarf_Func * dwgl,
+ Dwarf_Signed count)
+{
+ _dwarf_internal_globals_dealloc(dbg, (Dwarf_Global *) dwgl,
+ count,
+ DW_DLA_FUNC_CONTEXT,
+ DW_DLA_FUNC, DW_DLA_LIST);
+ return;
+}
+
+
+
+int
+dwarf_funcname(Dwarf_Func func_in, char **ret_name, Dwarf_Error * error)
+{
+ Dwarf_Global func = (Dwarf_Global) func_in;
+
+ if (func == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_FUNC_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ *ret_name = (char *) (func->gl_name);
+ return DW_DLV_OK;
+}
+
+int
+dwarf_func_die_offset(Dwarf_Func func_in,
+ Dwarf_Off * return_offset, Dwarf_Error * error)
+{
+ Dwarf_Global func = (Dwarf_Global) func_in;
+
+ return dwarf_global_die_offset(func, return_offset, error);
+}
+
+
+int
+dwarf_func_cu_offset(Dwarf_Func func_in,
+ Dwarf_Off * return_offset, Dwarf_Error * error)
+{
+ Dwarf_Global func = (Dwarf_Global) func_in;
+
+ return dwarf_global_cu_offset(func, return_offset, error);
+}
+
+
+int
+dwarf_func_name_offsets(Dwarf_Func func_in,
+ char **ret_func_name,
+ Dwarf_Off * die_offset,
+ Dwarf_Off * cu_die_offset, Dwarf_Error * error)
+{
+ Dwarf_Global func = (Dwarf_Global) func_in;
+
+ return dwarf_global_name_offsets(func,
+ ret_func_name,
+ die_offset, cu_die_offset, error);
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_funcs.h b/usr/src/lib/libdwarf/common/dwarf_funcs.h
new file mode 100644
index 0000000000..bf91c32157
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_funcs.h
@@ -0,0 +1,42 @@
+/*
+
+ Copyright (C) 2000, 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
+
+*/
+
+
+
+
+typedef struct Dwarf_Func_Context_s *Dwarf_Func_Context;
+
+
+/* struct never completed: see dwarf_global.h */
diff --git a/usr/src/lib/libdwarf/common/dwarf_global.c b/usr/src/lib/libdwarf/common/dwarf_global.c
new file mode 100644
index 0000000000..d1c090fa43
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_global.c
@@ -0,0 +1,607 @@
+/*
+
+ Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2007-2010 David Anderson. 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
+
+*/
+/* The address of the Free Software Foundation is
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ SGI has moved from the Crittenden Lane address.
+*/
+
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+#include "dwarf_global.h"
+
+
+#ifdef __sgi /* __sgi should only be defined for IRIX/MIPS. */
+/* The 'fixup' here intended for IRIX targets only.
+ With a 2+GB Elf64 IRIX executable (under 4GB in size),
+ some DIE offsets wrongly
+ got the 32bit upper bit sign extended. For the cu-header
+ offset in the .debug_pubnames section and in the
+ .debug_aranges section.
+ the 'varp' here is a pointer to an offset into .debug_info.
+ We fix up the offset here if it seems advisable..
+
+ As of June 2005 we have identified a series of mistakes
+ in ldx64 that can cause this (64 bit values getting passed
+ thru 32-bit signed knothole).
+*/
+void
+_dwarf_fix_up_offset_irix(Dwarf_Debug dbg,
+ Dwarf_Unsigned * varp, char *caller_site_name)
+{
+
+ Dwarf_Unsigned var = *varp;
+
+#define UPPER33 0xffffffff80000000LL
+#define LOWER32 0xffffffffLL
+ /* Restrict the hack to the known case. Upper 32 bits erroneously
+ sign extended from lower 32 upper bit. */
+ if ((var & UPPER33) == UPPER33) {
+ var &= LOWER32;
+ /* Apply the fix. Dreadful hack. */
+ *varp = var;
+ }
+#undef UPPER33
+#undef LOWER32
+ return;
+}
+#endif
+
+
+int
+dwarf_get_globals(Dwarf_Debug dbg,
+ Dwarf_Global ** globals,
+ Dwarf_Signed * return_count, Dwarf_Error * error)
+{
+ int res = _dwarf_load_section(dbg, &dbg->de_debug_pubnames,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ return _dwarf_internal_get_pubnames_like_data(dbg,
+ dbg->de_debug_pubnames.dss_data,
+ dbg->de_debug_pubnames.dss_size,
+ globals,
+ return_count,
+ error,
+ DW_DLA_GLOBAL_CONTEXT,
+ DW_DLA_GLOBAL,
+ DW_DLE_PUBNAMES_LENGTH_BAD,
+ DW_DLE_PUBNAMES_VERSION_ERROR);
+
+}
+
+/* Deallocating fully requires deallocating the list
+ and all entries. But some internal data is
+ not exposed, so we need a function with internal knowledge.
+*/
+
+void
+dwarf_globals_dealloc(Dwarf_Debug dbg, Dwarf_Global * dwgl,
+ Dwarf_Signed count)
+{
+ _dwarf_internal_globals_dealloc(dbg, dwgl,
+ count,
+ DW_DLA_GLOBAL_CONTEXT,
+ DW_DLA_GLOBAL, DW_DLA_LIST);
+ return;
+}
+
+void
+_dwarf_internal_globals_dealloc(Dwarf_Debug dbg, Dwarf_Global * dwgl,
+ Dwarf_Signed count,
+ int context_code,
+ int global_code, int list_code)
+{
+ Dwarf_Signed i;
+ struct Dwarf_Global_Context_s *gcp = 0;
+ struct Dwarf_Global_Context_s *lastgcp = 0;
+
+ for (i = 0; i < count; i++) {
+ Dwarf_Global dgb = dwgl[i];
+
+ gcp = dgb->gl_context;
+
+ if (lastgcp != gcp) {
+ lastgcp = gcp;
+ dwarf_dealloc(dbg, gcp, context_code);
+ }
+ dwarf_dealloc(dbg, dgb, global_code);
+ }
+ dwarf_dealloc(dbg, dwgl, list_code);
+ return;
+}
+
+
+/* Sweeps the complete section.
+*/
+int
+_dwarf_internal_get_pubnames_like_data(Dwarf_Debug dbg,
+ Dwarf_Small * section_data_ptr,
+ Dwarf_Unsigned section_length,
+ Dwarf_Global ** globals,
+ Dwarf_Signed * return_count,
+ Dwarf_Error * error,
+ int context_code,
+ int global_code,
+ int length_err_num,
+ int version_err_num)
+{
+
+
+ Dwarf_Small *pubnames_like_ptr = 0;
+
+
+
+ /* Points to the context for the current set of global names, and
+ contains information to identify the compilation-unit that the
+ set refers to. */
+ Dwarf_Global_Context pubnames_context = 0;
+
+ Dwarf_Half version = 0;
+
+ /*
+ Offset from the start of compilation-unit for the current
+ global. */
+ Dwarf_Off die_offset_in_cu = 0;
+
+ Dwarf_Unsigned global_count = 0;
+
+ /* Points to the current global read. */
+ Dwarf_Global global = 0;
+
+ /* Used to chain the Dwarf_Global_s structs for creating contiguous
+ list of pointers to the structs. */
+ Dwarf_Chain curr_chain = 0;
+ Dwarf_Chain prev_chain = 0;
+ Dwarf_Chain head_chain = 0;
+
+ /* Points to contiguous block of Dwarf_Global's to be returned. */
+ Dwarf_Global *ret_globals = 0;
+
+ /* Temporary counter. */
+ Dwarf_Unsigned i = 0;
+
+
+
+
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ /* We will eventually need the .debug_info data. Load it now. */
+ if (!dbg->de_debug_info.dss_data) {
+ int res = _dwarf_load_debug_info(dbg, error);
+
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ }
+
+ if (section_data_ptr == NULL) {
+ return (DW_DLV_NO_ENTRY);
+ }
+
+ pubnames_like_ptr = section_data_ptr;
+ do {
+ Dwarf_Unsigned length = 0;
+ int local_extension_size = 0;
+ int local_length_size = 0;
+
+ /* Some compilers emit padding at the end of each cu's area.
+ pubnames_ptr_past_end_cu records the true area end for this
+ cu's data. Essentially the length in the header and the 0
+ terminator of the data are redundant information. The
+ dwarf2/3 spec does not mention what to do if the length is
+ past the 0 terminator. So we take any bytes left after the 0
+ as padding and ignore them. */
+ Dwarf_Small *pubnames_ptr_past_end_cu = 0;
+
+
+ pubnames_context = (Dwarf_Global_Context)
+ _dwarf_get_alloc(dbg, context_code, 1);
+ if (pubnames_context == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ /* READ_AREA_LENGTH updates pubnames_like_ptr for consumed
+ bytes. */
+ READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned,
+ pubnames_like_ptr, local_length_size,
+ local_extension_size);
+ pubnames_context->pu_length_size = local_length_size;
+ pubnames_context->pu_extension_size = local_extension_size;
+ pubnames_context->pu_dbg = dbg;
+
+ pubnames_ptr_past_end_cu = pubnames_like_ptr + length;
+
+ READ_UNALIGNED(dbg, version, Dwarf_Half,
+ pubnames_like_ptr, sizeof(Dwarf_Half));
+ pubnames_like_ptr += sizeof(Dwarf_Half);
+ if (version != CURRENT_VERSION_STAMP) {
+ _dwarf_error(dbg, error, version_err_num);
+ return (DW_DLV_ERROR);
+ }
+
+ /* Offset of CU header in debug section. */
+ READ_UNALIGNED(dbg, pubnames_context->pu_offset_of_cu_header,
+ Dwarf_Off, pubnames_like_ptr,
+ pubnames_context->pu_length_size);
+ pubnames_like_ptr += pubnames_context->pu_length_size;
+
+ FIX_UP_OFFSET_IRIX_BUG(dbg,
+ pubnames_context->pu_offset_of_cu_header,
+ "pubnames cu header offset");
+
+
+ READ_UNALIGNED(dbg, pubnames_context->pu_info_length,
+ Dwarf_Unsigned, pubnames_like_ptr,
+ pubnames_context->pu_length_size);
+ pubnames_like_ptr += pubnames_context->pu_length_size;
+
+ if (pubnames_like_ptr > (section_data_ptr + section_length)) {
+ _dwarf_error(dbg, error, length_err_num);
+ return (DW_DLV_ERROR);
+ }
+
+ /* Read initial offset (of DIE within CU) of a pubname, final
+ entry is not a pair, just a zero offset. */
+ READ_UNALIGNED(dbg, die_offset_in_cu, Dwarf_Off,
+ pubnames_like_ptr,
+ pubnames_context->pu_length_size);
+ pubnames_like_ptr += pubnames_context->pu_length_size;
+ FIX_UP_OFFSET_IRIX_BUG(dbg,
+ die_offset_in_cu, "offset of die in cu");
+
+ /* Loop thru pairs. DIE off with CU followed by string. */
+ while (die_offset_in_cu != 0) {
+
+ /* Already read offset, pubnames_like_ptr now points to the
+ string. */
+ global =
+ (Dwarf_Global) _dwarf_get_alloc(dbg, global_code, 1);
+ if (global == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ global_count++;
+
+ global->gl_context = pubnames_context;
+
+ global->gl_named_die_offset_within_cu = die_offset_in_cu;
+
+ global->gl_name = pubnames_like_ptr;
+
+ pubnames_like_ptr = pubnames_like_ptr +
+ strlen((char *) pubnames_like_ptr) + 1;
+
+
+ /* finish off current entry chain */
+ curr_chain =
+ (Dwarf_Chain) _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
+ if (curr_chain == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ /* Put current global on singly_linked list. */
+ curr_chain->ch_item = (Dwarf_Global) global;
+
+ if (head_chain == NULL)
+ head_chain = prev_chain = curr_chain;
+ else {
+ prev_chain->ch_next = curr_chain;
+ prev_chain = curr_chain;
+ }
+
+ /* read offset for the *next* entry */
+ READ_UNALIGNED(dbg, die_offset_in_cu, Dwarf_Off,
+ pubnames_like_ptr,
+ pubnames_context->pu_length_size);
+
+ pubnames_like_ptr += pubnames_context->pu_length_size;
+ FIX_UP_OFFSET_IRIX_BUG(dbg,
+ die_offset_in_cu,
+ "offset of next die in cu");
+
+ if (pubnames_like_ptr > (section_data_ptr + section_length)) {
+ _dwarf_error(dbg, error, length_err_num);
+ return (DW_DLV_ERROR);
+ }
+ }
+ /* ASSERT: die_offset_in_cu == 0 */
+ if (pubnames_like_ptr > pubnames_ptr_past_end_cu) {
+ /* This is some kind of error. This simply cannot happen.
+ The encoding is wrong or the length in the header for
+ this cu's contribution is wrong. */
+ _dwarf_error(dbg, error, length_err_num);
+ return (DW_DLV_ERROR);
+ }
+ /* If there is some kind of padding at the end of the section,
+ as emitted by some compilers, skip over that padding and
+ simply ignore the bytes thus passed-over. With most
+ compilers, pubnames_like_ptr == pubnames_ptr_past_end_cu at
+ this point */
+ pubnames_like_ptr = pubnames_ptr_past_end_cu;
+
+ } while (pubnames_like_ptr < (section_data_ptr + section_length));
+
+ /* Points to contiguous block of Dwarf_Global's. */
+ ret_globals = (Dwarf_Global *)
+ _dwarf_get_alloc(dbg, DW_DLA_LIST, global_count);
+ if (ret_globals == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ /*
+ Store pointers to Dwarf_Global_s structs in contiguous block,
+ and deallocate the chain. */
+ curr_chain = head_chain;
+ for (i = 0; i < global_count; i++) {
+ *(ret_globals + i) = curr_chain->ch_item;
+ prev_chain = curr_chain;
+ curr_chain = curr_chain->ch_next;
+ dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN);
+ }
+
+ *globals = ret_globals;
+ *return_count = (Dwarf_Signed) global_count;
+ return DW_DLV_OK;
+}
+
+
+/*
+ Given a pubnames entry (or other like section entry)
+ return thru the ret_name pointer
+ a pointer to the string which is the entry name.
+
+*/
+int
+dwarf_globname(Dwarf_Global glob, char **ret_name, Dwarf_Error * error)
+{
+ if (glob == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ *ret_name = (char *) (glob->gl_name);
+ return DW_DLV_OK;
+}
+
+
+/*
+ Given a pubnames entry (or other like section entry)
+ return thru the ret_off pointer the
+ global offset of the DIE for this entry.
+ The global offset is the offset within the .debug_info
+ section as a whole.
+*/
+int
+dwarf_global_die_offset(Dwarf_Global global,
+ Dwarf_Off * ret_off, Dwarf_Error * error)
+{
+ if (global == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ if (global->gl_context == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_GLOBAL_CONTEXT_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ *ret_off = (global->gl_named_die_offset_within_cu +
+ global->gl_context->pu_offset_of_cu_header);
+ return DW_DLV_OK;
+}
+
+/*
+ Given a pubnames entry (or other like section entry)
+ return thru the ret_off pointer the
+ offset of the compilation unit header of the
+ compilation unit the global is part of.
+
+ In early versions of this, the value returned was
+ the offset of the compilation unit die, and
+ other cu-local die offsets were faked so adding this to
+ such a cu-local offset got a true section offset.
+ Now things do as they say (adding *cu_header_offset to
+ a cu-local offset gets the section offset).
+
+*/
+int
+dwarf_global_cu_offset(Dwarf_Global global,
+ Dwarf_Off * cu_header_offset,
+ Dwarf_Error * error)
+{
+ Dwarf_Global_Context con = 0;
+
+ if (global == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ con = global->gl_context;
+
+ if (con == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_GLOBAL_CONTEXT_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ /* In early libdwarf, this incorrectly returned the offset of the
+ CU DIE. Now correctly returns the header offset. */
+ *cu_header_offset = con->pu_offset_of_cu_header;
+
+ return DW_DLV_OK;
+}
+
+/*
+ Give back the pubnames entry (or any other like section)
+ name, symbol DIE offset, and the cu-DIE offset.
+
+ Various errors are possible.
+
+ The string pointer returned thru ret_name is not
+ dwarf_get_alloc()ed, so no dwarf_dealloc()
+ DW_DLA_STRING should be applied to it.
+
+*/
+int
+dwarf_global_name_offsets(Dwarf_Global global,
+ char **ret_name,
+ Dwarf_Off * die_offset,
+ Dwarf_Off * cu_die_offset,
+ Dwarf_Error * error)
+{
+ Dwarf_Global_Context con = 0;
+ Dwarf_Debug dbg = 0;
+ Dwarf_Off off = 0;
+
+ if (global == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ con = global->gl_context;
+
+ if (con == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_GLOBAL_CONTEXT_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ off = con->pu_offset_of_cu_header;
+ /* The offset had better not be too close to the end. If it is,
+ _dwarf_length_of_cu_header() will step off the end and therefore
+ must not be used. 10 is a meaningless heuristic, but no CU
+ header is that small so it is safe. An erroneous offset is due
+ to a bug in the tool chain. A bug like this has been seen on
+ IRIX with MIPSpro 7.3.1.3 and an executable > 2GB in size and
+ with 2 million pubnames entries. */
+#define MIN_CU_HDR_SIZE 10
+ dbg = con->pu_dbg;
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ if (dbg->de_debug_info.dss_size &&
+ ((off + MIN_CU_HDR_SIZE) >= dbg->de_debug_info.dss_size)) {
+ _dwarf_error(NULL, error, DW_DLE_OFFSET_BAD);
+ return (DW_DLV_ERROR);
+ }
+#undef MIN_CU_HDR_SIZE
+ if (die_offset != NULL) {
+ *die_offset = global->gl_named_die_offset_within_cu + off;
+ }
+
+ *ret_name = (char *) global->gl_name;
+
+ if (cu_die_offset != NULL) {
+ int res = _dwarf_load_debug_info(dbg, error);
+
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ /* The offset had better not be too close to the end. If it is,
+ _dwarf_length_of_cu_header() will step off the end and
+ therefore must not be used. 10 is a meaningless heuristic,
+ but no CU header is that small so it is safe. */
+ if ((off + 10) >= dbg->de_debug_info.dss_size) {
+ _dwarf_error(NULL, error, DW_DLE_OFFSET_BAD);
+ return (DW_DLV_ERROR);
+ }
+ *cu_die_offset = off + _dwarf_length_of_cu_header(dbg, off);
+ }
+
+
+ return DW_DLV_OK;
+}
+
+/*
+ We have the offset to a CU header.
+ Return thru outFileOffset the offset of the CU DIE.
+
+ New June, 2001.
+ Used by SGI debuggers.
+ No error is possible.
+
+ See also dwarf_CU_dieoffset_given_die().
+*/
+
+/* ARGSUSED */
+int
+dwarf_get_cu_die_offset_given_cu_header_offset(Dwarf_Debug dbg,
+ Dwarf_Off in_cu_header_offset,
+ Dwarf_Off * out_cu_die_offset,
+ Dwarf_Error * err)
+{
+ Dwarf_Off len =
+ _dwarf_length_of_cu_header(dbg, in_cu_header_offset);
+
+ Dwarf_Off newoff = in_cu_header_offset + len;
+
+ *out_cu_die_offset = newoff;
+ return DW_DLV_OK;
+}
+/* dwarf_CU_dieoffset_given_die returns
+ the global debug_info section offset of the CU die
+ that is the CU containing the given (passed-in) die.
+ This information makes it possible for a consumer to
+ find and print context information for any die.
+
+ Use dwarf_offdie() passing in the offset this returns
+ to get a die pointer to the CU die.
+ */
+int
+dwarf_CU_dieoffset_given_die(Dwarf_Die die,
+ Dwarf_Off* return_offset,
+ Dwarf_Error* error)
+{
+ Dwarf_Off dieoff = 0;
+ Dwarf_CU_Context cucontext = 0;
+
+ CHECK_DIE(die, DW_DLV_ERROR);
+ cucontext = die->di_cu_context;
+ dieoff = cucontext->cc_debug_info_offset;
+ /* The following call cannot fail, so no error check. */
+ dwarf_get_cu_die_offset_given_cu_header_offset(
+ cucontext->cc_dbg, dieoff, return_offset,error);
+ return DW_DLV_OK;
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_global.h b/usr/src/lib/libdwarf/common/dwarf_global.h
new file mode 100644
index 0000000000..c2bc2cdcc3
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_global.h
@@ -0,0 +1,124 @@
+/*
+
+ Copyright (C) 2000,2004,2005 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
+
+*/
+
+
+
+
+typedef struct Dwarf_Global_Context_s *Dwarf_Global_Context;
+
+/*
+ This struct contains header information for a set of pubnames.
+ Essentially, they contain the context for a set of pubnames
+ belonging to a compilation-unit.
+
+ This is also used for the sgi-specific
+ weaknames, typenames, varnames, funcnames data:
+ the structs for those are incomplete and
+ instances of this are used instead.
+
+ Also used for DWARF3 .debug_pubtypes.
+
+*/
+struct Dwarf_Global_Context_s {
+
+ /* Length in .debug_pubnames (etc) of a set of names for a
+ compilation-unit. Dwarf_Word pu_length; The value is not made
+ available outside libdwarf and not used inside, so no need to
+ record it. */
+
+ /* For this context, size of a length. 4 or 8 */
+ unsigned char pu_length_size;
+
+ /* For this CU, size of the extension 0 except for dwarf2 extension
+ 64bit, in which case is 4. */
+ unsigned char pu_extension_size;
+
+ /*
+ Offset into .debug_info of the compilation-unit header (not DIE)
+ for this set of pubnames. */
+ Dwarf_Off pu_offset_of_cu_header;
+
+ /* Size of compilation-unit that these pubnames are in. */
+ Dwarf_Unsigned pu_info_length;
+
+ Dwarf_Debug pu_dbg;
+};
+
+
+/* This struct contains information for a single pubname. */
+struct Dwarf_Global_s {
+
+ /*
+ Offset from the start of the corresponding compilation-unit of
+ the DIE for the given pubname CU. */
+ Dwarf_Off gl_named_die_offset_within_cu;
+
+ /* Points to the given pubname. */
+ Dwarf_Small *gl_name;
+
+ /* Context for this pubname. */
+ Dwarf_Global_Context gl_context;
+};
+
+int _dwarf_internal_get_pubnames_like_data(Dwarf_Debug dbg,
+ Dwarf_Small *
+ section_data_ptr,
+ Dwarf_Unsigned
+ section_length,
+ Dwarf_Global ** globals,
+ Dwarf_Signed * return_count,
+ Dwarf_Error * error,
+ int context_code,
+ int global_code,
+ int length_err_num,
+ int version_err_num);
+
+void
+_dwarf_internal_globals_dealloc( Dwarf_Debug dbg, Dwarf_Global *dwgl,
+ Dwarf_Signed count,
+ int context_code,
+ int global_code,
+ int list_code);
+
+
+#ifdef __sgi /* __sgi should only be defined for IRIX/MIPS. */
+void _dwarf_fix_up_offset_irix(Dwarf_Debug dbg,
+ Dwarf_Unsigned *varp,
+ char *caller_site_name);
+#define FIX_UP_OFFSET_IRIX_BUG(ldbg,var,name) _dwarf_fix_up_offset_irix(ldbg,&var,name)
+#else
+#define FIX_UP_OFFSET_IRIX_BUG(ldbg,var,name)
+#endif
+
diff --git a/usr/src/lib/libdwarf/common/dwarf_harmless.c b/usr/src/lib/libdwarf/common/dwarf_harmless.c
new file mode 100644
index 0000000000..16dbe4bc97
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_harmless.c
@@ -0,0 +1,226 @@
+/*
+
+ Copyright (C) 2010 David Anderson. 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.
+
+*/
+
+/*
+ This implements _dwarf_insert_harmless_error
+ and related helper functions for recording
+ compiler errors that need not make the input
+ unusable.
+
+ Applications can use dwarf_get_harmless_error_list to
+ find (and possibly print) a warning about such errors.
+
+ The initial error reported here is
+ DW_DLE_DEBUG_FRAME_LENGTH_NOT_MULTIPLE which was a
+ bug in a specific compiler.
+
+ It is a fixed length circular list to constrain
+ the space used for errors.
+
+ The assumption is that these errors are exceedingly
+ rare, and indicate a broken compiler (the one that
+ produced the object getting the error(s)).
+
+ dh_maxcount is recorded internally as 1 greater than
+ requested. Hiding the fact we always leave one
+ slot unused (at least). So a user request for
+ N slots really gives the user N usable slots.
+*/
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include "dwarf_frame.h"
+#include "dwarf_harmless.h"
+
+
+/* The pointers returned here through errmsg_ptrs_array
+ become invalidated by any call to libdwarf. Any call.
+*/
+int dwarf_get_harmless_error_list(Dwarf_Debug dbg,
+ unsigned count,
+ const char ** errmsg_ptrs_array,
+ unsigned * errs_count)
+{
+ struct Dwarf_Harmless_s *dhp = &dbg->de_harmless_errors;
+ if(!dhp->dh_errors) {
+ dhp->dh_errs_count = 0;
+ return DW_DLV_NO_ENTRY;
+ }
+ if(dhp->dh_errs_count == 0) {
+ return DW_DLV_NO_ENTRY;
+ }
+ if(errs_count) {
+ *errs_count = dhp->dh_errs_count;
+ }
+ if(count) {
+ /* NULL terminate the array of pointers */
+ --count;
+ errmsg_ptrs_array[count] = 0;
+
+ if(dhp->dh_next_to_use != dhp->dh_first) {
+ unsigned i = 0;
+ unsigned cur = dhp->dh_first;
+ for(i = 0; cur != dhp->dh_next_to_use; ++i) {
+ if(i >= count ) {
+ /* All output spaces are used. */
+ break;
+ }
+ errmsg_ptrs_array[i] = dhp->dh_errors[cur];
+ cur = (cur +1) % dhp->dh_maxcount;
+ }
+ errmsg_ptrs_array[i] = 0;
+ }
+ }
+ dhp->dh_next_to_use = 0;
+ dhp->dh_first = 0;
+ dhp->dh_errs_count = 0;
+ return DW_DLV_OK;
+}
+
+/* strncpy does not null-terminate, this does it. */
+static void
+safe_strncpy(char *targ, char *src, unsigned spaceavail)
+{
+ unsigned goodcount = spaceavail-1;
+ if(spaceavail < 1) {
+ return; /* impossible */
+ }
+ strncpy(targ,src,goodcount);
+ targ[goodcount] = 0;
+}
+
+/* Insertion made public is only for testing the harmless error code,
+ it is not necessarily useful for libdwarf client code aside
+ from code testing libdwarf. */
+void dwarf_insert_harmless_error(Dwarf_Debug dbg,
+ char *newerror)
+{
+ struct Dwarf_Harmless_s *dhp = &dbg->de_harmless_errors;
+ unsigned next = 0;
+ unsigned cur = dhp->dh_next_to_use;
+ char *msgspace;
+ if(!dhp->dh_errors) {
+ dhp->dh_errs_count++;
+ return;
+ }
+ msgspace = dhp->dh_errors[cur];
+ safe_strncpy(msgspace, newerror,DW_HARMLESS_ERROR_MSG_STRING_SIZE);
+ next = (cur+1) % dhp->dh_maxcount;
+ dhp->dh_errs_count++;
+ dhp->dh_next_to_use = next;
+ if (dhp->dh_next_to_use == dhp->dh_first) {
+ /* Array is full set full invariant. */
+ dhp->dh_first = (dhp->dh_first+1) % dhp->dh_maxcount;
+ }
+}
+
+/* The size of the circular list of strings may be set
+ and reset as desired. Returns the previous size of
+ the list. If the list is shortened excess error entries
+ are simply dropped.
+ If the reallocation fails the list size is left unchanged.
+ Do not make this a long list!
+
+ Remember the maxcount we record is 1 > the user count,
+ so we adjust it so it looks like the user count.
+*/
+unsigned dwarf_set_harmless_error_list_size(Dwarf_Debug dbg,
+ unsigned maxcount )
+{
+ struct Dwarf_Harmless_s *dhp = &dbg->de_harmless_errors;
+ unsigned prevcount = dhp->dh_maxcount;
+ if(maxcount != 0) {
+ ++maxcount;
+ if(maxcount != dhp->dh_maxcount) {
+ /* Assign transfers 'ownership' of the malloc areas
+ to oldarray. */
+ struct Dwarf_Harmless_s oldarray = *dhp;
+ /* Do not double increment the max, the init() func
+ increments it too. */
+ dwarf_harmless_init(dhp,maxcount-1);
+ if(oldarray.dh_next_to_use != oldarray.dh_first) {
+ unsigned i = 0;
+ for(i = oldarray.dh_first; i != oldarray.dh_next_to_use;
+ i = (i+1)%oldarray.dh_maxcount) {
+ dwarf_insert_harmless_error(dbg,oldarray.dh_errors[i]);
+ }
+ if( oldarray.dh_errs_count > dhp->dh_errs_count) {
+ dhp->dh_errs_count = oldarray.dh_errs_count;
+ }
+ }
+ dwarf_harmless_cleanout(&oldarray);
+ }
+ }
+ return prevcount-1;
+}
+
+void
+dwarf_harmless_init(struct Dwarf_Harmless_s *dhp,unsigned size)
+{
+ unsigned i = 0;
+ memset(dhp,0,sizeof(*dhp));
+ dhp->dh_maxcount = size +1;
+ dhp->dh_errors = (char **)malloc(sizeof( char *) *dhp->dh_maxcount);
+ if (!dhp->dh_errors) {
+ dhp->dh_maxcount = 0;
+ return;
+ }
+
+ for(i = 0; i < dhp->dh_maxcount; ++i) {
+ char *newstr =
+ (char *)malloc(DW_HARMLESS_ERROR_MSG_STRING_SIZE);
+ dhp->dh_errors[i] = newstr;
+ if(!newstr) {
+ dhp->dh_maxcount = 0;
+ /* Let it leak, the leak is a constrained amount. */
+ dhp->dh_errors = 0;
+ return;
+ }
+ /* We make the string content well-defined by an initial
+ NUL byte, but this is not really necessary. */
+ newstr[0] = 0;
+ }
+}
+
+void
+dwarf_harmless_cleanout(struct Dwarf_Harmless_s *dhp)
+{
+ unsigned i = 0;
+ if(!dhp->dh_errors) {
+ return;
+ }
+ for(i = 0; i < dhp->dh_maxcount; ++i) {
+ free(dhp->dh_errors[i]);
+ }
+ free(dhp->dh_errors);
+ dhp->dh_errors = 0;
+ dhp->dh_maxcount = 0;
+}
+
diff --git a/usr/src/lib/libdwarf/common/dwarf_harmless.h b/usr/src/lib/libdwarf/common/dwarf_harmless.h
new file mode 100644
index 0000000000..3d4d910ce9
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_harmless.h
@@ -0,0 +1,31 @@
+/*
+
+ Copyright (C) 2010 David Anderson. 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.
+
+*/
+
+
+
+void dwarf_harmless_init(struct Dwarf_Harmless_s *dhp,unsigned size);
+void dwarf_harmless_cleanout(struct Dwarf_Harmless_s *dhp);
+
diff --git a/usr/src/lib/libdwarf/common/dwarf_incl.h b/usr/src/lib/libdwarf/common/dwarf_incl.h
new file mode 100644
index 0000000000..df2fbf334c
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_incl.h
@@ -0,0 +1,66 @@
+/*
+
+ Copyright (C) 2000, 2002, 2004 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright 2008-2010 David Anderson. 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
+
+*/
+
+
+
+#ifndef DWARF_INCL_H
+#define DWARF_INCL_H
+#if (!defined(HAVE_RAW_LIBELF_OK) && defined(HAVE_LIBELF_OFF64_OK) )
+/* At a certain point libelf.h requires _GNU_SOURCE.
+ here we assume the criteria in configure determine that
+ usefully.
+*/
+#define _GNU_SOURCE 1
+#endif
+
+
+#include "libdwarfdefs.h"
+#include <string.h>
+
+#ifdef HAVE_ELF_H
+#include <elf.h>
+#endif
+
+#include <limits.h>
+#include <dwarf.h>
+#include <libdwarf.h>
+
+#include "dwarf_base_types.h"
+#include "dwarf_alloc.h"
+#include "dwarf_opaque.h"
+#include "dwarf_error.h"
+#include "dwarf_util.h"
+#endif /* DWARF_INCL_H */
diff --git a/usr/src/lib/libdwarf/common/dwarf_init_finish.c b/usr/src/lib/libdwarf/common/dwarf_init_finish.c
new file mode 100644
index 0000000000..1ab9d5fd38
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_init_finish.c
@@ -0,0 +1,577 @@
+/*
+
+ Copyright (C) 2000,2002,2003,2004,2005 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2008-2010 Arxan Technologies, Inc. All Rights Reserved.
+ Portions Copyright (C) 2009-2010 David Anderson. 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
+
+*/
+
+#include "config.h"
+#include "dwarf_incl.h"
+
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "dwarf_incl.h"
+#include "malloc_check.h"
+
+#define DWARF_DBG_ERROR(dbg,errval,retval) \
+ _dwarf_error(dbg, error, errval); return(retval);
+
+#define FALSE 0
+#define TRUE 1
+
+
+
+/* This static is copied to the dbg on dbg init
+ so that the static need not be referenced at
+ run time, preserving better locality of
+ reference.
+ Value is 0 means do the string check.
+ Value non-zero means do not do the check.
+*/
+static Dwarf_Small _dwarf_assume_string_bad;
+static Dwarf_Small _dwarf_apply_relocs = 1;
+
+/* Call this after calling dwarf_init but before doing anything else.
+ * It applies to all objects, not just the current object.
+ */
+int
+dwarf_set_reloc_application(int apply)
+{
+ int oldval = _dwarf_apply_relocs;
+ _dwarf_apply_relocs = apply;
+ return oldval;
+}
+
+int
+dwarf_set_stringcheck(int newval)
+{
+ int oldval = _dwarf_assume_string_bad;
+
+ _dwarf_assume_string_bad = newval;
+ return oldval;
+}
+
+/* Unifies the basic duplicate/empty testing and section
+ * data setting to one place. */
+static int
+get_basic_section_data(Dwarf_Debug dbg,
+ struct Dwarf_Section_s *secdata,
+ struct Dwarf_Obj_Access_Section_s *doas,
+ Dwarf_Half section_index,
+ Dwarf_Error* error,
+ int duperr, int emptyerr )
+{
+ if (secdata->dss_index != 0) {
+ DWARF_DBG_ERROR(dbg, duperr, DW_DLV_ERROR);
+ }
+ if (doas->size == 0) {
+ if (emptyerr == 0 ) {
+ /* Allow empty section. */
+ return DW_DLV_OK;
+ }
+ /* Know no reason to allow section */
+ DWARF_DBG_ERROR(dbg, emptyerr, DW_DLV_ERROR);
+ }
+ secdata->dss_index = section_index;
+ secdata->dss_size = doas->size;
+ secdata->dss_addr = doas->addr;
+ secdata->dss_link = doas->link;
+ return DW_DLV_OK;
+}
+
+
+static void
+add_rela_data( struct Dwarf_Section_s *secdata,
+ struct Dwarf_Obj_Access_Section_s *doas,
+ Dwarf_Half section_index)
+{
+ secdata->dss_reloc_index = section_index;
+ secdata->dss_reloc_size = doas->size;
+ secdata->dss_reloc_addr = doas->addr;
+ secdata->dss_reloc_symtab = doas->link;
+ secdata->dss_reloc_link = doas->link;
+}
+
+/*
+ Given an Elf ptr, set up dbg with pointers
+ to all the Dwarf data sections.
+ Return NULL on error.
+
+ This function is also responsible for determining
+ whether the given object contains Dwarf information
+ or not. The test currently used is that it contains
+ either a .debug_info or a .debug_frame section. If
+ not, it returns DW_DLV_NO_ENTRY causing dwarf_init() also to
+ return DW_DLV_NO_ENTRY. Earlier, we had thought of using only
+ the presence/absence of .debug_info to test, but we
+ added .debug_frame since there could be stripped objects
+ that have only a .debug_frame section for exception
+ processing.
+ DW_DLV_NO_ENTRY or DW_DLV_OK or DW_DLV_ERROR
+*/
+static int
+_dwarf_setup(Dwarf_Debug dbg, Dwarf_Error * error)
+{
+ const char *scn_name = 0;
+ int foundDwarf = 0;
+ struct Dwarf_Obj_Access_Interface_s * obj = 0;
+
+ Dwarf_Endianness endianness;
+
+ Dwarf_Unsigned section_size = 0;
+ Dwarf_Unsigned section_count = 0;
+ Dwarf_Half section_index = 0;
+ Dwarf_Addr section_addr = 0;
+
+ foundDwarf = FALSE;
+
+ dbg->de_assume_string_in_bounds = _dwarf_assume_string_bad;
+
+ dbg->de_same_endian = 1;
+ dbg->de_copy_word = memcpy;
+ obj = dbg->de_obj_file;
+ endianness = obj->methods->get_byte_order(obj->object);
+#ifdef WORDS_BIGENDIAN
+ dbg->de_big_endian_object = 1;
+ if (endianness == DW_OBJECT_LSB ) {
+ dbg->de_same_endian = 0;
+ dbg->de_big_endian_object = 0;
+ dbg->de_copy_word = _dwarf_memcpy_swap_bytes;
+ }
+#else /* little endian */
+ dbg->de_big_endian_object = 0;
+ if (endianness == DW_OBJECT_MSB ) {
+ dbg->de_same_endian = 0;
+ dbg->de_big_endian_object = 1;
+ dbg->de_copy_word = _dwarf_memcpy_swap_bytes;
+ }
+#endif /* !WORDS_BIGENDIAN */
+
+
+ /* The following de_length_size is Not Too Significant. Only used
+ one calculation, and an approximate one at that. */
+ dbg->de_length_size = obj->methods->get_length_size(obj->object);
+ dbg->de_pointer_size = obj->methods->get_pointer_size(obj->object);
+
+ section_count = obj->methods->get_section_count(obj->object);
+
+ /* We can skip index 0 when considering ELF files, but not other
+ object types. */
+ for (section_index = 0; section_index < section_count;
+ ++section_index) {
+
+ struct Dwarf_Obj_Access_Section_s doas;
+ int res = DW_DLV_ERROR;
+ int err;
+
+ res = obj->methods->get_section_info(obj->object,
+ section_index,
+ &doas, &err);
+ if(res == DW_DLV_ERROR){
+ DWARF_DBG_ERROR(dbg, err, DW_DLV_ERROR);
+ }
+
+ section_addr = doas.addr;
+ section_size = doas.size;
+ scn_name = doas.name;
+
+ if (strncmp(scn_name, ".debug_", 7)
+ && strcmp(scn_name, ".eh_frame")
+ && strcmp(scn_name, ".symtab")
+ && strcmp(scn_name, ".strtab")
+ && strncmp(scn_name, ".rela.",6)) {
+ continue;
+ }
+ else if (strcmp(scn_name, ".debug_info") == 0) {
+ res = get_basic_section_data(dbg,&dbg->de_debug_info, &doas,
+ section_index,error,
+ DW_DLE_DEBUG_INFO_DUPLICATE,DW_DLE_DEBUG_INFO_NULL);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+ foundDwarf = TRUE;
+ }
+ else if (strcmp(scn_name, ".debug_abbrev") == 0) {
+ res = get_basic_section_data(dbg,&dbg->de_debug_abbrev, &doas,
+ section_index,error,
+ DW_DLE_DEBUG_ABBREV_DUPLICATE,DW_DLE_DEBUG_ABBREV_NULL);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+ }
+ else if (strcmp(scn_name, ".debug_aranges") == 0) {
+ res = get_basic_section_data(dbg,&dbg->de_debug_aranges, &doas,
+ section_index,error,
+ DW_DLE_DEBUG_ARANGES_DUPLICATE,0);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+ }
+
+ else if (strcmp(scn_name, ".debug_line") == 0) {
+ res = get_basic_section_data(dbg,&dbg->de_debug_line, &doas,
+ section_index,error,
+ DW_DLE_DEBUG_LINE_DUPLICATE,0);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+ }
+ else if (strcmp(scn_name, ".debug_frame") == 0) {
+ res = get_basic_section_data(dbg,&dbg->de_debug_frame, &doas,
+ section_index,error,
+ DW_DLE_DEBUG_FRAME_DUPLICATE,0);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+ foundDwarf = TRUE;
+ } else if (strcmp(scn_name, ".eh_frame") == 0) {
+ /* gnu egcs-1.1.2 data */
+ res = get_basic_section_data(dbg,&dbg->de_debug_frame_eh_gnu, &doas,
+ section_index,error,
+ DW_DLE_DEBUG_FRAME_DUPLICATE,0);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+ foundDwarf = TRUE;
+ }
+ else if (strcmp(scn_name, ".debug_loc") == 0) {
+ res = get_basic_section_data(dbg,&dbg->de_debug_loc, &doas,
+ section_index,error,
+ DW_DLE_DEBUG_LOC_DUPLICATE,0);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+ }
+ else if (strcmp(scn_name, ".debug_pubnames") == 0) {
+ res = get_basic_section_data(dbg,&dbg->de_debug_pubnames, &doas,
+ section_index,error,
+ DW_DLE_DEBUG_PUBNAMES_DUPLICATE,0);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+ }
+
+ else if (strcmp(scn_name, ".debug_str") == 0) {
+ res = get_basic_section_data(dbg,&dbg->de_debug_str, &doas,
+ section_index,error,
+ DW_DLE_DEBUG_STR_DUPLICATE,0);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+ }
+ else if (strcmp(scn_name, ".debug_funcnames") == 0) {
+ /* SGI IRIX-only. */
+ res = get_basic_section_data(dbg,&dbg->de_debug_funcnames, &doas,
+ section_index,error,
+ DW_DLE_DEBUG_FUNCNAMES_DUPLICATE,0);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+ }
+ else if (strcmp(scn_name, ".debug_typenames") == 0) {
+ /* SGI IRIX-only, created years before DWARF3. Content
+ essentially identical to .debug_pubtypes. */
+ res = get_basic_section_data(dbg,&dbg->de_debug_typenames, &doas,
+ section_index,error,
+ DW_DLE_DEBUG_TYPENAMES_DUPLICATE,0);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+ } else if (strcmp(scn_name, ".debug_pubtypes") == 0) {
+ /* Section new in DWARF3. */
+ res = get_basic_section_data(dbg,&dbg->de_debug_pubtypes, &doas,
+ section_index,error,
+ DW_DLE_DEBUG_PUBTYPES_DUPLICATE,0);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+ }
+ else if (strcmp(scn_name, ".debug_varnames") == 0) {
+ /* SGI IRIX-only. */
+ res = get_basic_section_data(dbg,&dbg->de_debug_varnames, &doas,
+ section_index,error,
+ DW_DLE_DEBUG_VARNAMES_DUPLICATE,0);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+ }
+ else if (strcmp(scn_name, ".debug_weaknames") == 0) {
+ /* SGI IRIX-only. */
+ res = get_basic_section_data(dbg,&dbg->de_debug_weaknames, &doas,
+ section_index,error,
+ DW_DLE_DEBUG_WEAKNAMES_DUPLICATE,0);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+ } else if (strcmp(scn_name, ".debug_macinfo") == 0) {
+ res = get_basic_section_data(dbg,&dbg->de_debug_macinfo, &doas,
+ section_index,error,
+ DW_DLE_DEBUG_MACINFO_DUPLICATE,0);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+ }
+ else if (strcmp(scn_name, ".debug_ranges") == 0) {
+ res = get_basic_section_data(dbg,&dbg->de_debug_ranges, &doas,
+ section_index,error,
+ DW_DLE_DEBUG_RANGES_DUPLICATE,0);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+ foundDwarf = TRUE;
+ }
+ else if (strcmp(scn_name, ".symtab") == 0) {
+ res = get_basic_section_data(dbg,&dbg->de_elf_symtab, &doas,
+ section_index,error,
+ DW_DLE_DEBUG_SYMTAB_ERR,0);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+ }
+ else if (strcmp(scn_name, ".strtab") == 0) {
+ res = get_basic_section_data(dbg,&dbg->de_elf_strtab, &doas,
+ section_index,error,
+ DW_DLE_DEBUG_STRTAB_ERR,0);
+ if(res != DW_DLV_OK) {
+ return res;
+ }
+ }
+ else if (strncmp(scn_name, ".rela.debug_",12) == 0) {
+ const char *rcn_name = scn_name + 5;
+ if (strcmp(rcn_name, ".debug_info") == 0) {
+ add_rela_data(&dbg->de_debug_info,&doas,section_index);
+ } else if (strcmp(rcn_name, ".debug_abbrev") == 0) {
+ add_rela_data(&dbg->de_debug_abbrev,&doas,section_index);
+ } else if (strcmp(rcn_name, ".debug_aranges") == 0) {
+ add_rela_data(&dbg->de_debug_aranges,&doas,section_index);
+ } else if (strcmp(rcn_name, ".debug_line") == 0) {
+ add_rela_data(&dbg->de_debug_line,&doas,section_index);
+ } else if (strcmp(rcn_name, ".debug_frame") == 0) {
+ add_rela_data(&dbg->de_debug_frame,&doas,section_index);
+ } else if (strcmp(rcn_name, ".eh_frame") == 0) {
+ add_rela_data(&dbg->de_debug_frame_eh_gnu,&doas,section_index);
+ } else if (strcmp(rcn_name, ".debug_loc") == 0) {
+ add_rela_data(&dbg->de_debug_loc,&doas,section_index);
+ } else if (strcmp(rcn_name, ".debug_pubnames") == 0) {
+ add_rela_data(&dbg->de_debug_pubnames,&doas,section_index);
+ } else if (strcmp(rcn_name, ".debug_str") == 0) {
+ add_rela_data(&dbg->de_debug_str,&doas,section_index);
+ } else if (strcmp(rcn_name, ".debug_funcnames") == 0) {
+ add_rela_data(&dbg->de_debug_funcnames,&doas,section_index);
+ } else if (strcmp(rcn_name, ".debug_typenames") == 0) {
+ add_rela_data(&dbg->de_debug_typenames,&doas,section_index);
+ } else if (strcmp(rcn_name, ".debug_pubtypes") == 0) {
+ add_rela_data(&dbg->de_debug_pubtypes,&doas,section_index);
+ } else if (strcmp(rcn_name, ".debug_varnames") == 0) {
+ add_rela_data(&dbg->de_debug_varnames,&doas,section_index);
+ } else if (strcmp(rcn_name, ".debug_weaknames") == 0) {
+ add_rela_data(&dbg->de_debug_weaknames,&doas,section_index);
+ } else if (strcmp(rcn_name, ".debug_macinfo") == 0) {
+ add_rela_data(&dbg->de_debug_macinfo,&doas,section_index);
+ }
+ }
+ }
+ if (foundDwarf) {
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+
+
+/*
+ Use a Dwarf_Obj_Access_Interface to kick things off. All other
+ init routines eventually use this one.
+ The returned Dwarf_Debug contains a copy of *obj
+ the callers copy of *obj may be freed whenever the caller
+ wishes.
+*/
+int
+dwarf_object_init(Dwarf_Obj_Access_Interface* obj, Dwarf_Handler errhand,
+ Dwarf_Ptr errarg, Dwarf_Debug* ret_dbg,
+ Dwarf_Error* error)
+{
+ Dwarf_Debug dbg = 0;
+ int setup_result = DW_DLV_OK;
+
+ dbg = _dwarf_get_debug();
+ if (dbg == NULL) {
+ DWARF_DBG_ERROR(dbg, DW_DLE_DBG_ALLOC, DW_DLV_ERROR);
+ }
+ dbg->de_errhand = errhand;
+ dbg->de_errarg = errarg;
+ dbg->de_frame_rule_initial_value = DW_FRAME_REG_INITIAL_VALUE;
+ dbg->de_frame_reg_rules_entry_count = DW_FRAME_LAST_REG_NUM;
+#ifdef HAVE_OLD_FRAME_CFA_COL
+ /* DW_FRAME_CFA_COL is really only suitable for old libdwarf frame
+ interfaces and its value of 0 there is only usable where
+ (as in MIPS) register 0 has no value other than 0 so
+ we can use the frame table column 0 for the CFA value
+ (and rely on client software to know when 'register 0'
+ is the cfa and when to just use a value 0 for register 0).
+ */
+ dbg->de_frame_cfa_col_number = DW_FRAME_CFA_COL;
+#else
+ dbg->de_frame_cfa_col_number = DW_FRAME_CFA_COL3;
+#endif
+ dbg->de_frame_same_value_number = DW_FRAME_SAME_VAL;
+ dbg->de_frame_undefined_value_number = DW_FRAME_UNDEFINED_VAL;
+
+ dbg->de_obj_file = obj;
+
+ setup_result = _dwarf_setup(dbg, error);
+ if (setup_result != DW_DLV_OK) {
+ /* The status we want to return here is of _dwarf_setup,
+ not of the _dwarf_free_all_of_one_debug(dbg) call.
+ So use a local status variable for the free. */
+ int freeresult = _dwarf_free_all_of_one_debug(dbg);
+ if (freeresult == DW_DLV_ERROR) {
+ DWARF_DBG_ERROR(dbg, DW_DLE_DBG_ALLOC, DW_DLV_ERROR);
+ }
+ dwarf_malloc_check_complete("After Final free");
+ return setup_result;
+ }
+
+ dwarf_harmless_init(&dbg->de_harmless_errors,
+ DW_HARMLESS_ERROR_CIRCULAR_LIST_DEFAULT_SIZE);
+
+ /* This call cannot fail: allocates nothing, releases nothing */
+ _dwarf_setup_debug(dbg);
+
+
+ *ret_dbg = dbg;
+ return DW_DLV_OK;
+}
+
+
+/*
+ A finish routine that is completely unaware of ELF.
+
+ Frees all memory that was not previously freed by
+ dwarf_dealloc.
+ Aside frmo certain categories.
+ */
+int
+dwarf_object_finish(Dwarf_Debug dbg, Dwarf_Error * error)
+{
+ int res = DW_DLV_OK;
+
+ res = _dwarf_free_all_of_one_debug(dbg);
+ if (res == DW_DLV_ERROR) {
+ DWARF_DBG_ERROR(dbg, DW_DLE_DBG_ALLOC, DW_DLV_ERROR);
+ }
+ dwarf_malloc_check_complete("After Final free");
+
+ return res;
+}
+
+
+/*
+ Load the ELF section with the specified index and set the
+ pointer pointed to by section_data to the memory where it
+ was loaded.
+ */
+int
+_dwarf_load_section(Dwarf_Debug dbg,
+ struct Dwarf_Section_s *section,
+ Dwarf_Error * error)
+{
+ int res = DW_DLV_ERROR;
+ int err = 0;
+ struct Dwarf_Obj_Access_Interface_s *o = 0;
+
+ /* check to see if the section is already loaded */
+ if (section->dss_data != NULL) {
+ return DW_DLV_OK;
+ }
+ o = dbg->de_obj_file;
+ res = o->methods->load_section(
+ o->object, section->dss_index,
+ &section->dss_data, &err);
+ if(res == DW_DLV_ERROR){
+ DWARF_DBG_ERROR(dbg, err, DW_DLV_ERROR);
+ }
+ if(_dwarf_apply_relocs == 0) {
+ return res;
+ }
+ if(section->dss_reloc_size == 0) {
+ return res;
+ }
+ if(!o->methods->relocate_a_section) {
+ return res;
+ }
+ /*apply relocations */
+ res = o->methods->relocate_a_section( o->object, section->dss_index,
+ dbg, &err);
+ if(res == DW_DLV_ERROR) {
+ DWARF_DBG_ERROR(dbg, err, DW_DLV_ERROR);
+ }
+ return res;
+}
+
+/* This is a hack so clients can verify offsets.
+ Added April 2005 so that debugger can detect broken offsets
+ (which happened in an IRIX -64 executable larger than 2GB
+ using MIPSpro 7.3.1.3 compilers. A couple .debug_pubnames
+ offsets were wrong.).
+*/
+int
+dwarf_get_section_max_offsets(Dwarf_Debug dbg,
+ Dwarf_Unsigned * debug_info_size,
+ Dwarf_Unsigned * debug_abbrev_size,
+ Dwarf_Unsigned * debug_line_size,
+ Dwarf_Unsigned * debug_loc_size,
+ Dwarf_Unsigned * debug_aranges_size,
+ Dwarf_Unsigned * debug_macinfo_size,
+ Dwarf_Unsigned * debug_pubnames_size,
+ Dwarf_Unsigned * debug_str_size,
+ Dwarf_Unsigned * debug_frame_size,
+ Dwarf_Unsigned * debug_ranges_size,
+ Dwarf_Unsigned * debug_typenames_size)
+{
+ *debug_info_size = dbg->de_debug_info.dss_size;
+ *debug_abbrev_size = dbg->de_debug_abbrev.dss_size;
+ *debug_line_size = dbg->de_debug_line.dss_size;
+ *debug_loc_size = dbg->de_debug_loc.dss_size;
+ *debug_aranges_size = dbg->de_debug_aranges.dss_size;
+ *debug_macinfo_size = dbg->de_debug_macinfo.dss_size;
+ *debug_pubnames_size = dbg->de_debug_pubnames.dss_size;
+ *debug_str_size = dbg->de_debug_str.dss_size;
+ *debug_frame_size = dbg->de_debug_frame.dss_size;
+ *debug_ranges_size = dbg->de_debug_ranges.dss_size;
+ *debug_typenames_size = dbg->de_debug_typenames.dss_size;
+ return DW_DLV_OK;
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_leb.c b/usr/src/lib/libdwarf/common/dwarf_leb.c
new file mode 100644
index 0000000000..b3b5d262f5
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_leb.c
@@ -0,0 +1,149 @@
+/*
+
+ Copyright (C) 2000,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
+
+*/
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+
+
+/*
+ decode ULEB
+*/
+Dwarf_Unsigned
+_dwarf_decode_u_leb128(Dwarf_Small * leb128, Dwarf_Word * leb128_length)
+{
+ unsigned char byte;
+ Dwarf_Word word_number;
+ Dwarf_Unsigned number;
+ Dwarf_Sword shift;
+ Dwarf_Sword byte_length;
+
+ /* The following unrolls-the-loop for the first few bytes and
+ unpacks into 32 bits to make this as fast as possible.
+ word_number is assumed big enough that the shift has a defined
+ result. */
+ if ((*leb128 & 0x80) == 0) {
+ if (leb128_length != NULL)
+ *leb128_length = 1;
+ return (*leb128);
+ } else if ((*(leb128 + 1) & 0x80) == 0) {
+ if (leb128_length != NULL)
+ *leb128_length = 2;
+
+ word_number = *leb128 & 0x7f;
+ word_number |= (*(leb128 + 1) & 0x7f) << 7;
+ return (word_number);
+ } else if ((*(leb128 + 2) & 0x80) == 0) {
+ if (leb128_length != NULL)
+ *leb128_length = 3;
+
+ word_number = *leb128 & 0x7f;
+ word_number |= (*(leb128 + 1) & 0x7f) << 7;
+ word_number |= (*(leb128 + 2) & 0x7f) << 14;
+ return (word_number);
+ } else if ((*(leb128 + 3) & 0x80) == 0) {
+ if (leb128_length != NULL)
+ *leb128_length = 4;
+
+ word_number = *leb128 & 0x7f;
+ word_number |= (*(leb128 + 1) & 0x7f) << 7;
+ word_number |= (*(leb128 + 2) & 0x7f) << 14;
+ word_number |= (*(leb128 + 3) & 0x7f) << 21;
+ return (word_number);
+ }
+
+ /* The rest handles long numbers Because the 'number' may be larger
+ than the default int/unsigned, we must cast the 'byte' before
+ the shift for the shift to have a defined result. */
+ number = 0;
+ shift = 0;
+ byte_length = 1;
+ byte = *(leb128);
+ for (;;) {
+ number |= ((Dwarf_Unsigned) (byte & 0x7f)) << shift;
+
+ if ((byte & 0x80) == 0) {
+ if (leb128_length != NULL)
+ *leb128_length = byte_length;
+ return (number);
+ }
+ shift += 7;
+
+ byte_length++;
+ ++leb128;
+ byte = *leb128;
+ }
+}
+
+#define BITSINBYTE 8
+
+/*
+ decode SLEB
+*/
+Dwarf_Signed
+_dwarf_decode_s_leb128(Dwarf_Small * leb128, Dwarf_Word * leb128_length)
+{
+ Dwarf_Signed number = 0;
+ Dwarf_Bool sign = 0;
+ Dwarf_Sword shift = 0;
+ unsigned char byte = *leb128;
+ Dwarf_Sword byte_length = 1;
+
+ /* byte_length being the number of bytes of data absorbed so far in
+ turning the leb into a Dwarf_Signed. */
+
+ for (;;) {
+ sign = byte & 0x40;
+ number |= ((Dwarf_Signed) ((byte & 0x7f))) << shift;
+ shift += 7;
+
+ if ((byte & 0x80) == 0) {
+ break;
+ }
+ ++leb128;
+ byte = *leb128;
+ byte_length++;
+ }
+
+ if ((shift < sizeof(Dwarf_Signed) * BITSINBYTE) && sign) {
+ number |= -((Dwarf_Signed) 1 << shift);
+ }
+
+ if (leb128_length != NULL)
+ *leb128_length = byte_length;
+ return (number);
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_line.c b/usr/src/lib/libdwarf/common/dwarf_line.c
new file mode 100644
index 0000000000..e7e15e7c1a
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_line.c
@@ -0,0 +1,1951 @@
+/*
+ Copyright (C) 2000-2006 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2007-2010 David Anderson. 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
+
+*/
+/* The address of the Free Software Foundation is
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ SGI has moved from the Crittenden Lane address.
+*/
+
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include "dwarf_line.h"
+
+static int
+is_path_separator(Dwarf_Small s)
+{
+ if(s == '/') {
+ return 1;
+ }
+#ifdef HAVE_WINDOWS_PATH
+ if(s == '\\') {
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+/* Return 0 if false, 1 if true.
+ If HAVE_WINDOWS_PATH is defined we
+ attempt to handle windows full paths:
+ \\something or C:cwdpath.c
+*/
+static int
+file_name_is_full_path(Dwarf_Small *fname)
+{
+ Dwarf_Small firstc = *fname;
+ if(is_path_separator(firstc)) {
+ /* Full path. */
+ return 1;
+ }
+ if(!firstc) {
+ return 0;
+ }
+#ifdef HAVE_WINDOWS_PATH
+ if((firstc >= 'A' && firstc <= 'Z') ||
+ (firstc >= 'a' && firstc <= 'z')) {
+ Dwarf_Small secondc = fname[1];
+ if (secondc == ':') {
+ return 1;
+ }
+ }
+#endif
+ return 0;
+}
+
+/*
+ Although source files is supposed to return the
+ source files in the compilation-unit, it does
+ not look for any in the statement program. In
+ other words, it ignores those defined using the
+ extended opcode DW_LNE_define_file.
+*/
+int
+dwarf_srcfiles(Dwarf_Die die,
+ char ***srcfiles,
+ Dwarf_Signed * srcfilecount, Dwarf_Error * error)
+{
+ /* This pointer is used to scan the portion of the .debug_line
+ section for the current cu. */
+ Dwarf_Small *line_ptr;
+
+ /* Pointer to a DW_AT_stmt_list attribute in case it exists in the
+ die. */
+ Dwarf_Attribute stmt_list_attr;
+
+ /* Pointer to DW_AT_comp_dir attribute in die. */
+ Dwarf_Attribute comp_dir_attr;
+
+ /* Pointer to name of compilation directory. */
+ Dwarf_Small *comp_dir = 0;
+
+ /* Offset into .debug_line specified by a DW_AT_stmt_list
+ attribute. */
+ Dwarf_Unsigned line_offset = 0;
+
+ /* This points to a block of char *'s, each of which points to a
+ file name. */
+ char **ret_files = 0;
+
+ /* The Dwarf_Debug this die belongs to. */
+ Dwarf_Debug dbg = 0;
+
+ /* Used to chain the file names. */
+ Dwarf_Chain curr_chain = NULL;
+ Dwarf_Chain prev_chain = NULL;
+ Dwarf_Chain head_chain = NULL;
+ Dwarf_Half attrform = 0;
+ int resattr = DW_DLV_ERROR;
+ int lres = DW_DLV_ERROR;
+ struct Line_Table_Prefix_s line_prefix;
+ int i = 0;
+ int res = DW_DLV_ERROR;
+
+ /* ***** BEGIN CODE ***** */
+ /* Reset error. */
+ if (error != NULL)
+ *error = NULL;
+
+ CHECK_DIE(die, DW_DLV_ERROR);
+ dbg = die->di_cu_context->cc_dbg;
+
+ resattr = dwarf_attr(die, DW_AT_stmt_list, &stmt_list_attr, error);
+ if (resattr != DW_DLV_OK) {
+ return resattr;
+ }
+
+ if (dbg->de_debug_line.dss_index == 0) {
+ _dwarf_error(dbg, error, DW_DLE_DEBUG_LINE_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ res = _dwarf_load_section(dbg, &dbg->de_debug_line,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ lres = dwarf_whatform(stmt_list_attr,&attrform,error);
+ if (lres != DW_DLV_OK) {
+ return lres;
+ }
+ if (attrform != DW_FORM_data4 && attrform != DW_FORM_data8 &&
+ attrform != DW_FORM_sec_offset ) {
+ _dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD);
+ return (DW_DLV_ERROR);
+ }
+ lres = dwarf_global_formref(stmt_list_attr, &line_offset, error);
+ if (lres != DW_DLV_OK) {
+ return lres;
+ }
+ if (line_offset >= dbg->de_debug_line.dss_size) {
+ _dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD);
+ return (DW_DLV_ERROR);
+ }
+ line_ptr = dbg->de_debug_line.dss_data + line_offset;
+ dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR);
+
+ /*
+ If die has DW_AT_comp_dir attribute, get the string that names
+ the compilation directory. */
+ resattr = dwarf_attr(die, DW_AT_comp_dir, &comp_dir_attr, error);
+ if (resattr == DW_DLV_ERROR) {
+ return resattr;
+ }
+ if (resattr == DW_DLV_OK) {
+ int cres = DW_DLV_ERROR;
+ char *cdir = 0;
+
+ cres = dwarf_formstring(comp_dir_attr, &cdir, error);
+ if (cres == DW_DLV_ERROR) {
+ return cres;
+ } else if (cres == DW_DLV_OK) {
+ comp_dir = (Dwarf_Small *) cdir;
+ }
+ }
+ if (resattr == DW_DLV_OK) {
+ dwarf_dealloc(dbg, comp_dir_attr, DW_DLA_ATTR);
+ }
+ dwarf_init_line_table_prefix(&line_prefix);
+ {
+ Dwarf_Small *line_ptr_out = 0;
+ int dres = dwarf_read_line_table_prefix(dbg,
+ line_ptr,
+ dbg->de_debug_line.dss_size,
+ &line_ptr_out,
+ &line_prefix,
+ NULL, NULL,error,
+ 0);
+
+ if (dres == DW_DLV_ERROR) {
+ dwarf_free_line_table_prefix(&line_prefix);
+ return dres;
+ }
+ if (dres == DW_DLV_NO_ENTRY) {
+ dwarf_free_line_table_prefix(&line_prefix);
+ return dres;
+ }
+
+ line_ptr = line_ptr_out;
+ }
+
+ for (i = 0; i < line_prefix.pf_files_count; ++i) {
+ struct Line_Table_File_Entry_s *fe =
+ line_prefix.pf_line_table_file_entries + i;
+ char *file_name = (char *) fe->lte_filename;
+ char *dir_name = 0;
+ char *full_name = 0;
+ Dwarf_Unsigned dir_index = fe->lte_directory_index;
+
+ if (dir_index == 0) {
+ dir_name = (char *) comp_dir;
+ } else {
+ dir_name =
+ (char *) line_prefix.pf_include_directories[
+ fe->lte_directory_index - 1];
+ }
+
+ /* dir_name can be NULL if there is no DW_AT_comp_dir */
+ if(dir_name == 0 || file_name_is_full_path((unsigned char *)file_name)) {
+ /* This is safe because dwarf_dealloc is careful to not
+ dealloc strings which are part of the raw .debug_* data.
+ */
+ full_name = file_name;
+ } else {
+ full_name = (char *) _dwarf_get_alloc(dbg, DW_DLA_STRING,
+ strlen(dir_name) + 1 +
+ strlen(file_name) +
+ 1);
+ if (full_name == NULL) {
+ dwarf_free_line_table_prefix(&line_prefix);
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ /* This is not careful to avoid // in the output, Nothing
+ forces a 'canonical' name format here. Unclear if this
+ needs to be fixed. */
+ strcpy(full_name, dir_name);
+ strcat(full_name, "/");
+ strcat(full_name, file_name);
+ }
+ curr_chain =
+ (Dwarf_Chain) _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
+ if (curr_chain == NULL) {
+ dwarf_free_line_table_prefix(&line_prefix);
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ curr_chain->ch_item = full_name;
+ if (head_chain == NULL)
+ head_chain = prev_chain = curr_chain;
+ else {
+ prev_chain->ch_next = curr_chain;
+ prev_chain = curr_chain;
+ }
+ }
+
+ curr_chain = (Dwarf_Chain) _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
+ if (curr_chain == NULL) {
+ dwarf_free_line_table_prefix(&line_prefix);
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+
+
+
+ if (line_prefix.pf_files_count == 0) {
+ *srcfiles = NULL;
+ *srcfilecount = 0;
+ dwarf_free_line_table_prefix(&line_prefix);
+ return (DW_DLV_NO_ENTRY);
+ }
+
+ ret_files = (char **)
+ _dwarf_get_alloc(dbg, DW_DLA_LIST, line_prefix.pf_files_count);
+ if (ret_files == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ dwarf_free_line_table_prefix(&line_prefix);
+ return (DW_DLV_ERROR);
+ }
+
+ curr_chain = head_chain;
+ for (i = 0; i < line_prefix.pf_files_count; i++) {
+ *(ret_files + i) = curr_chain->ch_item;
+ prev_chain = curr_chain;
+ curr_chain = curr_chain->ch_next;
+ dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN);
+ }
+
+ *srcfiles = ret_files;
+ *srcfilecount = line_prefix.pf_files_count;
+ dwarf_free_line_table_prefix(&line_prefix);
+ return (DW_DLV_OK);
+}
+
+
+/*
+ return DW_DLV_OK if ok. else DW_DLV_NO_ENTRY or DW_DLV_ERROR
+*/
+int
+_dwarf_internal_srclines(Dwarf_Die die,
+ Dwarf_Line ** linebuf,
+ Dwarf_Signed * count,
+ Dwarf_Bool doaddrs,
+ Dwarf_Bool dolines, Dwarf_Error * error)
+{
+ /* This pointer is used to scan the portion of the .debug_line
+ section for the current cu. */
+ Dwarf_Small *line_ptr = 0;
+
+ /* This points to the last byte of the .debug_line portion for the
+ current cu. */
+ Dwarf_Small *line_ptr_end = 0;
+
+ /* Pointer to a DW_AT_stmt_list attribute in case it exists in the
+ die. */
+ Dwarf_Attribute stmt_list_attr = 0;
+
+ /* Pointer to DW_AT_comp_dir attribute in die. */
+ Dwarf_Attribute comp_dir_attr = 0;
+
+ /* Pointer to name of compilation directory. */
+ Dwarf_Small *comp_dir = NULL;
+
+ /* Offset into .debug_line specified by a DW_AT_stmt_list
+ attribute. */
+ Dwarf_Unsigned line_offset = 0;
+
+ Dwarf_File_Entry file_entries = 0;
+
+ /* These are the state machine state variables. */
+ Dwarf_Addr address = 0;
+ Dwarf_Word file = 1;
+ Dwarf_Word line = 1;
+ Dwarf_Word column = 0;
+
+ /* Phony init. See below for true initialization. */
+ Dwarf_Bool is_stmt = false;
+
+ Dwarf_Bool basic_block = false;
+ Dwarf_Bool prologue_end = false;
+ Dwarf_Bool epilogue_begin = false;
+ Dwarf_Small isa = 0;
+ Dwarf_Bool end_sequence = false;
+
+ /* These pointers are used to build the list of files names by this
+ cu. cur_file_entry points to the file name being added, and
+ prev_file_entry to the previous one. */
+ Dwarf_File_Entry cur_file_entry, prev_file_entry;
+
+ Dwarf_Sword i = 0;
+ Dwarf_Sword file_entry_count = 0;
+
+ /* This is the current opcode read from the statement program. */
+ Dwarf_Small opcode = 0;
+
+ /* Pointer to a Dwarf_Line_Context_s structure that contains the
+ context such as file names and include directories for the set
+ of lines being generated. */
+ Dwarf_Line_Context line_context = 0;
+
+ /* This is a pointer to the current line being added to the line
+ matrix. */
+ Dwarf_Line curr_line = 0;
+
+ /* These variables are used to decode leb128 numbers. Leb128_num
+ holds the decoded number, and leb128_length is its length in
+ bytes. */
+ Dwarf_Word leb128_num = 0;
+ Dwarf_Word leb128_length = 0;
+ Dwarf_Sword advance_line = 0;
+
+ /* This is the operand of the latest fixed_advance_pc extended
+ opcode. */
+ Dwarf_Half fixed_advance_pc = 0;
+
+ /* Counts the number of lines in the line matrix. */
+ Dwarf_Sword line_count = 0;
+
+ /* This is the length of an extended opcode instr. */
+ Dwarf_Word instr_length = 0;
+ Dwarf_Small ext_opcode = 0;
+ struct Line_Table_Prefix_s prefix;
+
+ /* Used to chain together pointers to line table entries that are
+ later used to create a block of Dwarf_Line entries. */
+ Dwarf_Chain chain_line = NULL;
+ Dwarf_Chain head_chain = NULL;
+ Dwarf_Chain curr_chain = NULL;
+
+ /* This points to a block of Dwarf_Lines, a pointer to which is
+ returned in linebuf. */
+ Dwarf_Line *block_line = 0;
+
+ /* The Dwarf_Debug this die belongs to. */
+ Dwarf_Debug dbg = 0;
+ int resattr = DW_DLV_ERROR;
+ int lres = DW_DLV_ERROR;
+ Dwarf_Half address_size = 0;
+
+ int res = DW_DLV_ERROR;
+
+ /* ***** BEGIN CODE ***** */
+ if (error != NULL)
+ *error = NULL;
+
+ CHECK_DIE(die, DW_DLV_ERROR);
+ dbg = die->di_cu_context->cc_dbg;
+
+ res = _dwarf_load_section(dbg, &dbg->de_debug_line,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ address_size = _dwarf_get_address_size(dbg, die);
+ resattr = dwarf_attr(die, DW_AT_stmt_list, &stmt_list_attr, error);
+ if (resattr != DW_DLV_OK) {
+ return resattr;
+ }
+
+ lres = dwarf_formudata(stmt_list_attr, &line_offset, error);
+ if (lres != DW_DLV_OK) {
+ return lres;
+ }
+
+ if (line_offset >= dbg->de_debug_line.dss_size) {
+ _dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD);
+ return (DW_DLV_ERROR);
+ }
+ line_ptr = dbg->de_debug_line.dss_data + line_offset;
+ dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR);
+
+ /* If die has DW_AT_comp_dir attribute, get the string that names
+ the compilation directory. */
+ resattr = dwarf_attr(die, DW_AT_comp_dir, &comp_dir_attr, error);
+ if (resattr == DW_DLV_ERROR) {
+ return resattr;
+ }
+ if (resattr == DW_DLV_OK) {
+ int cres = DW_DLV_ERROR;
+ char *cdir = 0;
+
+ cres = dwarf_formstring(comp_dir_attr, &cdir, error);
+ if (cres == DW_DLV_ERROR) {
+ return cres;
+ } else if (cres == DW_DLV_OK) {
+ comp_dir = (Dwarf_Small *) cdir;
+ }
+ }
+ if (resattr == DW_DLV_OK) {
+ dwarf_dealloc(dbg, comp_dir_attr, DW_DLA_ATTR);
+ }
+ dwarf_init_line_table_prefix(&prefix);
+
+ {
+ Dwarf_Small *newlinep = 0;
+ int res = dwarf_read_line_table_prefix(dbg,
+ line_ptr,
+ dbg->de_debug_line.dss_size,
+ &newlinep,
+ &prefix,
+ NULL,NULL,
+ error,
+ 0);
+
+ if (res == DW_DLV_ERROR) {
+ dwarf_free_line_table_prefix(&prefix);
+ return res;
+ }
+ if (res == DW_DLV_NO_ENTRY) {
+ dwarf_free_line_table_prefix(&prefix);
+ return res;
+ }
+ line_ptr_end = prefix.pf_line_ptr_end;
+ line_ptr = newlinep;
+ }
+
+
+ /* Set up context structure for this set of lines. */
+ line_context = (Dwarf_Line_Context)
+ _dwarf_get_alloc(dbg, DW_DLA_LINE_CONTEXT, 1);
+ if (line_context == NULL) {
+ dwarf_free_line_table_prefix(&prefix);
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ /* Fill out a Dwarf_File_Entry list as we use that to implement the
+ define_file operation. */
+ file_entries = prev_file_entry = NULL;
+ for (i = 0; i < prefix.pf_files_count; ++i) {
+ struct Line_Table_File_Entry_s *pfxfile =
+ prefix.pf_line_table_file_entries + i;
+
+ cur_file_entry = (Dwarf_File_Entry)
+ _dwarf_get_alloc(dbg, DW_DLA_FILE_ENTRY, 1);
+ if (cur_file_entry == NULL) {
+ dwarf_free_line_table_prefix(&prefix);
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ cur_file_entry->fi_file_name = pfxfile->lte_filename;
+ cur_file_entry->fi_dir_index = pfxfile->lte_directory_index;
+ cur_file_entry->fi_time_last_mod =
+ pfxfile->lte_last_modification_time;
+
+ cur_file_entry->fi_file_length = pfxfile->lte_length_of_file;
+
+ if (file_entries == NULL)
+ file_entries = cur_file_entry;
+ else
+ prev_file_entry->fi_next = cur_file_entry;
+ prev_file_entry = cur_file_entry;
+
+ file_entry_count++;
+ }
+
+
+ /* Initialize the one state machine variable that depends on the
+ prefix. */
+ is_stmt = prefix.pf_default_is_stmt;
+
+
+ /* Start of statement program. */
+ while (line_ptr < line_ptr_end) {
+ int type;
+
+ opcode = *(Dwarf_Small *) line_ptr;
+ line_ptr++;
+
+
+ /* 'type' is the output */
+ WHAT_IS_OPCODE(type, opcode, prefix.pf_opcode_base,
+ prefix.pf_opcode_length_table, line_ptr,
+ prefix.pf_std_op_count);
+
+ if (type == LOP_DISCARD) {
+ int oc;
+ int opcnt = prefix.pf_opcode_length_table[opcode];
+
+ for (oc = 0; oc < opcnt; oc++) {
+ /*
+ ** Read and discard operands we don't
+ ** understand.
+ ** arbitrary choice of unsigned read.
+ ** signed read would work as well.
+ */
+ Dwarf_Unsigned utmp2;
+
+ DECODE_LEB128_UWORD(line_ptr, utmp2);
+ }
+ } else if (type == LOP_SPECIAL) {
+ /* This op code is a special op in the object, no matter
+ that it might fall into the standard op range in this
+ compile. That is, these are special opcodes between
+ opcode_base and MAX_LINE_OP_CODE. (including
+ opcode_base and MAX_LINE_OP_CODE) */
+
+ opcode = opcode - prefix.pf_opcode_base;
+ address = address + prefix.pf_minimum_instruction_length *
+ (opcode / prefix.pf_line_range);
+ line =
+ line + prefix.pf_line_base +
+ opcode % prefix.pf_line_range;
+
+ if (dolines) {
+ curr_line =
+ (Dwarf_Line) _dwarf_get_alloc(dbg, DW_DLA_LINE, 1);
+ if (curr_line == NULL) {
+ dwarf_free_line_table_prefix(&prefix);
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ curr_line->li_address = address;
+ curr_line->li_addr_line.li_l_data.li_file =
+ (Dwarf_Sword) file;
+ curr_line->li_addr_line.li_l_data.li_line =
+ (Dwarf_Sword) line;
+ curr_line->li_addr_line.li_l_data.li_column =
+ (Dwarf_Half) column;
+ curr_line->li_addr_line.li_l_data.li_is_stmt = is_stmt;
+ curr_line->li_addr_line.li_l_data.li_basic_block =
+ basic_block;
+ curr_line->li_addr_line.li_l_data.li_end_sequence =
+ curr_line->li_addr_line.li_l_data.
+ li_epilogue_begin = epilogue_begin;
+ curr_line->li_addr_line.li_l_data.li_prologue_end =
+ prologue_end;
+ curr_line->li_addr_line.li_l_data.li_isa = isa;
+ curr_line->li_context = line_context;
+ line_count++;
+
+ chain_line = (Dwarf_Chain)
+ _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
+ if (chain_line == NULL) {
+ dwarf_free_line_table_prefix(&prefix);
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ chain_line->ch_item = curr_line;
+
+ if (head_chain == NULL)
+ head_chain = curr_chain = chain_line;
+ else {
+ curr_chain->ch_next = chain_line;
+ curr_chain = chain_line;
+ }
+ }
+
+ basic_block = false;
+ } else if (type == LOP_STANDARD) {
+ switch (opcode) {
+
+ case DW_LNS_copy:{
+ if (dolines) {
+
+ curr_line =
+ (Dwarf_Line) _dwarf_get_alloc(dbg,
+ DW_DLA_LINE,
+ 1);
+ if (curr_line == NULL) {
+ dwarf_free_line_table_prefix(&prefix);
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ curr_line->li_address = address;
+ curr_line->li_addr_line.li_l_data.li_file =
+ (Dwarf_Sword) file;
+ curr_line->li_addr_line.li_l_data.li_line =
+ (Dwarf_Sword) line;
+ curr_line->li_addr_line.li_l_data.li_column =
+ (Dwarf_Half) column;
+ curr_line->li_addr_line.li_l_data.li_is_stmt =
+ is_stmt;
+ curr_line->li_addr_line.li_l_data.
+ li_basic_block = basic_block;
+ curr_line->li_addr_line.li_l_data.
+ li_end_sequence = end_sequence;
+ curr_line->li_context = line_context;
+ curr_line->li_addr_line.li_l_data.
+ li_epilogue_begin = epilogue_begin;
+ curr_line->li_addr_line.li_l_data.
+ li_prologue_end = prologue_end;
+ curr_line->li_addr_line.li_l_data.li_isa = isa;
+ line_count++;
+
+ chain_line = (Dwarf_Chain)
+ _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
+ if (chain_line == NULL) {
+ dwarf_free_line_table_prefix(&prefix);
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ chain_line->ch_item = curr_line;
+ if (head_chain == NULL)
+ head_chain = curr_chain = chain_line;
+ else {
+ curr_chain->ch_next = chain_line;
+ curr_chain = chain_line;
+ }
+ }
+
+ basic_block = false;
+ prologue_end = false;
+ epilogue_begin = false;
+ break;
+ }
+
+ case DW_LNS_advance_pc:{
+ Dwarf_Unsigned utmp2;
+
+ DECODE_LEB128_UWORD(line_ptr, utmp2);
+ leb128_num = (Dwarf_Word) utmp2;
+ address =
+ address +
+ prefix.pf_minimum_instruction_length *
+ leb128_num;
+ break;
+ }
+
+ case DW_LNS_advance_line:{
+ Dwarf_Signed stmp;
+
+ DECODE_LEB128_SWORD(line_ptr, stmp);
+ advance_line = (Dwarf_Sword) stmp;
+ line = line + advance_line;
+ break;
+ }
+
+ case DW_LNS_set_file:{
+ Dwarf_Unsigned utmp2;
+
+ DECODE_LEB128_UWORD(line_ptr, utmp2);
+ file = (Dwarf_Word) utmp2;
+ break;
+ }
+
+ case DW_LNS_set_column:{
+ Dwarf_Unsigned utmp2;
+
+ DECODE_LEB128_UWORD(line_ptr, utmp2);
+ column = (Dwarf_Word) utmp2;
+ break;
+ }
+
+ case DW_LNS_negate_stmt:{
+
+ is_stmt = !is_stmt;
+ break;
+ }
+
+ case DW_LNS_set_basic_block:{
+
+ basic_block = true;
+ break;
+ }
+
+ case DW_LNS_const_add_pc:{
+ opcode = MAX_LINE_OP_CODE - prefix.pf_opcode_base;
+ address = address +
+ prefix.pf_minimum_instruction_length * (opcode /
+ prefix.
+ pf_line_range);
+ break;
+ }
+
+ case DW_LNS_fixed_advance_pc:{
+
+ READ_UNALIGNED(dbg, fixed_advance_pc, Dwarf_Half,
+ line_ptr, sizeof(Dwarf_Half));
+ line_ptr += sizeof(Dwarf_Half);
+ address = address + fixed_advance_pc;
+ break;
+ }
+
+ /* New in DWARF3 */
+ case DW_LNS_set_prologue_end:{
+
+ prologue_end = true;
+ break;
+
+
+ }
+ /* New in DWARF3 */
+ case DW_LNS_set_epilogue_begin:{
+ epilogue_begin = true;
+ break;
+ }
+
+ /* New in DWARF3 */
+ case DW_LNS_set_isa:{
+ Dwarf_Unsigned utmp2;
+
+ DECODE_LEB128_UWORD(line_ptr, utmp2);
+ isa = utmp2;
+ if (isa != utmp2) {
+ /* The value of the isa did not fit in our
+ local so we record it wrong. declare an
+ error. */
+ dwarf_free_line_table_prefix(&prefix);
+
+ _dwarf_error(dbg, error,
+ DW_DLE_LINE_NUM_OPERANDS_BAD);
+ return (DW_DLV_ERROR);
+ }
+ break;
+ }
+ }
+
+ } else if (type == LOP_EXTENDED) {
+ Dwarf_Unsigned utmp3;
+
+ DECODE_LEB128_UWORD(line_ptr, utmp3);
+ instr_length = (Dwarf_Word) utmp3;
+ /* Dwarf_Small is a ubyte and the extended opcode is a
+ ubyte, though not stated as clearly in the 2.0.0 spec as
+ one might hope. */
+ ext_opcode = *(Dwarf_Small *) line_ptr;
+ line_ptr++;
+ switch (ext_opcode) {
+
+ case DW_LNE_end_sequence:{
+ end_sequence = true;
+
+ if (dolines) {
+ curr_line = (Dwarf_Line)
+ _dwarf_get_alloc(dbg, DW_DLA_LINE, 1);
+ if (curr_line == NULL) {
+ dwarf_free_line_table_prefix(&prefix);
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ curr_line->li_address = address;
+ curr_line->li_addr_line.li_l_data.li_file =
+ (Dwarf_Sword) file;
+ curr_line->li_addr_line.li_l_data.li_line =
+ (Dwarf_Sword) line;
+ curr_line->li_addr_line.li_l_data.li_column =
+ (Dwarf_Half) column;
+ curr_line->li_addr_line.li_l_data.li_is_stmt =
+ prefix.pf_default_is_stmt;
+ curr_line->li_addr_line.li_l_data.
+ li_basic_block = basic_block;
+ curr_line->li_addr_line.li_l_data.
+ li_end_sequence = end_sequence;
+ curr_line->li_context = line_context;
+ curr_line->li_addr_line.li_l_data.
+ li_epilogue_begin = epilogue_begin;
+ curr_line->li_addr_line.li_l_data.
+ li_prologue_end = prologue_end;
+ curr_line->li_addr_line.li_l_data.li_isa = isa;
+ line_count++;
+
+ chain_line = (Dwarf_Chain)
+ _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
+ if (chain_line == NULL) {
+ dwarf_free_line_table_prefix(&prefix);
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ chain_line->ch_item = curr_line;
+
+ if (head_chain == NULL)
+ head_chain = curr_chain = chain_line;
+ else {
+ curr_chain->ch_next = chain_line;
+ curr_chain = chain_line;
+ }
+ }
+
+ address = 0;
+ file = 1;
+ line = 1;
+ column = 0;
+ is_stmt = prefix.pf_default_is_stmt;
+ basic_block = false;
+ end_sequence = false;
+ prologue_end = false;
+ epilogue_begin = false;
+
+
+ break;
+ }
+
+ case DW_LNE_set_address:{
+ {
+ READ_UNALIGNED(dbg, address, Dwarf_Addr,
+ line_ptr, address_size);
+ if (doaddrs) {
+ curr_line =
+ (Dwarf_Line) _dwarf_get_alloc(dbg,
+ DW_DLA_LINE,
+ 1);
+ if (curr_line == NULL) {
+ dwarf_free_line_table_prefix(&prefix);
+ _dwarf_error(dbg, error,
+ DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ curr_line->li_address = address;
+ curr_line->li_addr_line.li_offset =
+ line_ptr - dbg->de_debug_line.dss_data;
+
+ line_count++;
+
+ chain_line = (Dwarf_Chain)
+ _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
+ if (chain_line == NULL) {
+ dwarf_free_line_table_prefix(&prefix);
+ _dwarf_error(dbg, error,
+ DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ chain_line->ch_item = curr_line;
+
+ if (head_chain == NULL)
+ head_chain = curr_chain = chain_line;
+ else {
+ curr_chain->ch_next = chain_line;
+ curr_chain = chain_line;
+ }
+ }
+
+ line_ptr += address_size;
+ }
+
+ break;
+ }
+
+ case DW_LNE_define_file:{
+
+ if (dolines) {
+ cur_file_entry = (Dwarf_File_Entry)
+ _dwarf_get_alloc(dbg, DW_DLA_FILE_ENTRY, 1);
+ if (cur_file_entry == NULL) {
+ dwarf_free_line_table_prefix(&prefix);
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ cur_file_entry->fi_file_name =
+ (Dwarf_Small *) line_ptr;
+ line_ptr =
+ line_ptr + strlen((char *) line_ptr) + 1;
+
+ cur_file_entry->fi_dir_index = (Dwarf_Sword)
+ _dwarf_decode_u_leb128(line_ptr,
+ &leb128_length);
+ line_ptr = line_ptr + leb128_length;
+
+ cur_file_entry->fi_time_last_mod =
+ _dwarf_decode_u_leb128(line_ptr,
+ &leb128_length);
+ line_ptr = line_ptr + leb128_length;
+
+ cur_file_entry->fi_file_length =
+ _dwarf_decode_u_leb128(line_ptr,
+ &leb128_length);
+ line_ptr = line_ptr + leb128_length;
+
+ if (file_entries == NULL)
+ file_entries = cur_file_entry;
+ else
+ prev_file_entry->fi_next = cur_file_entry;
+ prev_file_entry = cur_file_entry;
+
+ file_entry_count++;
+ }
+ break;
+ }
+
+ default:{
+ /* This is an extended op code we do not know about,
+ other than we know now many bytes it is
+ and the op code and the bytes of operand. */
+ Dwarf_Unsigned remaining_bytes = instr_length -1;
+ if(instr_length < 1 || remaining_bytes > DW_LNE_LEN_MAX) {
+ dwarf_free_line_table_prefix(&prefix);
+ _dwarf_error(dbg, error,
+ DW_DLE_LINE_EXT_OPCODE_BAD);
+ return (DW_DLV_ERROR);
+ }
+ line_ptr += remaining_bytes;
+ break;
+ }
+ }
+
+ }
+ }
+
+ block_line = (Dwarf_Line *)
+ _dwarf_get_alloc(dbg, DW_DLA_LIST, line_count);
+ if (block_line == NULL) {
+ dwarf_free_line_table_prefix(&prefix);
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ curr_chain = head_chain;
+ for (i = 0; i < line_count; i++) {
+ *(block_line + i) = curr_chain->ch_item;
+ head_chain = curr_chain;
+ curr_chain = curr_chain->ch_next;
+ dwarf_dealloc(dbg, head_chain, DW_DLA_CHAIN);
+ }
+
+ line_context->lc_file_entries = file_entries;
+ line_context->lc_file_entry_count = file_entry_count;
+ line_context->lc_include_directories_count =
+ prefix.pf_include_directories_count;
+ if (prefix.pf_include_directories_count > 0) {
+ /* This gets a pointer to the *first* include dir. The others
+ follow directly with the standard DWARF2/3 NUL byte
+ following the last. */
+ line_context->lc_include_directories =
+ prefix.pf_include_directories[0];
+ }
+
+ line_context->lc_line_count = line_count;
+ line_context->lc_compilation_directory = comp_dir;
+ line_context->lc_version_number = prefix.pf_version;
+ line_context->lc_dbg = dbg;
+ *count = line_count;
+
+ *linebuf = block_line;
+ dwarf_free_line_table_prefix(&prefix);
+ return (DW_DLV_OK);
+}
+
+int
+dwarf_srclines(Dwarf_Die die,
+ Dwarf_Line ** linebuf,
+ Dwarf_Signed * linecount, Dwarf_Error * error)
+{
+ Dwarf_Signed count = 0;
+ int res = _dwarf_internal_srclines(die, linebuf, &count,
+ /* addrlist= */ false,
+ /* linelist= */ true, error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ *linecount = count;
+ return res;
+}
+
+
+
+/* Every line table entry (except DW_DLE_end_sequence,
+ which is returned using dwarf_lineendsequence())
+ potentially has the begin-statement
+ flag marked 'on'. This returns thru *return_bool,
+ the begin-statement flag.
+*/
+
+int
+dwarf_linebeginstatement(Dwarf_Line line,
+ Dwarf_Bool * return_bool, Dwarf_Error * error)
+{
+ if (line == NULL || return_bool == 0) {
+ _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ *return_bool = (line->li_addr_line.li_l_data.li_is_stmt);
+ return DW_DLV_OK;
+}
+
+/* At the end of any contiguous line-table there may be
+ a DW_LNE_end_sequence operator.
+ This returns non-zero thru *return_bool
+ if and only if this 'line' entry was a DW_LNE_end_sequence.
+
+ Within a compilation unit or function there may be multiple
+ line tables, each ending with a DW_LNE_end_sequence.
+ Each table describes a contiguous region.
+ Because compilers may split function code up in arbitrary ways
+ compilers may need to emit multiple contigous regions (ie
+ line tables) for a single function.
+ See the DWARF3 spec section 6.2.
+*/
+int
+dwarf_lineendsequence(Dwarf_Line line,
+ Dwarf_Bool * return_bool, Dwarf_Error * error)
+{
+ if (line == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ *return_bool = (line->li_addr_line.li_l_data.li_end_sequence);
+ return DW_DLV_OK;
+}
+
+
+/* Each 'line' entry has a line-number.
+ If the entry is a DW_LNE_end_sequence the line-number is
+ meaningless (see dwarf_lineendsequence(), just above).
+*/
+int
+dwarf_lineno(Dwarf_Line line,
+ Dwarf_Unsigned * ret_lineno, Dwarf_Error * error)
+{
+ if (line == NULL || ret_lineno == 0) {
+ _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ *ret_lineno = (line->li_addr_line.li_l_data.li_line);
+ return DW_DLV_OK;
+}
+
+/* Each 'line' entry has a file-number, and index into the file table.
+ If the entry is a DW_LNE_end_sequence the index is
+ meaningless (see dwarf_lineendsequence(), just above).
+ The file number returned is an index into the file table
+ produced by dwarf_srcfiles(), but care is required: the
+ li_file begins with 1 for real files, so that the li_file returned here
+ is 1 greater than its index into the dwarf_srcfiles() output array.
+ And entries from DW_LNE_define_file don't appear in
+ the dwarf_srcfiles() output so file indexes from here may exceed
+ the size of the dwarf_srcfiles() output array size.
+*/
+int
+dwarf_line_srcfileno(Dwarf_Line line,
+ Dwarf_Unsigned * ret_fileno, Dwarf_Error * error)
+{
+ if (line == NULL || ret_fileno == 0) {
+ _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL);
+ return (DW_DLV_ERROR);
+ }
+ /* li_file must be <= line->li_context->lc_file_entry_count else it
+ is trash. li_file 0 means not attributable to any source file
+ per dwarf2/3 spec. */
+
+ *ret_fileno = (line->li_addr_line.li_l_data.li_file);
+ return DW_DLV_OK;
+}
+
+
+/* Each 'line' entry has a line-address.
+ If the entry is a DW_LNE_end_sequence the adddress
+ is one-beyond the last address this contigous region
+ covers, so the address is not inside the region,
+ but is just outside it.
+*/
+int
+dwarf_lineaddr(Dwarf_Line line,
+ Dwarf_Addr * ret_lineaddr, Dwarf_Error * error)
+{
+ if (line == NULL || ret_lineaddr == 0) {
+ _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ *ret_lineaddr = (line->li_address);
+ return DW_DLV_OK;
+}
+
+
+/* Each 'line' entry has a column-within-line (offset
+ within the line) where the
+ source text begins.
+ If the entry is a DW_LNE_end_sequence the line-number is
+ meaningless (see dwarf_lineendsequence(), just above).
+ Lines of text begin at column 1. The value 0
+ means the line begins at the left edge of the line.
+ (See the DWARF3 spec, section 6.2.2).
+*/
+int
+dwarf_lineoff(Dwarf_Line line,
+ Dwarf_Signed * ret_lineoff, Dwarf_Error * error)
+{
+ if (line == NULL || ret_lineoff == 0) {
+ _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ *ret_lineoff =
+ (line->li_addr_line.li_l_data.li_column ==
+ 0 ? -1 : line->li_addr_line.li_l_data.li_column);
+ return DW_DLV_OK;
+}
+
+
+int
+dwarf_linesrc(Dwarf_Line line, char **ret_linesrc, Dwarf_Error * error)
+{
+ Dwarf_Signed i = 0;
+ Dwarf_File_Entry file_entry;
+ Dwarf_Small *name_buffer = 0;
+ Dwarf_Small *include_directories = 0;
+ Dwarf_Small include_direc_full_path = 0;
+ Dwarf_Small file_name_full_path = 0;
+ Dwarf_Debug dbg = 0;
+ unsigned int comp_dir_len = 0;
+
+ if (line == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ if (line->li_context == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_LINE_CONTEXT_NULL);
+ return (DW_DLV_ERROR);
+ }
+ dbg = line->li_context->lc_dbg;
+
+ if (line->li_addr_line.li_l_data.li_file >
+ line->li_context->lc_file_entry_count) {
+ _dwarf_error(dbg, error, DW_DLE_LINE_FILE_NUM_BAD);
+ return (DW_DLV_ERROR);
+ }
+
+ if (line->li_addr_line.li_l_data.li_file == 0) {
+ /* No file name known: see dwarf2/3 spec. */
+ _dwarf_error(dbg, error, DW_DLE_NO_FILE_NAME);
+ return (DW_DLV_ERROR);
+ }
+ file_entry = line->li_context->lc_file_entries;
+ /* ASSERT: li_file > 0, dwarf correctness issue, see line table
+ definition of dwarf2/3 spec. */
+ /* Example: if li_file is 2 and lc_file_entry_count is 3,
+ file_entry is file 3 (1 based), aka 2( 0 based) file_entry->next
+ is file 2 (1 based), aka 1( 0 based) file_entry->next->next is
+ file 1 (1 based), aka 0( 0 based) file_entry->next->next->next
+ is NULL.
+
+ and this loop finds the file_entry we need (2 (1 based) in this
+ case). Because lc_file_entries are in reverse order and
+ effectively zero based as a count whereas li_file is 1 based. */
+ for (i = line->li_addr_line.li_l_data.li_file - 1; i > 0; i--)
+ file_entry = file_entry->fi_next;
+
+ if (file_entry->fi_file_name == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_NO_FILE_NAME);
+ return (DW_DLV_ERROR);
+ }
+
+ file_name_full_path = file_name_is_full_path(file_entry->fi_file_name);
+ if (file_name_full_path) {
+ *ret_linesrc = ((char *) file_entry->fi_file_name);
+ return DW_DLV_OK;
+ }
+
+ if (file_entry->fi_dir_index == 0) {
+
+ /* dir_index of 0 means that the compilation was in the
+ 'current directory of compilation' */
+ if (line->li_context->lc_compilation_directory == NULL) {
+ /* we don't actually *have* a current directory of
+ compilation: DW_AT_comp_dir was not present Rather than
+ emitting DW_DLE_NO_COMP_DIR lets just make an empty name
+ here. In other words, do the best we can with what we do
+ have instead of reporting an error. _dwarf_error(dbg,
+ error, DW_DLE_NO_COMP_DIR); return(DW_DLV_ERROR); */
+ comp_dir_len = 0;
+ } else {
+ comp_dir_len = strlen((char *)
+ (line->li_context->
+ lc_compilation_directory));
+ }
+
+ name_buffer =
+ _dwarf_get_alloc(line->li_context->lc_dbg, DW_DLA_STRING,
+ comp_dir_len + 1 +
+ strlen((char *) file_entry->fi_file_name) +
+ 1);
+ if (name_buffer == NULL) {
+ _dwarf_error(line->li_context->lc_dbg, error,
+ DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ if (comp_dir_len > 0) {
+ /* if comp_dir_len is 0 we do not want to put a / in front
+ of the fi_file_name as we just don't know anything. */
+ strcpy((char *) name_buffer,
+ (char *) (line->li_context->
+ lc_compilation_directory));
+ strcat((char *) name_buffer, "/");
+ }
+ strcat((char *) name_buffer, (char *) file_entry->fi_file_name);
+ *ret_linesrc = ((char *) name_buffer);
+ return DW_DLV_OK;
+ }
+
+ if (file_entry->fi_dir_index >
+ line->li_context->lc_include_directories_count) {
+ _dwarf_error(dbg, error, DW_DLE_INCL_DIR_NUM_BAD);
+ return (DW_DLV_ERROR);
+ }
+
+ include_directories = line->li_context->lc_include_directories;
+ for (i = file_entry->fi_dir_index - 1; i > 0; i--)
+ include_directories += strlen((char *) include_directories) + 1;
+
+ if (line->li_context->lc_compilation_directory) {
+ comp_dir_len = strlen((char *)
+ (line->li_context->lc_compilation_directory));
+ } else {
+ /* No DW_AT_comp_dir present. Do the best we can without it. */
+ comp_dir_len = 0;
+ }
+
+ include_direc_full_path = file_name_is_full_path(include_directories);
+ name_buffer = _dwarf_get_alloc(dbg, DW_DLA_STRING,
+ (include_direc_full_path ? 0 : comp_dir_len + 1) +
+ strlen((char *)include_directories) + 1 +
+ strlen((char *)file_entry->fi_file_name) + 1);
+ if (name_buffer == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ if (!include_direc_full_path) {
+ if (comp_dir_len > 0) {
+ strcpy((char *)name_buffer,
+ (char *)line->li_context->lc_compilation_directory);
+ /* Who provides the / needed after the compilation
+ directory? */
+ if (!is_path_separator(name_buffer[comp_dir_len - 1])) {
+ /* Here we provide the / separator. It
+ should work ok for Windows */
+ /* Overwrite previous nul terminator with needed / */
+ name_buffer[comp_dir_len] = '/';
+ name_buffer[comp_dir_len + 1] = 0;
+ }
+ }
+ } else {
+ strcpy((char *) name_buffer, "");
+ }
+ strcat((char *) name_buffer, (char *) include_directories);
+ strcat((char *) name_buffer, "/");
+ strcat((char *) name_buffer, (char *) file_entry->fi_file_name);
+ *ret_linesrc = ((char *) name_buffer);
+ return DW_DLV_OK;
+}
+
+/* Every line table entry potentially has the basic-block-start
+ flag marked 'on'. This returns thru *return_bool,
+ the basic-block-start flag.
+*/
+int
+dwarf_lineblock(Dwarf_Line line,
+ Dwarf_Bool * return_bool, Dwarf_Error * error)
+{
+ if (line == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL);
+ return (DW_DLV_ERROR);
+ }
+ *return_bool = (line->li_addr_line.li_l_data.li_basic_block);
+ return DW_DLV_OK;
+}
+
+
+#if 0 /* Ignore this. This needs major
+ re-work. */
+/*
+ This routine works by looking for exact matches between
+ the current line address and pc, and crossovers from
+ from less than pc value to greater than. At each line
+ that satisfies the above, it records a pointer to the
+ line, and the difference between the address and pc.
+ It then scans these pointers and picks out those with
+ the smallest difference between pc and address.
+*/
+int
+dwarf_pclines(Dwarf_Debug dbg,
+ Dwarf_Addr pc,
+ Dwarf_Line ** linebuf,
+ Dwarf_Signed slide,
+ Dwarf_Signed * linecount, Dwarf_Error * error)
+{
+ /*
+ Scans the line matrix for the current cu to which a pointer
+ exists in dbg. */
+ Dwarf_Line line;
+ Dwarf_Line prev_line;
+
+ /*
+ These flags are for efficiency reasons. Check_line is true
+ initially, but set false when the address of the current line is
+ greater than pc. It is set true only when the address of the
+ current line falls below pc. This assumes that addresses within
+ the same segment increase, and we are only interested in the
+ switch from a less than pc address to a greater than. First_line
+ is set true initially, but set false after the first line is
+ scanned. This is to prevent looking at the address of previous
+ line when slide is DW_DLS_BACKWARD, and the first line is being
+ scanned. */
+ Dwarf_Bool check_line, first_line;
+
+ /*
+ Diff tracks the smallest difference a line address and the input
+ pc value. */
+ Dwarf_Signed diff, i;
+
+ /*
+ For the slide = DW_DLS_BACKWARD case, pc_less is the value of
+ the address of the line immediately preceding the first line
+ that has value greater than pc. For the slide = DW_DLS_FORWARD
+ case, pc_more is the values of address for the first line that
+ is greater than pc. Diff is the difference between either of the
+ these values and pc. */
+ Dwarf_Addr pc_less, pc_more;
+
+ /*
+ Pc_line_buf points to a chain of pointers to lines of which
+ those with a diff equal to the smallest difference will be
+ returned. */
+ Dwarf_Line *pc_line_buf, *pc_line;
+
+ /*
+ Chain_count counts the number of lines in the above chain for
+ which the diff is equal to the smallest difference This is the
+ number returned by this routine. */
+ Dwarf_Signed chain_count;
+
+ chain_head = NULL;
+
+ check_line = true;
+ first_line = true;
+ diff = MAX_LINE_DIFF;
+
+ for (i = 0; i < dbg->de_cu_line_count; i++) {
+
+ line = *(dbg->de_cu_line_ptr + i);
+ prev_line = first_line ? NULL : *(dbg->de_cu_line_ptr + i - 1);
+
+ if (line->li_address == pc) {
+ chain_ptr = (struct chain *)
+ _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
+ if (chain_ptr == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ chain_ptr->line = line;
+ chain_ptr->diff = diff = 0;
+ chain_ptr->next = chain_head;
+ chain_head = chain_ptr;
+ } else
+ /*
+ Look for crossover from less than pc address to greater
+ than. */
+ if (check_line && line->li_address > pc &&
+ (first_line ? 0 : prev_line->li_address) < pc)
+
+ if (slide == DW_DLS_BACKWARD && !first_line) {
+ pc_less = prev_line->li_address;
+ if (pc - pc_less <= diff) {
+ chain_ptr = (struct chain *)
+ _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
+ if (chain_ptr == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ chain_ptr->line = prev_line;
+ chain_ptr->diff = diff = pc - pc_less;
+ chain_ptr->next = chain_head;
+ chain_head = chain_ptr;
+ }
+ check_line = false;
+ } else if (slide == DW_DLS_FORWARD) {
+ pc_more = line->li_address;
+ if (pc_more - pc <= diff) {
+ chain_ptr = (struct chain *)
+ _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
+ if (chain_ptr == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ chain_ptr->line = line;
+ chain_ptr->diff = diff = pc_more - pc;
+ chain_ptr->next = chain_head;
+ chain_head = chain_ptr;
+ }
+ check_line = false;
+ } else
+ /* Check addresses only when they go */
+ /* below pc. */
+ if (line->li_address < pc)
+ check_line = true;
+
+ first_line = false;
+ }
+
+ chain_count = 0;
+ for (chain_ptr = chain_head; chain_ptr != NULL;
+ chain_ptr = chain_ptr->next)
+ if (chain_ptr->diff == diff)
+ chain_count++;
+
+ pc_line_buf = pc_line = (Dwarf_Line)
+ _dwarf_get_alloc(dbg, DW_DLA_LIST, chain_count);
+ for (chain_ptr = chain_head; chain_ptr != NULL;
+ chain_ptr = chain_ptr->next)
+ if (chain_ptr->diff == diff) {
+ *pc_line = chain_ptr->line;
+ pc_line++;
+ }
+
+ for (chain_ptr = chain_head; chain_ptr != NULL;) {
+ chain_head = chain_ptr;
+ chain_ptr = chain_ptr->next;
+ dwarf_dealloc(dbg, chain_head, DW_DLA_CHAIN);
+ }
+
+ *linebuf = pc_line_buf;
+ return (chain_count);
+}
+#endif
+
+
+
+/*
+ It's impossible for callers of dwarf_srclines() to get to and
+ free all the resources (in particular, the li_context and its
+ lc_file_entries).
+ So this function, new July 2005, does it.
+*/
+
+void
+dwarf_srclines_dealloc(Dwarf_Debug dbg, Dwarf_Line * linebuf,
+ Dwarf_Signed count)
+{
+
+ Dwarf_Signed i = 0;
+ struct Dwarf_Line_Context_s *context = 0;
+
+ if (count > 0) {
+ /* All these entries share a single context */
+ context = linebuf[0]->li_context;
+ }
+ for (i = 0; i < count; ++i) {
+ dwarf_dealloc(dbg, linebuf[i], DW_DLA_LINE);
+ }
+ dwarf_dealloc(dbg, linebuf, DW_DLA_LIST);
+
+ if (context) {
+ Dwarf_File_Entry fe = context->lc_file_entries;
+
+ while (fe) {
+ Dwarf_File_Entry fenext = fe->fi_next;
+
+ dwarf_dealloc(dbg, fe, DW_DLA_FILE_ENTRY);
+ fe = fenext;
+ }
+ dwarf_dealloc(dbg, context, DW_DLA_LINE_CONTEXT);
+ }
+
+ return;
+}
+
+/* Operand counts per standard operand.
+ The initial zero is for DW_LNS_copy.
+ This is an economical way to verify we understand the table
+ of standard-opcode-lengths in the line table prologue. */
+#define STANDARD_OPERAND_COUNT_DWARF2 9
+#define STANDARD_OPERAND_COUNT_DWARF3 12
+static unsigned char
+ dwarf_standard_opcode_operand_count[STANDARD_OPERAND_COUNT_DWARF3] = {
+ /* DWARF2 */
+ 0,
+ 1, 1, 1, 1,
+ 0, 0, 0,
+ 1,
+ /* Following are new for DWARF3. */
+ 0, 0, 1
+};
+
+/* We have a normal standard opcode base, but
+ an arm compiler emitted a non-standard table!
+ This could lead to problems...
+ ARM C/C++ Compiler, RVCT4.0 [Build 4
+ 00] seems to get the table wrong . */
+static unsigned char
+dwarf_arm_standard_opcode_operand_count[STANDARD_OPERAND_COUNT_DWARF3] = {
+ /* DWARF2 */
+ 0,
+ 1, 1, 1, 1,
+ 0, 0, 0,
+ 0, /* <<< --- this is wrong */
+ /* Following are new for DWARF3. */
+ 0, 0, 1
+};
+
+static void
+print_header_issue(Dwarf_Debug dbg,
+ char *specific_msg,
+ Dwarf_Small *data_start,
+ int *err_count_out)
+{
+ if(!err_count_out)
+ return;
+ printf("*** DWARF CHECK: "
+ "line table header: %s",
+ specific_msg);
+ if( data_start >= dbg->de_debug_line.dss_data &&
+ (data_start < (dbg->de_debug_line.dss_data +
+ dbg->de_debug_line.dss_size))) {
+ Dwarf_Unsigned off = data_start - dbg->de_debug_line.dss_data;
+ printf(" at .debug_line section offset 0x%" DW_PR_DUx
+ " ( %" DW_PR_DUu " ) ",
+ off,off);
+ } else {
+ printf(" (unknown section location) ");
+ }
+ printf("***\n");
+ *err_count_out += 1;
+}
+
+
+
+/* Common line table prefix reading code.
+ Returns DW_DLV_OK, DW_DLV_ERROR.
+ DW_DLV_NO_ENTRY cannot be returned, but callers should
+ assume it is possible.
+
+ The prefix_out area must be initialized properly before calling this.
+
+ Has the side effect of allocating arrays which
+ must be freed (see the Line_Table_Prefix_s struct which
+ holds the pointers to space we allocate here).
+
+ bogus_bytes_ptr and bogus_bytes are output values which
+ let a print-program notify the user of some surprising bytes
+ after a line table header and before the line table instructions.
+ These can be ignored unless one is printing.
+ And are ignored if NULL passed as the pointer.
+*/
+
+/* err_count_out may be NULL, in which case we
+ make no attempt to count checking-type errors.
+ Checking-type errors do not stop us, we just report them.
+*/
+int
+dwarf_read_line_table_prefix(Dwarf_Debug dbg,
+ Dwarf_Small * data_start,
+ Dwarf_Unsigned data_length,
+ Dwarf_Small ** updated_data_start_out,
+ struct Line_Table_Prefix_s *prefix_out,
+ Dwarf_Small ** bogus_bytes_ptr,
+ Dwarf_Unsigned *bogus_bytes,
+ Dwarf_Error * err,
+ int *err_count_out)
+{
+ Dwarf_Small *line_ptr = data_start;
+ Dwarf_Unsigned total_length = 0;
+ int local_length_size = 0;
+ int local_extension_size = 0;
+ Dwarf_Unsigned prologue_length = 0;
+ Dwarf_Half version = 0;
+ Dwarf_Unsigned directories_count = 0;
+ Dwarf_Unsigned directories_malloc = 0;
+ Dwarf_Unsigned files_count = 0;
+ Dwarf_Unsigned files_malloc = 0;
+ Dwarf_Small *line_ptr_end = 0;
+ Dwarf_Small *lp_begin = 0;
+ if(bogus_bytes_ptr) *bogus_bytes_ptr = 0;
+ if(bogus_bytes) *bogus_bytes= 0;
+
+ prefix_out->pf_line_ptr_start = line_ptr;
+ /* READ_AREA_LENGTH updates line_ptr for consumed bytes */
+ READ_AREA_LENGTH(dbg, total_length, Dwarf_Unsigned,
+ line_ptr, local_length_size, local_extension_size);
+
+
+ line_ptr_end = line_ptr + total_length;
+ prefix_out->pf_line_ptr_end = line_ptr_end;
+ prefix_out->pf_length_field_length = local_length_size +
+ local_extension_size;
+ /* ASSERT: prefix_out->pf_length_field_length == line_ptr
+ -prefix_out->pf_line_ptr_start; */
+ if (line_ptr_end > dbg->de_debug_line.dss_data +
+ dbg->de_debug_line.dss_size) {
+ _dwarf_error(dbg, err, DW_DLE_DEBUG_LINE_LENGTH_BAD);
+ return (DW_DLV_ERROR);
+ }
+ if (line_ptr_end > data_start + data_length) {
+ _dwarf_error(dbg, err, DW_DLE_DEBUG_LINE_LENGTH_BAD);
+ return (DW_DLV_ERROR);
+ }
+ prefix_out->pf_total_length = total_length;
+
+ READ_UNALIGNED(dbg, version, Dwarf_Half,
+ line_ptr, sizeof(Dwarf_Half));
+ prefix_out->pf_version = version;
+ line_ptr += sizeof(Dwarf_Half);
+ if (version != CURRENT_VERSION_STAMP &&
+ version != CURRENT_VERSION_STAMP3) {
+ _dwarf_error(dbg, err, DW_DLE_VERSION_STAMP_ERROR);
+ return (DW_DLV_ERROR);
+ }
+
+ READ_UNALIGNED(dbg, prologue_length, Dwarf_Unsigned,
+ line_ptr, local_length_size);
+ prefix_out->pf_prologue_length = prologue_length;
+ line_ptr += local_length_size;
+ prefix_out->pf_line_prologue_start = line_ptr;
+
+ prefix_out->pf_minimum_instruction_length =
+ *(unsigned char *) line_ptr;
+ line_ptr = line_ptr + sizeof(Dwarf_Small);
+
+ prefix_out->pf_default_is_stmt = *(unsigned char *) line_ptr;
+ line_ptr = line_ptr + sizeof(Dwarf_Small);
+
+ prefix_out->pf_line_base = *(signed char *) line_ptr;
+ line_ptr = line_ptr + sizeof(Dwarf_Sbyte);
+
+ prefix_out->pf_line_range = *(unsigned char *) line_ptr;
+ line_ptr = line_ptr + sizeof(Dwarf_Small);
+
+ prefix_out->pf_opcode_base = *(unsigned char *) line_ptr;
+ line_ptr = line_ptr + sizeof(Dwarf_Small);
+
+ /* Set up the array of standard opcode lengths. */
+ /* We think this works ok even for cross-endian processing of
+ objects. It might be wrong, we might need to specially process
+ the array of ubyte into host order. */
+ prefix_out->pf_opcode_length_table = line_ptr;
+
+ /* pf_opcode_base is one greater than the size of the array. */
+ line_ptr += prefix_out->pf_opcode_base - 1;
+
+ {
+ /* Determine (as best we can) whether the
+ pf_opcode_length_table holds 9 or 12 standard-conforming
+ entries. gcc4 upped to DWARF3's 12 without updating the
+ version number. */
+ int operand_ck_fail = true;
+
+ if (prefix_out->pf_opcode_base >= STANDARD_OPERAND_COUNT_DWARF3) {
+ int mismatch = memcmp(dwarf_standard_opcode_operand_count,
+ prefix_out->pf_opcode_length_table,
+ STANDARD_OPERAND_COUNT_DWARF3);
+ if(mismatch) {
+ if(err_count_out) {
+ print_header_issue(dbg,"standard-operands did not match",
+ data_start,err_count_out);
+ }
+ mismatch = memcmp(dwarf_arm_standard_opcode_operand_count,
+ prefix_out->pf_opcode_length_table,
+ STANDARD_OPERAND_COUNT_DWARF3);
+ if(!mismatch && err_count_out) {
+ print_header_issue(dbg,"arm (incorrect) operands in use",
+ data_start,err_count_out);
+ }
+ }
+ if (!mismatch) {
+ if (version == 2) {
+ if(err_count_out) {
+ print_header_issue(dbg,
+ "standard DWARF3 operands matched, but is DWARF2 linetable",
+ data_start,err_count_out);
+ }
+ }
+ operand_ck_fail = false;
+ prefix_out->pf_std_op_count =
+ STANDARD_OPERAND_COUNT_DWARF3;
+ }
+ }
+ if (operand_ck_fail) {
+ if (prefix_out->pf_opcode_base >=
+ STANDARD_OPERAND_COUNT_DWARF2) {
+
+ int mismatch =
+ memcmp(dwarf_standard_opcode_operand_count,
+ prefix_out->pf_opcode_length_table,
+ STANDARD_OPERAND_COUNT_DWARF2);
+ if(mismatch) {
+ if(err_count_out) {
+ print_header_issue(dbg,"standard-operands-lengths did not match",
+ data_start,err_count_out);
+ }
+ mismatch = memcmp(dwarf_arm_standard_opcode_operand_count,
+ prefix_out->pf_opcode_length_table,
+ STANDARD_OPERAND_COUNT_DWARF2);
+ if(!mismatch && err_count_out) {
+ print_header_issue(dbg,"arm (incorrect) operand in use",
+ data_start,err_count_out);
+ }
+ }
+
+ if (!mismatch) {
+ operand_ck_fail = false;
+ prefix_out->pf_std_op_count =
+ STANDARD_OPERAND_COUNT_DWARF2;
+ }
+ }
+ }
+ if (operand_ck_fail) {
+ /* Here we are not sure what the pf_std_op_count is. */
+ _dwarf_error(dbg, err, DW_DLE_LINE_NUM_OPERANDS_BAD);
+ return (DW_DLV_ERROR);
+ }
+ }
+ /* At this point we no longer need to check operand counts. */
+
+
+ directories_count = 0;
+ directories_malloc = 5;
+ prefix_out->pf_include_directories = malloc(sizeof(Dwarf_Small *) *
+ directories_malloc);
+ if (prefix_out->pf_include_directories == NULL) {
+ _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ memset(prefix_out->pf_include_directories, 0,
+ sizeof(Dwarf_Small *) * directories_malloc);
+
+ while ((*(char *) line_ptr) != '\0') {
+ if (directories_count >= directories_malloc) {
+ Dwarf_Unsigned expand = 2 * directories_malloc;
+ Dwarf_Unsigned bytesalloc = sizeof(Dwarf_Small *) * expand;
+ Dwarf_Small **newdirs =
+ realloc(prefix_out->pf_include_directories,
+ bytesalloc);
+
+ if (!newdirs) {
+ _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ /* Doubled size, zero out second half. */
+ memset(newdirs + directories_malloc, 0,
+ sizeof(Dwarf_Small *) * directories_malloc);
+ directories_malloc = expand;
+ prefix_out->pf_include_directories = newdirs;
+ }
+ prefix_out->pf_include_directories[directories_count] =
+ line_ptr;
+ line_ptr = line_ptr + strlen((char *) line_ptr) + 1;
+ directories_count++;
+ }
+ prefix_out->pf_include_directories_count = directories_count;
+ line_ptr++;
+
+ files_count = 0;
+ files_malloc = 5;
+ prefix_out->pf_line_table_file_entries =
+ malloc(sizeof(struct Line_Table_File_Entry_s) * files_malloc);
+ if (prefix_out->pf_line_table_file_entries == NULL) {
+ _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ memset(prefix_out->pf_line_table_file_entries, 0,
+ sizeof(struct Line_Table_File_Entry_s) * files_malloc);
+
+ while (*(char *) line_ptr != '\0') {
+ Dwarf_Unsigned utmp;
+ Dwarf_Unsigned dir_index = 0;
+ Dwarf_Unsigned lastmod = 0;
+ Dwarf_Unsigned file_length = 0;
+ struct Line_Table_File_Entry_s *curline;
+ Dwarf_Word leb128_length = 0;
+
+
+ if (files_count >= files_malloc) {
+ Dwarf_Unsigned expand = 2 * files_malloc;
+ struct Line_Table_File_Entry_s *newfiles =
+ realloc(prefix_out->pf_line_table_file_entries,
+ sizeof(struct Line_Table_File_Entry_s) *
+ expand);
+ if (!newfiles) {
+ _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ memset(newfiles + files_malloc, 0,
+ sizeof(struct Line_Table_File_Entry_s) *
+ files_malloc);
+ files_malloc = expand;
+ prefix_out->pf_line_table_file_entries = newfiles;
+ }
+ curline = prefix_out->pf_line_table_file_entries + files_count;
+
+ curline->lte_filename = line_ptr;
+ line_ptr = line_ptr + strlen((char *) line_ptr) + 1;
+
+ DECODE_LEB128_UWORD(line_ptr, utmp);
+ dir_index = (Dwarf_Sword) utmp;
+ if (dir_index > directories_count) {
+ _dwarf_error(dbg, err, DW_DLE_DIR_INDEX_BAD);
+ return (DW_DLV_ERROR);
+ }
+ curline->lte_directory_index = dir_index;
+
+ lastmod = _dwarf_decode_u_leb128(line_ptr, &leb128_length);
+ line_ptr = line_ptr + leb128_length;
+ curline->lte_last_modification_time = lastmod;
+
+ /* Skip over file length. */
+ file_length = _dwarf_decode_u_leb128(line_ptr, &leb128_length);
+ line_ptr = line_ptr + leb128_length;
+ curline->lte_length_of_file = file_length;
+
+ ++files_count;
+
+ }
+ prefix_out->pf_files_count = files_count;
+ /* Skip trailing nul byte */
+ ++line_ptr;
+
+
+ lp_begin = prefix_out->pf_line_prologue_start +
+ prefix_out->pf_prologue_length;
+ if (line_ptr != lp_begin) {
+ if(line_ptr > lp_begin) {
+ _dwarf_error(dbg, err, DW_DLE_LINE_PROLOG_LENGTH_BAD);
+ return (DW_DLV_ERROR);
+ } else {
+ /* Bug in compiler. These
+ * bytes are really part of the instruction
+ * stream. The prefix_out->pf_prologue_length is
+ * wrong (12 too high). */
+ if(bogus_bytes_ptr) {
+ *bogus_bytes_ptr = line_ptr;
+ }
+ if(bogus_bytes) {
+ /* How far off things are. We expect the
+ value 12 ! */
+ *bogus_bytes = (lp_begin - line_ptr);
+ }
+ }
+ /* Ignore the lp_begin calc. Assume line_ptr right.
+ Making up for compiler bug. */
+ lp_begin = line_ptr;
+
+ }
+
+ *updated_data_start_out = lp_begin;
+ return DW_DLV_OK;
+}
+
+
+/* Initialize the Line_Table_Prefix_s struct.
+ memset is not guaranteed a portable initializer, but works
+ fine for current architectures. AFAIK.
+*/
+void
+dwarf_init_line_table_prefix(struct Line_Table_Prefix_s *pf)
+{
+ memset(pf, 0, sizeof(*pf));
+}
+
+/* Free any malloc'd area. of the Line_Table_Prefix_s struct. */
+void
+dwarf_free_line_table_prefix(struct Line_Table_Prefix_s *pf)
+{
+ if (pf->pf_include_directories) {
+ free(pf->pf_include_directories);
+ pf->pf_include_directories = 0;
+ }
+ if (pf->pf_line_table_file_entries) {
+ free(pf->pf_line_table_file_entries);
+ pf->pf_line_table_file_entries = 0;
+ }
+ return;
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_line.h b/usr/src/lib/libdwarf/common/dwarf_line.h
new file mode 100644
index 0000000000..66d6062754
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_line.h
@@ -0,0 +1,331 @@
+/*
+
+ Copyright (C) 2000, 2004, 2006 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2009-2010 David Anderson. 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
+
+*/
+
+
+
+#define DW_EXTENDED_OPCODE 0
+
+/*
+ This is used as the starting value for an algorithm
+ to get the minimum difference between 2 values.
+ UINT_MAX is used as our approximation to infinity.
+*/
+#define MAX_LINE_DIFF UINT_MAX
+
+/* This is for a sanity check on line
+ table extended opcodes.
+ It is entirely arbitrary, and 100 is surely too small if
+ someone was inserting strings in the opcode. */
+#define DW_LNE_LEN_MAX 100
+
+
+/*
+ This structure is used to build a list of all the
+ files that are used in the current compilation unit.
+ All of the fields execpt fi_next have meanings that
+ are obvious from section 6.2.4 of the Libdwarf Doc.
+*/
+struct Dwarf_File_Entry_s {
+ /* Points to string naming the file. */
+ Dwarf_Small *fi_file_name;
+
+ /*
+ Index into the list of directories of the directory in which
+ this file exits. */
+ Dwarf_Sword fi_dir_index;
+
+ /* Time of last modification of the file. */
+ Dwarf_Unsigned fi_time_last_mod;
+
+ /* Length in bytes of the file. */
+ Dwarf_Unsigned fi_file_length;
+
+ /* Pointer for chaining file entries. */
+ Dwarf_File_Entry fi_next;
+};
+
+
+typedef struct Dwarf_Line_Context_s *Dwarf_Line_Context;
+
+/*
+ This structure provides the context in which the fields of
+ a Dwarf_Line structure are interpreted. They come from the
+ statement program prologue. **Updated by dwarf_srclines in
+ dwarf_line.c.
+*/
+struct Dwarf_Line_Context_s {
+ /*
+ Points to a chain of entries providing info about source files
+ for the current set of Dwarf_Line structures. File number
+ 'li_file 1' is last on the list, the first list entry is the
+ file numbered lc_file_entry_count. The numbering of the file
+ names matches the dwarf2/3 line table specification file table
+ and DW_LNE_define_file numbering rules. */
+ Dwarf_File_Entry lc_file_entries;
+ /*
+ Count of number of source files for this set of Dwarf_Line
+ structures. */
+ Dwarf_Sword lc_file_entry_count;
+ /*
+ Points to the portion of .debug_line section that contains a
+ list of strings naming the included directories. */
+ Dwarf_Small *lc_include_directories;
+
+ /* Count of the number of included directories. */
+ Dwarf_Sword lc_include_directories_count;
+
+ /* Count of the number of lines for this cu. */
+ Dwarf_Sword lc_line_count;
+
+ /* Points to name of compilation directory. */
+ Dwarf_Small *lc_compilation_directory;
+
+ Dwarf_Debug lc_dbg;
+
+ Dwarf_Half lc_version_number; /* DWARF2/3 version number, 2
+ for DWARF2, 3 for DWARF3. */
+};
+
+
+/*
+ This structure defines a row of the line table.
+ All of the fields except li_offset have the exact
+ same meaning that is defined in Section 6.2.2
+ of the Libdwarf Document.
+
+ li_offset is used by _dwarf_addr_finder() which is called
+ by rqs(1), an sgi utility for 'moving' shared libraries
+ as if the static linker (ld) had linked the shared library
+ at the newly-specified address. Most libdwarf-using
+ apps will ignore li_offset and _dwarf_addr_finder().
+
+*/
+struct Dwarf_Line_s {
+ Dwarf_Addr li_address; /* pc value of machine instr */
+ union addr_or_line_s {
+ struct li_inner_s {
+ Dwarf_Sword li_file; /* int identifying src file */
+ /* li_file is a number 1-N, indexing into a conceptual
+ source file table as described in dwarf2/3 spec line
+ table doc. (see Dwarf_File_Entry lc_file_entries; and
+ Dwarf_Sword lc_file_entry_count;) */
+
+ Dwarf_Sword li_line; /* source file line number. */
+ Dwarf_Half li_column; /* source file column number */
+ Dwarf_Small li_isa;
+
+ /* To save space, use bit flags. */
+ /* indicate start of stmt */
+ unsigned char li_is_stmt:1;
+
+ /* indicate start basic block */
+ unsigned char li_basic_block:1;
+
+ /* first post sequence instr */
+ unsigned char li_end_sequence:1;
+
+ unsigned char li_prologue_end:1;
+ unsigned char li_epilogue_begin:1;
+ } li_l_data;
+ Dwarf_Off li_offset; /* for rqs */
+ } li_addr_line;
+ Dwarf_Line_Context li_context; /* assoc Dwarf_Line_Context_s */
+};
+
+
+int _dwarf_line_address_offsets(Dwarf_Debug dbg,
+ Dwarf_Die die,
+ Dwarf_Addr ** addrs,
+ Dwarf_Off ** offs,
+ Dwarf_Unsigned * returncount,
+ Dwarf_Error * err);
+int _dwarf_internal_srclines(Dwarf_Die die,
+ Dwarf_Line ** linebuf,
+ Dwarf_Signed * count,
+ Dwarf_Bool doaddrs,
+ Dwarf_Bool dolines, Dwarf_Error * error);
+
+
+
+/* The LOP, WHAT_IS_OPCODE stuff is here so it can
+ be reused in 3 places. Seemed hard to keep
+ the 3 places the same without an inline func or
+ a macro.
+
+ Handling the line section where the header and the
+ file being processed do not match (unusual, but
+ planned for in the design of .debug_line)
+ is too tricky to recode this several times and keep
+ it right.
+
+ As it is the code starting up line-reading is duplicated
+ and that is just wrong to do. FIXME!
+*/
+#define LOP_EXTENDED 1
+#define LOP_DISCARD 2
+#define LOP_STANDARD 3
+#define LOP_SPECIAL 4
+
+#define WHAT_IS_OPCODE(type,opcode,base,opcode_length,line_ptr,highest_std) \
+ if( (opcode) < (base) ) { \
+ /* we know we must treat as a standard op \
+ or a special case. \
+ */ \
+ if((opcode) == DW_EXTENDED_OPCODE) { \
+ type = LOP_EXTENDED; \
+ } else if( ((highest_std)+1) >= (base)) { \
+ /* == Standard case: compile of \
+ dwarf_line.c and object \
+ have same standard op codes set. \
+ \
+ > Special case: compile of dwarf_line.c\
+ has things in standard op codes list \
+ in dwarf.h header not \
+ in the object: handle this as a standard\
+ op code in switch below. \
+ The header special ops overlap the \
+ object standard ops. \
+ The new standard op codes will not \
+ appear in the object. \
+ */ \
+ type = LOP_STANDARD; \
+ } else { \
+ /* These are standard opcodes in the object\
+ ** that were not defined in the header \
+ ** at the time dwarf_line.c \
+ ** was compiled. Provides the ability of \
+ ** out-of-date dwarf reader to read newer \
+ ** line table data transparently. \
+ */ \
+ type = LOP_DISCARD; \
+ } \
+ \
+ } else { \
+ /* Is a special op code. \
+ */ \
+ type = LOP_SPECIAL; \
+ }
+
+/* The following is from the dwarf definition of 'ubyte'
+ and is specifically mentioned in section 6.2.5.1, page 54
+ of the Rev 2.0.0 dwarf specification.
+*/
+
+#define MAX_LINE_OP_CODE 255
+
+
+/* The following structs (Line_Table_File_Entry_s,Line_Table_Prefix_s)
+ and functions allow refactoring common code into a single
+ reader routine.
+*/
+/* There can be zero of more of these needed for 1 line prologue. */
+struct Line_Table_File_Entry_s {
+ Dwarf_Small *lte_filename;
+ Dwarf_Unsigned lte_directory_index;
+ Dwarf_Unsigned lte_last_modification_time;
+ Dwarf_Unsigned lte_length_of_file;
+};
+
+/* Data picked up from the line table prologue for a single
+CU. */
+struct Line_Table_Prefix_s {
+
+ /* pf_total_length is the value of the length field for the line
+ table of this CU. So it does not count the length of itself (the
+ length value) for consistency with the say lenghts recorded in
+ DWARF2/3. */
+ Dwarf_Unsigned pf_total_length;
+
+ /* Length of the initial length field itself. */
+ Dwarf_Half pf_length_field_length;
+
+ /* The version is 2 for DWARF2, 3 for DWARF3 */
+ Dwarf_Half pf_version;
+
+ Dwarf_Unsigned pf_prologue_length;
+ Dwarf_Small pf_minimum_instruction_length;
+
+ /* Start and end of this CU line area. pf_line_ptr_start +
+ pf_total_length + pf_length_field_length == pf_line_ptr_end.
+ Meaning pf_line_ptr_start is before the length info. */
+ Dwarf_Small *pf_line_ptr_start;
+ Dwarf_Small *pf_line_ptr_end;
+
+ /* Used to check that decoding of the line prologue is done right. */
+ Dwarf_Small *pf_line_prologue_start;
+
+ Dwarf_Small pf_default_is_stmt;
+ Dwarf_Sbyte pf_line_base;
+ Dwarf_Small pf_line_range;
+
+ /* Highest std opcode (+1). */
+ Dwarf_Small pf_opcode_base;
+
+ /* pf_opcode_base -1 entries (each a count, normally the value of
+ each entry is 0 or 1). */
+ Dwarf_Small *pf_opcode_length_table;
+
+ Dwarf_Unsigned pf_include_directories_count;
+ /* Array of pointers to dir strings. pf_include_directories_count
+ entriesin the array. */
+ Dwarf_Small **pf_include_directories;
+
+ /* Count of entries in line_table_file_entries array. */
+ Dwarf_Unsigned pf_files_count;
+ struct Line_Table_File_Entry_s *pf_line_table_file_entries;
+
+ /* The number to treat as standard ops. This is a special
+ accomodation of gcc using the new standard opcodes but not
+ updating the version number. It's legal dwarf2, but much better
+ for the user to understand as dwarf3 when 'it looks ok'. */
+ Dwarf_Bool pf_std_op_count;
+
+};
+
+void dwarf_init_line_table_prefix(struct Line_Table_Prefix_s *pf);
+void dwarf_free_line_table_prefix(struct Line_Table_Prefix_s *pf);
+
+int dwarf_read_line_table_prefix(Dwarf_Debug dbg,
+ Dwarf_Small * data_start,
+ Dwarf_Unsigned data_length,
+ Dwarf_Small ** updated_data_start_out,
+ struct Line_Table_Prefix_s *prefix_out,
+ /* The following 2 arguments are solely for warning users
+ * when there is a surprising 'gap' in the .debug_line info. */
+ Dwarf_Small ** bogus_bytes_ptr,
+ Dwarf_Unsigned * bogus_bytes_count,
+ Dwarf_Error * err,
+ int * err_count_out);
diff --git a/usr/src/lib/libdwarf/common/dwarf_line2.c b/usr/src/lib/libdwarf/common/dwarf_line2.c
new file mode 100644
index 0000000000..634b848167
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_line2.c
@@ -0,0 +1,110 @@
+/*
+
+ Copyright (C) 2000,2002,2004,2005,2006 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright 2008-2010 David Anderson, 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 source file used for SGI-IRIX rqs processing.
+ Unused otherwise.
+*/
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+#include "dwarf_line.h"
+
+/*
+ Return DW_DLV_OK or, if error,
+ DW_DLV_ERROR.
+
+ Thru pointers, return 2 arrays and a count
+ for rqs.
+*/
+int
+_dwarf_line_address_offsets(Dwarf_Debug dbg,
+ Dwarf_Die die,
+ Dwarf_Addr ** addrs,
+ Dwarf_Off ** offs,
+ Dwarf_Unsigned * returncount,
+ Dwarf_Error * err)
+{
+ Dwarf_Addr *laddrs;
+ Dwarf_Off *loffsets;
+ Dwarf_Signed lcount;
+ Dwarf_Signed i;
+ int res;
+ Dwarf_Line *linebuf;
+
+ res = _dwarf_internal_srclines(die, &linebuf, &lcount, /* addrlist=
+ */ true,
+ /* linelist= */ false, err);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ laddrs = (Dwarf_Addr *)
+ _dwarf_get_alloc(dbg, DW_DLA_ADDR, lcount);
+ if (laddrs == NULL) {
+ dwarf_srclines_dealloc(dbg, linebuf, lcount);
+ _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ loffsets = (Dwarf_Off *)
+ _dwarf_get_alloc(dbg, DW_DLA_ADDR, lcount);
+ if (loffsets == NULL) {
+ dwarf_srclines_dealloc(dbg, linebuf, lcount);
+ /* We already allocated what laddrs points at, so we'e better
+ deallocate that space since we are not going to return the
+ pointer to the caller. */
+ dwarf_dealloc(dbg, laddrs, DW_DLA_ADDR);
+ _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ for (i = 0; i < lcount; i++) {
+ laddrs[i] = linebuf[i]->li_address;
+ loffsets[i] = linebuf[i]->li_addr_line.li_offset;
+ }
+ dwarf_srclines_dealloc(dbg, linebuf, lcount);
+ *returncount = lcount;
+ *offs = loffsets;
+ *addrs = laddrs;
+ return DW_DLV_OK;
+}
+
+/*
+ It's impossible for callers of dwarf_srclines() to get to and
+ free all the resources (in particular, the li_context and its
+ lc_file_entries).
+ So this function, new July 2005, does it.
+*/
diff --git a/usr/src/lib/libdwarf/common/dwarf_loc.c b/usr/src/lib/libdwarf/common/dwarf_loc.c
new file mode 100644
index 0000000000..f28b27b630
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_loc.c
@@ -0,0 +1,1073 @@
+/*
+
+ Copyright (C) 2000-2004 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2007-2010 David Anderson. 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
+
+*/
+/* The address of the Free Software Foundation is
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ SGI has moved from the Crittenden Lane address.
+*/
+
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include "dwarf_loc.h"
+#include <stdio.h> /* for debugging only. */
+#include <sys/types.h>
+
+/*
+ Given a Dwarf_Block that represents a location expression,
+ this function returns a pointer to a Dwarf_Locdesc struct
+ that has its ld_cents field set to the number of location
+ operators in the block, and its ld_s field pointing to a
+ contiguous block of Dwarf_Loc structs. However, the
+ ld_lopc and ld_hipc values are uninitialized. Returns
+ NULL on error. This function assumes that the length of
+ the block is greater than 0. Zero length location expressions
+ to represent variables that have been optimized away are
+ handled in the calling function.
+*/
+static Dwarf_Locdesc *
+_dwarf_get_locdesc(Dwarf_Debug dbg,
+ Dwarf_Block * loc_block,
+ Dwarf_Half address_size,
+ Dwarf_Addr lowpc,
+ Dwarf_Addr highpc,
+ Dwarf_Error * error)
+{
+ /* Size of the block containing the location expression. */
+ Dwarf_Unsigned loc_len = 0;
+
+ /* Sweeps the block containing the location expression. */
+ Dwarf_Small *loc_ptr = 0;
+
+ /* Current location operator. */
+ Dwarf_Small atom = 0;
+
+ /* Offset of current operator from start of block. */
+ Dwarf_Unsigned offset = 0;
+
+ /* Operands of current location operator. */
+ Dwarf_Unsigned operand1, operand2;
+
+ /* Used to chain the Dwarf_Loc_Chain_s structs. */
+ Dwarf_Loc_Chain curr_loc = NULL;
+ Dwarf_Loc_Chain prev_loc = NULL;
+ Dwarf_Loc_Chain head_loc = NULL;
+
+ /* Count of the number of location operators. */
+ Dwarf_Unsigned op_count = 0;
+
+ /* Contiguous block of Dwarf_Loc's for Dwarf_Locdesc. */
+ Dwarf_Loc *block_loc = 0;
+
+ /* Dwarf_Locdesc pointer to be returned. */
+ Dwarf_Locdesc *locdesc = 0;
+
+ Dwarf_Word leb128_length = 0;
+ Dwarf_Unsigned i = 0;
+
+ /* ***** BEGIN CODE ***** */
+
+ loc_len = loc_block->bl_len;
+ loc_ptr = loc_block->bl_data;
+
+ offset = 0;
+ op_count = 0;
+ while (offset < loc_len) {
+
+ operand1 = 0;
+ operand2 = 0;
+ op_count++;
+
+ atom = *(Dwarf_Small *) loc_ptr;
+ loc_ptr++;
+ offset++;
+
+ curr_loc =
+ (Dwarf_Loc_Chain) _dwarf_get_alloc(dbg, DW_DLA_LOC_CHAIN,
+ 1);
+ if (curr_loc == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (NULL);
+ }
+ curr_loc->lc_offset = offset;
+ curr_loc->lc_atom = atom;
+ switch (atom) {
+
+ case DW_OP_reg0:
+ case DW_OP_reg1:
+ case DW_OP_reg2:
+ case DW_OP_reg3:
+ case DW_OP_reg4:
+ case DW_OP_reg5:
+ case DW_OP_reg6:
+ case DW_OP_reg7:
+ case DW_OP_reg8:
+ case DW_OP_reg9:
+ case DW_OP_reg10:
+ case DW_OP_reg11:
+ case DW_OP_reg12:
+ case DW_OP_reg13:
+ case DW_OP_reg14:
+ case DW_OP_reg15:
+ case DW_OP_reg16:
+ case DW_OP_reg17:
+ case DW_OP_reg18:
+ case DW_OP_reg19:
+ case DW_OP_reg20:
+ case DW_OP_reg21:
+ case DW_OP_reg22:
+ case DW_OP_reg23:
+ case DW_OP_reg24:
+ case DW_OP_reg25:
+ case DW_OP_reg26:
+ case DW_OP_reg27:
+ case DW_OP_reg28:
+ case DW_OP_reg29:
+ case DW_OP_reg30:
+ case DW_OP_reg31:
+ break;
+
+ case DW_OP_regx:
+ operand1 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length);
+ loc_ptr = loc_ptr + leb128_length;
+ offset = offset + leb128_length;
+ break;
+
+ case DW_OP_lit0:
+ case DW_OP_lit1:
+ case DW_OP_lit2:
+ case DW_OP_lit3:
+ case DW_OP_lit4:
+ case DW_OP_lit5:
+ case DW_OP_lit6:
+ case DW_OP_lit7:
+ case DW_OP_lit8:
+ case DW_OP_lit9:
+ case DW_OP_lit10:
+ case DW_OP_lit11:
+ case DW_OP_lit12:
+ case DW_OP_lit13:
+ case DW_OP_lit14:
+ case DW_OP_lit15:
+ case DW_OP_lit16:
+ case DW_OP_lit17:
+ case DW_OP_lit18:
+ case DW_OP_lit19:
+ case DW_OP_lit20:
+ case DW_OP_lit21:
+ case DW_OP_lit22:
+ case DW_OP_lit23:
+ case DW_OP_lit24:
+ case DW_OP_lit25:
+ case DW_OP_lit26:
+ case DW_OP_lit27:
+ case DW_OP_lit28:
+ case DW_OP_lit29:
+ case DW_OP_lit30:
+ case DW_OP_lit31:
+ operand1 = atom - DW_OP_lit0;
+ break;
+
+ case DW_OP_addr:
+ READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned,
+ loc_ptr, address_size);
+ loc_ptr += address_size;
+ offset += address_size;
+ break;
+
+ case DW_OP_const1u:
+ operand1 = *(Dwarf_Small *) loc_ptr;
+ loc_ptr = loc_ptr + 1;
+ offset = offset + 1;
+ break;
+
+ case DW_OP_const1s:
+ operand1 = *(Dwarf_Sbyte *) loc_ptr;
+ SIGN_EXTEND(operand1,1);
+ loc_ptr = loc_ptr + 1;
+ offset = offset + 1;
+ break;
+
+ case DW_OP_const2u:
+ READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 2);
+ loc_ptr = loc_ptr + 2;
+ offset = offset + 2;
+ break;
+
+ case DW_OP_const2s:
+ READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 2);
+ SIGN_EXTEND(operand1,2);
+ loc_ptr = loc_ptr + 2;
+ offset = offset + 2;
+ break;
+
+ case DW_OP_const4u:
+ READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 4);
+ loc_ptr = loc_ptr + 4;
+ offset = offset + 4;
+ break;
+
+ case DW_OP_const4s:
+ READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 4);
+ SIGN_EXTEND(operand1,4);
+ loc_ptr = loc_ptr + 4;
+ offset = offset + 4;
+ break;
+
+ case DW_OP_const8u:
+ READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 8);
+ loc_ptr = loc_ptr + 8;
+ offset = offset + 8;
+ break;
+
+ case DW_OP_const8s:
+ READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 8);
+ loc_ptr = loc_ptr + 8;
+ offset = offset + 8;
+ break;
+
+ case DW_OP_constu:
+ operand1 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length);
+ loc_ptr = loc_ptr + leb128_length;
+ offset = offset + leb128_length;
+ break;
+
+ case DW_OP_consts:
+ operand1 = _dwarf_decode_s_leb128(loc_ptr, &leb128_length);
+ loc_ptr = loc_ptr + leb128_length;
+ offset = offset + leb128_length;
+ break;
+
+ case DW_OP_fbreg:
+ operand1 = _dwarf_decode_s_leb128(loc_ptr, &leb128_length);
+ loc_ptr = loc_ptr + leb128_length;
+ offset = offset + leb128_length;
+ break;
+
+ case DW_OP_breg0:
+ case DW_OP_breg1:
+ case DW_OP_breg2:
+ case DW_OP_breg3:
+ case DW_OP_breg4:
+ case DW_OP_breg5:
+ case DW_OP_breg6:
+ case DW_OP_breg7:
+ case DW_OP_breg8:
+ case DW_OP_breg9:
+ case DW_OP_breg10:
+ case DW_OP_breg11:
+ case DW_OP_breg12:
+ case DW_OP_breg13:
+ case DW_OP_breg14:
+ case DW_OP_breg15:
+ case DW_OP_breg16:
+ case DW_OP_breg17:
+ case DW_OP_breg18:
+ case DW_OP_breg19:
+ case DW_OP_breg20:
+ case DW_OP_breg21:
+ case DW_OP_breg22:
+ case DW_OP_breg23:
+ case DW_OP_breg24:
+ case DW_OP_breg25:
+ case DW_OP_breg26:
+ case DW_OP_breg27:
+ case DW_OP_breg28:
+ case DW_OP_breg29:
+ case DW_OP_breg30:
+ case DW_OP_breg31:
+ operand1 = _dwarf_decode_s_leb128(loc_ptr, &leb128_length);
+ loc_ptr = loc_ptr + leb128_length;
+ offset = offset + leb128_length;
+ break;
+
+ case DW_OP_bregx:
+ /* uleb reg num followed by sleb offset */
+ operand1 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length);
+ loc_ptr = loc_ptr + leb128_length;
+ offset = offset + leb128_length;
+
+ operand2 = _dwarf_decode_s_leb128(loc_ptr, &leb128_length);
+ loc_ptr = loc_ptr + leb128_length;
+ offset = offset + leb128_length;
+ break;
+
+ case DW_OP_dup:
+ case DW_OP_drop:
+ break;
+
+ case DW_OP_pick:
+ operand1 = *(Dwarf_Small *) loc_ptr;
+ loc_ptr = loc_ptr + 1;
+ offset = offset + 1;
+ break;
+
+ case DW_OP_over:
+ case DW_OP_swap:
+ case DW_OP_rot:
+ case DW_OP_deref:
+ break;
+
+ case DW_OP_deref_size:
+ operand1 = *(Dwarf_Small *) loc_ptr;
+ loc_ptr = loc_ptr + 1;
+ offset = offset + 1;
+ break;
+
+ case DW_OP_xderef:
+ break;
+
+ case DW_OP_xderef_size:
+ operand1 = *(Dwarf_Small *) loc_ptr;
+ loc_ptr = loc_ptr + 1;
+ offset = offset + 1;
+ break;
+
+ case DW_OP_abs:
+ case DW_OP_and:
+ case DW_OP_div:
+ case DW_OP_minus:
+ case DW_OP_mod:
+ case DW_OP_mul:
+ case DW_OP_neg:
+ case DW_OP_not:
+ case DW_OP_or:
+ case DW_OP_plus:
+ break;
+
+ case DW_OP_plus_uconst:
+ operand1 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length);
+ loc_ptr = loc_ptr + leb128_length;
+ offset = offset + leb128_length;
+ break;
+
+ case DW_OP_shl:
+ case DW_OP_shr:
+ case DW_OP_shra:
+ case DW_OP_xor:
+ break;
+
+ case DW_OP_le:
+ case DW_OP_ge:
+ case DW_OP_eq:
+ case DW_OP_lt:
+ case DW_OP_gt:
+ case DW_OP_ne:
+ break;
+
+ case DW_OP_skip:
+ case DW_OP_bra:
+ READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 2);
+ loc_ptr = loc_ptr + 2;
+ offset = offset + 2;
+ break;
+
+ case DW_OP_piece:
+ operand1 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length);
+ loc_ptr = loc_ptr + leb128_length;
+ offset = offset + leb128_length;
+ break;
+
+ case DW_OP_nop:
+ break;
+ case DW_OP_push_object_address: /* DWARF3 */
+ break;
+ case DW_OP_call2: /* DWARF3 */
+ READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 2);
+ loc_ptr = loc_ptr + 2;
+ offset = offset + 2;
+ break;
+
+ case DW_OP_call4: /* DWARF3 */
+ READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 4);
+ loc_ptr = loc_ptr + 4;
+ offset = offset + 4;
+ break;
+ case DW_OP_call_ref: /* DWARF3 */
+ READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr,
+ dbg->de_length_size);
+ loc_ptr = loc_ptr + dbg->de_length_size;
+ offset = offset + dbg->de_length_size;
+ break;
+
+ case DW_OP_form_tls_address: /* DWARF3f */
+ break;
+ case DW_OP_call_frame_cfa: /* DWARF3f */
+ break;
+ case DW_OP_bit_piece: /* DWARF3f */
+ /* uleb size in bits followed by uleb offset in bits */
+ operand1 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length);
+ loc_ptr = loc_ptr + leb128_length;
+ offset = offset + leb128_length;
+
+ operand2 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length);
+ loc_ptr = loc_ptr + leb128_length;
+ offset = offset + leb128_length;
+ break;
+ case DW_OP_implicit_value: /* DWARF4 */
+ /* uleb length of value bytes followed by that
+ number of bytes of the value. */
+ operand1 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length);
+ loc_ptr = loc_ptr + leb128_length;
+ offset = offset + leb128_length;
+
+ /* Second operand is block of 'operand1' bytes of stuff. */
+ /* This using the second operand as a pointer
+ is quite ugly. */
+ /* This gets an ugly compiler warning. Sorry. */
+ operand2 = (Dwarf_Unsigned)(uintptr_t)loc_ptr;
+ offset = offset + operand1;
+ loc_ptr = loc_ptr + operand1;
+ break;
+ case DW_OP_stack_value: /* DWARF4 */
+ break;
+
+
+ default:
+ _dwarf_error(dbg, error, DW_DLE_LOC_EXPR_BAD);
+ return (NULL);
+ }
+
+
+ curr_loc->lc_number = operand1;
+ curr_loc->lc_number2 = operand2;
+
+ if (head_loc == NULL)
+ head_loc = prev_loc = curr_loc;
+ else {
+ prev_loc->lc_next = curr_loc;
+ prev_loc = curr_loc;
+ }
+ }
+
+ block_loc =
+ (Dwarf_Loc *) _dwarf_get_alloc(dbg, DW_DLA_LOC_BLOCK, op_count);
+ if (block_loc == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (NULL);
+ }
+
+ curr_loc = head_loc;
+ for (i = 0; i < op_count; i++) {
+ (block_loc + i)->lr_atom = curr_loc->lc_atom;
+ (block_loc + i)->lr_number = curr_loc->lc_number;
+ (block_loc + i)->lr_number2 = curr_loc->lc_number2;
+ (block_loc + i)->lr_offset = curr_loc->lc_offset;
+
+ prev_loc = curr_loc;
+ curr_loc = curr_loc->lc_next;
+ dwarf_dealloc(dbg, prev_loc, DW_DLA_LOC_CHAIN);
+ }
+
+ locdesc =
+ (Dwarf_Locdesc *) _dwarf_get_alloc(dbg, DW_DLA_LOCDESC, 1);
+ if (locdesc == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (NULL);
+ }
+
+ locdesc->ld_cents = op_count;
+ locdesc->ld_s = block_loc;
+ locdesc->ld_from_loclist = loc_block->bl_from_loclist;
+ locdesc->ld_section_offset = loc_block->bl_section_offset;
+ locdesc->ld_lopc = lowpc;
+ locdesc->ld_hipc = highpc;
+
+ return (locdesc);
+}
+
+/* Using a loclist offset to get the in-memory
+ address of .debug_loc data to read, returns the loclist
+ 'header' info in return_block.
+*/
+
+#define MAX_ADDR ((address_size == 8)?0xffffffffffffffffULL:0xffffffff)
+
+static int
+_dwarf_read_loc_section(Dwarf_Debug dbg,
+ Dwarf_Block * return_block,
+ Dwarf_Addr * lowpc, Dwarf_Addr * hipc,
+ Dwarf_Off sec_offset,
+ Dwarf_Half address_size,
+ Dwarf_Error * error)
+{
+ Dwarf_Small *beg = dbg->de_debug_loc.dss_data + sec_offset;
+
+ Dwarf_Addr start_addr = 0;
+ Dwarf_Addr end_addr = 0;
+ Dwarf_Half exprblock_size = 0;
+ Dwarf_Unsigned exprblock_off =
+ 2 * address_size + sizeof(Dwarf_Half);
+
+ if (sec_offset >= dbg->de_debug_loc.dss_size) {
+ /* We're at the end. No more present. */
+ return DW_DLV_NO_ENTRY;
+ }
+
+ /* If it goes past end, error */
+ if (exprblock_off > dbg->de_debug_loc.dss_size) {
+ _dwarf_error(NULL, error, DW_DLE_DEBUG_LOC_SECTION_SHORT);
+ return DW_DLV_ERROR;
+ }
+
+ READ_UNALIGNED(dbg, start_addr, Dwarf_Addr, beg, address_size);
+ READ_UNALIGNED(dbg, end_addr, Dwarf_Addr,
+ beg + address_size, address_size);
+ if (start_addr == 0 && end_addr == 0) {
+ /* If start_addr and end_addr are 0, it's the end and no
+ exprblock_size field follows. */
+ exprblock_size = 0;
+ exprblock_off -= sizeof(Dwarf_Half);
+ } else if (start_addr == MAX_ADDR) {
+ /* end address is a base address, no exprblock_size field here
+ either */
+ exprblock_size = 0;
+ exprblock_off -= sizeof(Dwarf_Half);
+ } else {
+
+ READ_UNALIGNED(dbg, exprblock_size, Dwarf_Half,
+ beg + 2 * address_size, sizeof(Dwarf_Half));
+ /* exprblock_size can be zero, means no expression */
+ if ((exprblock_off + exprblock_size) > dbg->de_debug_loc.dss_size) {
+ _dwarf_error(NULL, error, DW_DLE_DEBUG_LOC_SECTION_SHORT);
+ return DW_DLV_ERROR;
+ }
+ }
+#undef MAX_ADDR
+ *lowpc = start_addr;
+ *hipc = end_addr;
+
+ return_block->bl_len = exprblock_size;
+ return_block->bl_from_loclist = 1;
+ return_block->bl_data = beg + exprblock_off;
+ return_block->bl_section_offset =
+ ((Dwarf_Small *) return_block->bl_data) - dbg->de_debug_loc.dss_data;
+
+ return DW_DLV_OK;
+
+}
+static int
+_dwarf_get_loclist_count(Dwarf_Debug dbg,
+ Dwarf_Off loclist_offset,
+ Dwarf_Half address_size,
+ int *loclist_count, Dwarf_Error * error)
+{
+ int count = 0;
+ Dwarf_Off offset = loclist_offset;
+
+
+ for (;;) {
+ Dwarf_Block b;
+ Dwarf_Addr lowpc;
+ Dwarf_Addr highpc;
+ int res = _dwarf_read_loc_section(dbg, &b,
+ &lowpc, &highpc,
+ offset, address_size,error);
+
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ offset = b.bl_len + b.bl_section_offset;
+ if (lowpc == 0 && highpc == 0) {
+ break;
+ }
+ count++;
+ }
+ *loclist_count = count;
+ return DW_DLV_OK;
+}
+
+/* Helper routine to avoid code duplication.
+*/
+static int
+_dwarf_setup_loc(Dwarf_Attribute attr,
+ Dwarf_Debug * dbg_ret,
+ Dwarf_CU_Context *cucontext_ret,
+ Dwarf_Half * form_ret, Dwarf_Error * error)
+{
+ Dwarf_Debug dbg = 0;
+ Dwarf_Half form = 0;
+ int blkres = DW_DLV_ERROR;
+
+ if (attr == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NULL);
+ return (DW_DLV_ERROR);
+ }
+ if (attr->ar_cu_context == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT);
+ return (DW_DLV_ERROR);
+ }
+ *cucontext_ret = attr->ar_cu_context;
+
+ dbg = attr->ar_cu_context->cc_dbg;
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_ATTR_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ *dbg_ret = dbg;
+ blkres = dwarf_whatform(attr, &form, error);
+ if (blkres != DW_DLV_OK) {
+ _dwarf_error(dbg, error, DW_DLE_LOC_EXPR_BAD);
+ return blkres;
+ }
+ *form_ret = form;
+ return DW_DLV_OK;
+}
+
+/* Helper routine to avoid code duplication.
+*/
+static int
+_dwarf_get_loclist_header_start(Dwarf_Debug dbg,
+ Dwarf_Attribute attr,
+ Dwarf_Unsigned * loclist_offset,
+ Dwarf_Error * error)
+{
+ int blkres = dwarf_formudata(attr, loclist_offset, error);
+ if (blkres != DW_DLV_OK) {
+ return (blkres);
+ }
+
+ if (!dbg->de_debug_loc.dss_data) {
+ int secload = _dwarf_load_section(dbg, &dbg->de_debug_loc,error);
+ if (secload != DW_DLV_OK) {
+ return secload;
+ }
+ }
+ return DW_DLV_OK;
+}
+
+/* When llbuf (see dwarf_loclist_n) is partially set up
+ and an error is encountered, tear it down as it
+ won't be used.
+*/
+static void
+_dwarf_cleanup_llbuf(Dwarf_Debug dbg, Dwarf_Locdesc ** llbuf, int count)
+{
+ int i;
+ for (i = 0; i < count; ++i) {
+ dwarf_dealloc(dbg, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK);
+ dwarf_dealloc(dbg, llbuf[i], DW_DLA_LOCDESC);
+ }
+ dwarf_dealloc(dbg, llbuf, DW_DLA_LIST);
+}
+
+/*
+ Handles simple location entries and loclists.
+ Returns all the Locdesc's thru llbuf.
+
+*/
+int
+dwarf_loclist_n(Dwarf_Attribute attr,
+ Dwarf_Locdesc *** llbuf_out,
+ Dwarf_Signed * listlen_out, Dwarf_Error * error)
+{
+ Dwarf_Debug dbg;
+
+ /*
+ Dwarf_Attribute that describes the DW_AT_location in die, if
+ present. */
+ Dwarf_Attribute loc_attr = attr;
+
+ /* Dwarf_Block that describes a single location expression. */
+ Dwarf_Block loc_block;
+
+ /* A pointer to the current Dwarf_Locdesc read. */
+ Dwarf_Locdesc *locdesc = 0;
+
+ Dwarf_Half form = 0;
+ Dwarf_Addr lowpc = 0;
+ Dwarf_Addr highpc = 0;
+ Dwarf_Signed listlen = 0;
+ Dwarf_Locdesc **llbuf = 0;
+ Dwarf_CU_Context cucontext = 0;
+ unsigned address_size = 0;
+
+ int blkres = DW_DLV_ERROR;
+ int setup_res = DW_DLV_ERROR;
+
+ /* ***** BEGIN CODE ***** */
+ setup_res = _dwarf_setup_loc(attr, &dbg,&cucontext, &form, error);
+ if (setup_res != DW_DLV_OK) {
+ return setup_res;
+ }
+ address_size = cucontext->cc_address_size;
+ /* If this is a form_block then it's a location expression. If it's
+ DW_FORM_data4 or DW_FORM_data8 it's a loclist offset */
+ if (((cucontext->cc_version_stamp == CURRENT_VERSION_STAMP ||
+ cucontext->cc_version_stamp == CURRENT_VERSION_STAMP3) &&
+ (form == DW_FORM_data4 || form == DW_FORM_data8)) ||
+ (cucontext->cc_version_stamp == CURRENT_VERSION_STAMP4 &&
+ form == DW_FORM_sec_offset))
+ {
+
+
+ /* A reference to .debug_loc, with an offset in .debug_loc of a
+ loclist */
+ Dwarf_Unsigned loclist_offset = 0;
+ int off_res = DW_DLV_ERROR;
+ int count_res = DW_DLV_ERROR;
+ int loclist_count;
+ int lli;
+
+ off_res = _dwarf_get_loclist_header_start(dbg,
+ attr, &loclist_offset,
+ error);
+ if (off_res != DW_DLV_OK) {
+ return off_res;
+ }
+ count_res = _dwarf_get_loclist_count(dbg, loclist_offset,
+ address_size,
+ &loclist_count, error);
+ listlen = loclist_count;
+ if (count_res != DW_DLV_OK) {
+ return count_res;
+ }
+ if (loclist_count == 0) {
+ return DW_DLV_NO_ENTRY;
+ }
+
+ llbuf = (Dwarf_Locdesc **)
+ _dwarf_get_alloc(dbg, DW_DLA_LIST, loclist_count);
+ if (!llbuf) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ for (lli = 0; lli < loclist_count; ++lli) {
+ blkres = _dwarf_read_loc_section(dbg, &loc_block,
+ &lowpc,
+ &highpc,
+ loclist_offset,
+ address_size,
+ error);
+ if (blkres != DW_DLV_OK) {
+ _dwarf_cleanup_llbuf(dbg, llbuf, lli);
+ return (blkres);
+ }
+ locdesc = _dwarf_get_locdesc(dbg, &loc_block,
+ address_size,
+ lowpc, highpc, error);
+ if (locdesc == NULL) {
+ _dwarf_cleanup_llbuf(dbg, llbuf, lli);
+ /* low level error already set: let it be passed back */
+ return (DW_DLV_ERROR);
+ }
+ llbuf[lli] = locdesc;
+
+ /* Now get to next loclist entry offset. */
+ loclist_offset = loc_block.bl_section_offset +
+ loc_block.bl_len;
+ }
+
+
+ } else {
+ Dwarf_Block *tblock = 0;
+
+ blkres = dwarf_formblock(loc_attr, &tblock, error);
+ if (blkres != DW_DLV_OK) {
+ return (blkres);
+ }
+ loc_block = *tblock;
+ /* We copied tblock contents to the stack var, so can dealloc
+ tblock now. Avoids leaks. */
+ dwarf_dealloc(dbg, tblock, DW_DLA_BLOCK);
+ listlen = 1; /* One by definition of a location entry. */
+ lowpc = 0; /* HACK */
+ highpc = (Dwarf_Unsigned) (-1LL); /* HACK */
+
+ /* An empty location description (block length 0) means the
+ code generator emitted no variable, the variable was not
+ generated, it was unused or perhaps never tested after being
+ set. Dwarf2, section 2.4.1 In other words, it is not an
+ error, and we don't test for block length 0 specially here. */
+ locdesc = _dwarf_get_locdesc(dbg, &loc_block,
+ address_size,
+ lowpc, highpc, error);
+ if (locdesc == NULL) {
+ /* low level error already set: let it be passed back */
+ return (DW_DLV_ERROR);
+ }
+ llbuf = (Dwarf_Locdesc **)
+ _dwarf_get_alloc(dbg, DW_DLA_LIST, listlen);
+ if (!llbuf) {
+ /* Free the locdesc we allocated but won't use. */
+ dwarf_dealloc(dbg, locdesc, DW_DLA_LOCDESC);
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+ llbuf[0] = locdesc;
+ }
+
+ *llbuf_out = llbuf;
+ *listlen_out = listlen;
+ return (DW_DLV_OK);
+}
+
+
+/*
+ Handles only a location expression.
+ If called on a loclist, just returns one of those.
+ Cannot not handle a real loclist.
+ It returns the location expression as a loclist with
+ a single entry.
+ See dwarf_loclist_n() which handles any number
+ of location list entries.
+
+ This is the original definition, and it simply
+ does not work for loclists. Kept for compatibility.
+*/
+int
+dwarf_loclist(Dwarf_Attribute attr,
+ Dwarf_Locdesc ** llbuf,
+ Dwarf_Signed * listlen, Dwarf_Error * error)
+{
+ Dwarf_Debug dbg;
+
+ /* Dwarf_Attribute that describes the DW_AT_location in die, if
+ present. */
+ Dwarf_Attribute loc_attr = attr;
+
+ /* Dwarf_Block that describes a single location expression. */
+ Dwarf_Block loc_block;
+
+ /* A pointer to the current Dwarf_Locdesc read. */
+ Dwarf_Locdesc *locdesc = 0;
+
+ Dwarf_Half form = 0;
+ Dwarf_Addr lowpc = 0;
+ Dwarf_Addr highpc = 0;
+ Dwarf_CU_Context cucontext = 0;
+ unsigned address_size = 0;
+
+ int blkres = DW_DLV_ERROR;
+ int setup_res = DW_DLV_ERROR;
+
+ /* ***** BEGIN CODE ***** */
+ setup_res = _dwarf_setup_loc(attr, &dbg, &cucontext, &form, error);
+ if (setup_res != DW_DLV_OK) {
+ return setup_res;
+ }
+ address_size = cucontext->cc_address_size;
+ /* If this is a form_block then it's a location expression. If it's
+ DW_FORM_data4 or DW_FORM_data8 it's a loclist offset */
+ if (((cucontext->cc_version_stamp == CURRENT_VERSION_STAMP ||
+ cucontext->cc_version_stamp == CURRENT_VERSION_STAMP3) &&
+ (form == DW_FORM_data4 || form == DW_FORM_data8)) ||
+ (cucontext->cc_version_stamp == CURRENT_VERSION_STAMP4 &&
+ form == DW_FORM_sec_offset))
+ {
+
+ /* A reference to .debug_loc, with an offset in .debug_loc of a
+ loclist */
+ Dwarf_Unsigned loclist_offset = 0;
+ int off_res = DW_DLV_ERROR;
+
+ off_res = _dwarf_get_loclist_header_start(dbg,
+ attr, &loclist_offset,
+ error);
+ if (off_res != DW_DLV_OK) {
+ return off_res;
+ }
+
+ /* With dwarf_loclist, just read a single entry */
+ blkres = _dwarf_read_loc_section(dbg, &loc_block,
+ &lowpc,
+ &highpc,
+ loclist_offset,
+ address_size,
+ error);
+ if (blkres != DW_DLV_OK) {
+ return (blkres);
+ }
+ } else {
+ Dwarf_Block *tblock = 0;
+
+ blkres = dwarf_formblock(loc_attr, &tblock, error);
+ if (blkres != DW_DLV_OK) {
+ return (blkres);
+ }
+ loc_block = *tblock;
+ /* We copied tblock contents to the stack var, so can dealloc
+ tblock now. Avoids leaks. */
+ dwarf_dealloc(dbg, tblock, DW_DLA_BLOCK);
+ lowpc = 0; /* HACK */
+ highpc = (Dwarf_Unsigned) (-1LL); /* HACK */
+ }
+
+ /* An empty location description (block length 0) means the code
+ generator emitted no variable, the variable was not generated,
+ it was unused or perhaps never tested after being set. Dwarf2,
+ section 2.4.1 In other words, it is not an error, and we don't
+ test for block length 0 specially here.
+ See *dwarf_loclist_n() which handles the general case, this case
+ handles only a single location expression. */
+ locdesc = _dwarf_get_locdesc(dbg, &loc_block,
+ address_size,
+ lowpc, highpc, error);
+ if (locdesc == NULL) {
+ /* low level error already set: let it be passed back */
+ return (DW_DLV_ERROR);
+ }
+
+ *llbuf = locdesc;
+ *listlen = 1;
+ return (DW_DLV_OK);
+}
+
+
+
+/*
+ Handles only a location expression.
+ It returns the location expression as a loclist with
+ a single entry.
+
+ Usable to access dwarf expressions from any source, but
+ specifically from
+ DW_CFA_def_cfa_expression
+ DW_CFA_expression
+ DW_CFA_val_expression
+
+ expression_in must point to a valid dwarf expression
+ set of bytes of length expression_length. Not
+ a DW_FORM_block*, just the expression bytes.
+
+ If the address_size != de_pointer_size this will not work
+ right. FIXME.
+*/
+int
+dwarf_loclist_from_expr(Dwarf_Debug dbg,
+ Dwarf_Ptr expression_in,
+ Dwarf_Unsigned expression_length,
+ Dwarf_Locdesc ** llbuf,
+ Dwarf_Signed * listlen, Dwarf_Error * error)
+{
+ int res = 0;
+ Dwarf_Half addr_size = dbg->de_pointer_size;
+ res = dwarf_loclist_from_expr_a(dbg,expression_in,
+ expression_length, addr_size,llbuf,listlen,error);
+ return res;
+}
+/* New April 27 2009. Adding addr_size argument for the rare
+ * cases where an object has CUs with a different address_size. */
+int
+dwarf_loclist_from_expr_a(Dwarf_Debug dbg,
+ Dwarf_Ptr expression_in,
+ Dwarf_Unsigned expression_length,
+ Dwarf_Half addr_size,
+ Dwarf_Locdesc ** llbuf,
+ Dwarf_Signed * listlen, Dwarf_Error * error)
+{
+ /* Dwarf_Block that describes a single location expression. */
+ Dwarf_Block loc_block;
+
+ /* A pointer to the current Dwarf_Locdesc read. */
+ Dwarf_Locdesc *locdesc = 0;
+ Dwarf_Addr lowpc = 0;
+ Dwarf_Addr highpc = (Dwarf_Unsigned) (-1LL);
+
+ memset(&loc_block,0,sizeof(loc_block));
+ loc_block.bl_len = expression_length;
+ loc_block.bl_data = expression_in;
+ loc_block.bl_from_loclist = 0; /* Not from loclist. */
+ loc_block.bl_section_offset = 0; /* Fake. Not meaningful. */
+
+ /* An empty location description (block length 0) means the code
+ generator emitted no variable, the variable was not generated,
+ it was unused or perhaps never tested after being set. Dwarf2,
+ section 2.4.1 In other words, it is not an error, and we don't
+ test for block length 0 specially here. */
+ locdesc = _dwarf_get_locdesc(dbg, &loc_block,
+ addr_size,lowpc, highpc, error);
+ if (locdesc == NULL) {
+ /* low level error already set: let it be passed back */
+ return (DW_DLV_ERROR);
+ }
+
+ *llbuf = locdesc;
+ *listlen = 1;
+ return (DW_DLV_OK);
+}
+
+/* Usable to read a single loclist or to read a block of them
+ or to read an entire section's loclists.
+
+ It's broken because it's not safe to read a loclist entry
+ when we do not know the address size (in any object where
+ address size can vary by compilation unit).
+*/
+
+ /*ARGSUSED*/ int
+dwarf_get_loclist_entry(Dwarf_Debug dbg,
+ Dwarf_Unsigned offset,
+ Dwarf_Addr * hipc_offset,
+ Dwarf_Addr * lopc_offset,
+ Dwarf_Ptr * data,
+ Dwarf_Unsigned * entry_len,
+ Dwarf_Unsigned * next_entry,
+ Dwarf_Error * error)
+{
+ Dwarf_Block b;
+ Dwarf_Addr lowpc = 0;
+ Dwarf_Addr highpc = 0;
+ Dwarf_Half address_size = 0;
+ int res = DW_DLV_ERROR;
+
+ if (!dbg->de_debug_loc.dss_data) {
+ int secload = _dwarf_load_section(dbg, &dbg->de_debug_loc,error);
+ if (secload != DW_DLV_OK) {
+ return secload;
+ }
+ }
+
+ /* FIXME: address_size is not necessarily the same in every frame. */
+ address_size = dbg->de_pointer_size;
+ res = _dwarf_read_loc_section(dbg,
+ &b, &lowpc, &highpc, offset,
+ address_size,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ *hipc_offset = highpc;
+ *lopc_offset = lowpc;
+ *entry_len = b.bl_len;
+ *data = b.bl_data;
+ *next_entry = b.bl_len + b.bl_section_offset;
+ return DW_DLV_OK;
+}
+
+
diff --git a/usr/src/lib/libdwarf/common/dwarf_loc.h b/usr/src/lib/libdwarf/common/dwarf_loc.h
new file mode 100644
index 0000000000..685d199f29
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_loc.h
@@ -0,0 +1,46 @@
+/*
+
+ Copyright (C) 2000, 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
+
+*/
+
+
+
+typedef struct Dwarf_Loc_Chain_s *Dwarf_Loc_Chain;
+
+struct Dwarf_Loc_Chain_s {
+ Dwarf_Small lc_atom;
+ Dwarf_Unsigned lc_number;
+ Dwarf_Unsigned lc_number2;
+ Dwarf_Unsigned lc_offset;
+ Dwarf_Loc_Chain lc_next;
+};
diff --git a/usr/src/lib/libdwarf/common/dwarf_macro.c b/usr/src/lib/libdwarf/common/dwarf_macro.c
new file mode 100644
index 0000000000..e1ff976d8c
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_macro.c
@@ -0,0 +1,467 @@
+/*
+
+ Copyright (C) 2000-2004 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2007-2010 David Anderson. 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
+
+*/
+/* The address of the Free Software Foundation is
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ SGI has moved from the Crittenden Lane address.
+*/
+
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+#include <limits.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif /* HAVE_STDLIB_H */
+#include "dwarf_macro.h"
+
+
+#define LEFTPAREN '('
+#define RIGHTPAREN ')'
+#define SPACE ' '
+
+/*
+ Given the dwarf macro string, return a pointer to
+ the value. Returns pointer to 0 byte at end of string
+ if no value found (meaning the value is the empty string).
+
+ Only understands well-formed dwarf macinfo strings.
+*/
+char *
+dwarf_find_macro_value_start(char *str)
+{
+ char *lcp;
+ int funclike = 0;
+
+ for (lcp = str; *lcp; ++lcp) {
+ switch (*lcp) {
+ case LEFTPAREN:
+ funclike = 1;
+ break;
+ case RIGHTPAREN:
+ /* lcp+1 must be a space, and following char is the value */
+ return lcp + 2;
+ case SPACE:
+ /* we allow extraneous spaces inside macro parameter **
+ list, just in case... This is not really needed. */
+ if (!funclike) {
+ return lcp + 1;
+ }
+ break;
+ }
+ }
+ /* never found value: returns pointer to the 0 byte at end of
+ string */
+ return lcp;
+
+}
+
+
+/*
+ Try to keep fileindex correct in every Macro_Details
+ record by tracking file starts and ends.
+ Uses high water mark: space reused, not freed.
+ Presumption is that this makes sense for most uses.
+ STARTERMAX is set so that the array need not be expanded for
+ most files: it is the initial include file depth.
+*/
+struct macro_stack_s {
+ Dwarf_Signed *st_base;
+ long max;
+ long next_to_use;
+ int was_fault;
+};
+
+static void _dwarf_reset_index_macro_stack(struct macro_stack_s *ms);
+static void
+free_macro_stack(Dwarf_Debug dbg, struct macro_stack_s *ms)
+{
+ dwarf_dealloc(dbg,ms->st_base,DW_DLA_STRING);
+ _dwarf_reset_index_macro_stack(ms);
+}
+
+#define STARTERMAX 10
+static void
+_dwarf_reset_index_macro_stack(struct macro_stack_s *ms)
+{
+ ms->st_base = 0;
+ ms->max = 0;
+ ms->next_to_use = 0;
+ ms->was_fault = 0;
+}
+static int
+_dwarf_macro_stack_push_index(Dwarf_Debug dbg, Dwarf_Signed indx,
+ struct macro_stack_s *ms)
+{
+ Dwarf_Signed *newbase;
+
+ if (ms->next_to_use >= ms->max) {
+ long new_size;
+
+ if (ms->max == 0) {
+ ms->max = STARTERMAX;
+ }
+ new_size = ms->max * 2;
+ newbase =
+ _dwarf_get_alloc(dbg, DW_DLA_STRING,
+ new_size * sizeof(Dwarf_Signed));
+ if (newbase == 0) {
+ /* just leave the old array in place */
+ ms->was_fault = 1;
+ return DW_DLV_ERROR;
+ }
+ if(ms->st_base) {
+ memcpy(newbase, ms->st_base,
+ ms->next_to_use * sizeof(Dwarf_Signed));
+ dwarf_dealloc(dbg, ms->st_base, DW_DLA_STRING);
+ }
+ ms->st_base = newbase;
+ ms->max = new_size;
+ }
+ ms->st_base[ms->next_to_use] = indx;
+ ++ms->next_to_use;
+ return DW_DLV_OK;
+}
+
+static Dwarf_Signed
+_dwarf_macro_stack_pop_index(struct macro_stack_s *ms)
+{
+ if (ms->was_fault) {
+ return -1;
+ }
+ if (ms->next_to_use > 0) {
+ ms->next_to_use--;
+ return (ms->st_base[ms->next_to_use]);
+ } else {
+ ms->was_fault = 1;
+ }
+ return -1;
+}
+
+/* starting at macro_offset in .debug_macinfo,
+ if maximum_count is 0, treat as if it is infinite.
+ get macro data up thru
+ maximum_count entries or the end of a compilation
+ unit's entries (whichever comes first).
+*/
+
+int
+dwarf_get_macro_details(Dwarf_Debug dbg,
+ Dwarf_Off macro_offset,
+ Dwarf_Unsigned maximum_count,
+ Dwarf_Signed * entry_count,
+ Dwarf_Macro_Details ** details,
+ Dwarf_Error * error)
+{
+ Dwarf_Small *macro_base = 0;
+ Dwarf_Small *pnext = 0;
+ Dwarf_Unsigned endloc = 0;
+ unsigned char uc = 0;
+ unsigned long depth = 0;
+ /* By section 6.3.2 Dwarf3 draft 8/9,
+ the base file should appear as
+ DW_MACINFO_start_file. See
+ http://gcc.gnu.org/ml/gcc-bugs/2005-02/msg03442.html
+ on "[Bug debug/20253] New: [3.4/4.0 regression]:
+ Macro debug info broken due to lexer change" for how
+ gcc is broken in some versions. We no longer use
+ depth as a stopping point, it's not needed as a
+ stopping point anyway. */
+ int res = 0;
+ /* count space used by strings */
+ unsigned long str_space = 0;
+ int done = 0;
+ unsigned long space_needed = 0;
+ unsigned long string_offset = 0;
+ Dwarf_Small *return_data = 0;
+ Dwarf_Small *pdata = 0;
+ unsigned long final_count = 0;
+ Dwarf_Signed fileindex = -1;
+ Dwarf_Small *latest_str_loc = 0;
+ struct macro_stack_s msdata;
+
+ unsigned long count = 0;
+ unsigned long max_count = (unsigned long) maximum_count;
+
+ _dwarf_reset_index_macro_stack(&msdata);
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
+ free_macro_stack(dbg,&msdata);
+ return (DW_DLV_ERROR);
+ }
+
+ res = _dwarf_load_section(dbg, &dbg->de_debug_macinfo,error);
+ if (res != DW_DLV_OK) {
+ free_macro_stack(dbg,&msdata);
+ return res;
+ }
+
+ macro_base = dbg->de_debug_macinfo.dss_data;
+ if (macro_base == NULL) {
+ free_macro_stack(dbg,&msdata);
+ return (DW_DLV_NO_ENTRY);
+ }
+ if (macro_offset >= dbg->de_debug_macinfo.dss_size) {
+ free_macro_stack(dbg,&msdata);
+ return (DW_DLV_NO_ENTRY);
+ }
+
+ pnext = macro_base + macro_offset;
+ if (maximum_count == 0) {
+ max_count = ULONG_MAX;
+ }
+
+
+ /* how many entries and how much space will they take? */
+
+ endloc = (pnext - macro_base);
+ if (endloc >= dbg->de_debug_macinfo.dss_size) {
+ if (endloc == dbg->de_debug_macinfo.dss_size) {
+ /* normal: found last entry */
+ free_macro_stack(dbg,&msdata);
+ return DW_DLV_NO_ENTRY;
+ }
+ _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_LENGTH_BAD);
+ free_macro_stack(dbg,&msdata);
+ return (DW_DLV_ERROR);
+ }
+ for (count = 0; !done && count < max_count; ++count) {
+ unsigned long slen;
+ Dwarf_Word len;
+
+ uc = *pnext;
+ ++pnext; /* get past the type code */
+ switch (uc) {
+ case DW_MACINFO_define:
+ case DW_MACINFO_undef:
+ /* line, string */
+ case DW_MACINFO_vendor_ext:
+ /* number, string */
+ (void) _dwarf_decode_u_leb128(pnext, &len);
+
+ pnext += len;
+ if (((pnext - macro_base)) >= dbg->de_debug_macinfo.dss_size) {
+ free_macro_stack(dbg,&msdata);
+ _dwarf_error(dbg, error,
+ DW_DLE_DEBUG_MACRO_INCONSISTENT);
+ return (DW_DLV_ERROR);
+ }
+ slen = strlen((char *) pnext) + 1;
+ pnext += slen;
+ if (((pnext - macro_base)) >= dbg->de_debug_macinfo.dss_size) {
+ free_macro_stack(dbg,&msdata);
+ _dwarf_error(dbg, error,
+ DW_DLE_DEBUG_MACRO_INCONSISTENT);
+ return (DW_DLV_ERROR);
+ }
+ str_space += slen;
+ break;
+ case DW_MACINFO_start_file:
+ /* line, file index */
+ (void) _dwarf_decode_u_leb128(pnext, &len);
+ pnext += len;
+ if (((pnext - macro_base)) >= dbg->de_debug_macinfo.dss_size) {
+ free_macro_stack(dbg,&msdata);
+ _dwarf_error(dbg, error,
+ DW_DLE_DEBUG_MACRO_INCONSISTENT);
+ return (DW_DLV_ERROR);
+ }
+ (void) _dwarf_decode_u_leb128(pnext, &len);
+ pnext += len;
+ if (((pnext - macro_base)) >= dbg->de_debug_macinfo.dss_size) {
+ free_macro_stack(dbg,&msdata);
+ _dwarf_error(dbg, error,
+ DW_DLE_DEBUG_MACRO_INCONSISTENT);
+ return (DW_DLV_ERROR);
+ }
+ ++depth;
+ break;
+
+ case DW_MACINFO_end_file:
+ if (--depth == 0) {
+ /* done = 1; no, do not stop here, at least one gcc had
+ the wrong depth settings in the gcc 3.4 timeframe. */
+ }
+ break; /* no string or number here */
+ case 0:
+ /* end of cu's entries */
+ done = 1;
+ break;
+ default:
+ free_macro_stack(dbg,&msdata);
+ _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_INCONSISTENT);
+ return (DW_DLV_ERROR);
+ /* bogus macinfo! */
+ }
+
+ endloc = (pnext - macro_base);
+ if (endloc == dbg->de_debug_macinfo.dss_size) {
+ done = 1;
+ } else if (endloc > dbg->de_debug_macinfo.dss_size) {
+ _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_LENGTH_BAD);
+ free_macro_stack(dbg,&msdata);
+ return (DW_DLV_ERROR);
+ }
+ }
+ if (count == 0) {
+ free_macro_stack(dbg,&msdata);
+ _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_INTERNAL_ERR);
+ return (DW_DLV_ERROR);
+ }
+
+ /* we have 'count' array entries to allocate and str_space bytes of
+ string space to provide for. */
+
+ string_offset = count * sizeof(Dwarf_Macro_Details);
+
+ /* extra 2 not really needed */
+ space_needed = string_offset + str_space + 2;
+ return_data = pdata =
+ _dwarf_get_alloc(dbg, DW_DLA_STRING, space_needed);
+ latest_str_loc = pdata + string_offset;
+ if (pdata == 0) {
+ free_macro_stack(dbg,&msdata);
+ _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_MALLOC_SPACE);
+ return (DW_DLV_ERROR);
+ }
+ pnext = macro_base + macro_offset;
+
+ done = 0;
+
+ /* A series ends with a type code of 0. */
+
+ for (final_count = 0; !done && final_count < count; ++final_count) {
+ unsigned long slen;
+ Dwarf_Word len;
+ Dwarf_Unsigned v1;
+ Dwarf_Macro_Details *pdmd = (Dwarf_Macro_Details *) (pdata +
+ (final_count * sizeof (Dwarf_Macro_Details)));
+
+ endloc = (pnext - macro_base);
+ if (endloc > dbg->de_debug_macinfo.dss_size) {
+ free_macro_stack(dbg,&msdata);
+ _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_LENGTH_BAD);
+ return (DW_DLV_ERROR);
+ }
+ uc = *pnext;
+ pdmd->dmd_offset = (pnext - macro_base);
+ pdmd->dmd_type = uc;
+ pdmd->dmd_fileindex = fileindex;
+ pdmd->dmd_lineno = 0;
+ pdmd->dmd_macro = 0;
+ ++pnext; /* get past the type code */
+ switch (uc) {
+ case DW_MACINFO_define:
+ case DW_MACINFO_undef:
+ /* line, string */
+ case DW_MACINFO_vendor_ext:
+ /* number, string */
+ v1 = _dwarf_decode_u_leb128(pnext, &len);
+ pdmd->dmd_lineno = v1;
+
+ pnext += len;
+ if (((pnext - macro_base)) >= dbg->de_debug_macinfo.dss_size) {
+ free_macro_stack(dbg,&msdata);
+ dwarf_dealloc(dbg, return_data, DW_DLA_STRING);
+ _dwarf_error(dbg, error,
+ DW_DLE_DEBUG_MACRO_INCONSISTENT);
+ return (DW_DLV_ERROR);
+ }
+ slen = strlen((char *) pnext) + 1;
+ strcpy((char *) latest_str_loc, (char *) pnext);
+ pdmd->dmd_macro = (char *) latest_str_loc;
+ latest_str_loc += slen;
+ pnext += slen;
+ if (((pnext - macro_base)) >= dbg->de_debug_macinfo.dss_size) {
+ free_macro_stack(dbg,&msdata);
+ dwarf_dealloc(dbg, return_data, DW_DLA_STRING);
+ _dwarf_error(dbg, error,
+ DW_DLE_DEBUG_MACRO_INCONSISTENT);
+ return (DW_DLV_ERROR);
+ }
+ break;
+ case DW_MACINFO_start_file:
+ /* Line, file index */
+ v1 = _dwarf_decode_u_leb128(pnext, &len);
+ pdmd->dmd_lineno = v1;
+ pnext += len;
+ if (((pnext - macro_base)) >= dbg->de_debug_macinfo.dss_size) {
+ free_macro_stack(dbg,&msdata);
+ dwarf_dealloc(dbg, return_data, DW_DLA_STRING);
+ _dwarf_error(dbg, error,
+ DW_DLE_DEBUG_MACRO_INCONSISTENT);
+ return (DW_DLV_ERROR);
+ }
+ v1 = _dwarf_decode_u_leb128(pnext, &len);
+ pdmd->dmd_fileindex = v1;
+ (void) _dwarf_macro_stack_push_index(dbg, fileindex,
+ &msdata);
+ /* We ignore the error, we just let fileindex ** be -1 when
+ we pop this one. */
+ fileindex = v1;
+ pnext += len;
+ if (((pnext - macro_base)) >= dbg->de_debug_macinfo.dss_size) {
+ free_macro_stack(dbg,&msdata);
+ dwarf_dealloc(dbg, return_data, DW_DLA_STRING);
+ _dwarf_error(dbg, error,
+ DW_DLE_DEBUG_MACRO_INCONSISTENT);
+ return (DW_DLV_ERROR);
+ }
+ break;
+
+ case DW_MACINFO_end_file:
+ fileindex = _dwarf_macro_stack_pop_index(&msdata);
+ break; /* no string or number here */
+ case 0:
+ /* Type code of 0 means the end of cu's entries. */
+ done = 1;
+ break;
+ default:
+ /* Bogus macinfo! */
+ dwarf_dealloc(dbg, return_data, DW_DLA_STRING);
+ free_macro_stack(dbg,&msdata);
+ _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_INCONSISTENT);
+ return (DW_DLV_ERROR);
+ }
+ }
+ *entry_count = count;
+ *details = (Dwarf_Macro_Details *) return_data;
+ free_macro_stack(dbg,&msdata);
+ return DW_DLV_OK;
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_macro.h b/usr/src/lib/libdwarf/common/dwarf_macro.h
new file mode 100644
index 0000000000..31ea2e6e67
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_macro.h
@@ -0,0 +1,44 @@
+/*
+
+ Copyright (C) 2000, 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
+
+*/
+
+
+/*
+
+
+ dwarf_macro.h
+
+ $Revision: 1.4 $ $Date: 2004/10/28 22:19:14 $
+
+*/
diff --git a/usr/src/lib/libdwarf/common/dwarf_names.c b/usr/src/lib/libdwarf/common/dwarf_names.c
new file mode 100644
index 0000000000..417e025690
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_names.c
@@ -0,0 +1,2408 @@
+/* Generated routines, do not edit. */
+/* Generated on May 22 2011 03:05:33 */
+
+/* BEGIN FILE */
+
+#include "dwarf.h"
+
+#include "libdwarf.h"
+
+/* ARGSUSED */
+int
+dwarf_get_TAG_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_TAG_array_type:
+ *s_out = "DW_TAG_array_type";
+ return DW_DLV_OK;
+ case DW_TAG_class_type:
+ *s_out = "DW_TAG_class_type";
+ return DW_DLV_OK;
+ case DW_TAG_entry_point:
+ *s_out = "DW_TAG_entry_point";
+ return DW_DLV_OK;
+ case DW_TAG_enumeration_type:
+ *s_out = "DW_TAG_enumeration_type";
+ return DW_DLV_OK;
+ case DW_TAG_formal_parameter:
+ *s_out = "DW_TAG_formal_parameter";
+ return DW_DLV_OK;
+ case DW_TAG_imported_declaration:
+ *s_out = "DW_TAG_imported_declaration";
+ return DW_DLV_OK;
+ case DW_TAG_label:
+ *s_out = "DW_TAG_label";
+ return DW_DLV_OK;
+ case DW_TAG_lexical_block:
+ *s_out = "DW_TAG_lexical_block";
+ return DW_DLV_OK;
+ case DW_TAG_member:
+ *s_out = "DW_TAG_member";
+ return DW_DLV_OK;
+ case DW_TAG_pointer_type:
+ *s_out = "DW_TAG_pointer_type";
+ return DW_DLV_OK;
+ case DW_TAG_reference_type:
+ *s_out = "DW_TAG_reference_type";
+ return DW_DLV_OK;
+ case DW_TAG_compile_unit:
+ *s_out = "DW_TAG_compile_unit";
+ return DW_DLV_OK;
+ case DW_TAG_string_type:
+ *s_out = "DW_TAG_string_type";
+ return DW_DLV_OK;
+ case DW_TAG_structure_type:
+ *s_out = "DW_TAG_structure_type";
+ return DW_DLV_OK;
+ case DW_TAG_subroutine_type:
+ *s_out = "DW_TAG_subroutine_type";
+ return DW_DLV_OK;
+ case DW_TAG_typedef:
+ *s_out = "DW_TAG_typedef";
+ return DW_DLV_OK;
+ case DW_TAG_union_type:
+ *s_out = "DW_TAG_union_type";
+ return DW_DLV_OK;
+ case DW_TAG_unspecified_parameters:
+ *s_out = "DW_TAG_unspecified_parameters";
+ return DW_DLV_OK;
+ case DW_TAG_variant:
+ *s_out = "DW_TAG_variant";
+ return DW_DLV_OK;
+ case DW_TAG_common_block:
+ *s_out = "DW_TAG_common_block";
+ return DW_DLV_OK;
+ case DW_TAG_common_inclusion:
+ *s_out = "DW_TAG_common_inclusion";
+ return DW_DLV_OK;
+ case DW_TAG_inheritance:
+ *s_out = "DW_TAG_inheritance";
+ return DW_DLV_OK;
+ case DW_TAG_inlined_subroutine:
+ *s_out = "DW_TAG_inlined_subroutine";
+ return DW_DLV_OK;
+ case DW_TAG_module:
+ *s_out = "DW_TAG_module";
+ return DW_DLV_OK;
+ case DW_TAG_ptr_to_member_type:
+ *s_out = "DW_TAG_ptr_to_member_type";
+ return DW_DLV_OK;
+ case DW_TAG_set_type:
+ *s_out = "DW_TAG_set_type";
+ return DW_DLV_OK;
+ case DW_TAG_subrange_type:
+ *s_out = "DW_TAG_subrange_type";
+ return DW_DLV_OK;
+ case DW_TAG_with_stmt:
+ *s_out = "DW_TAG_with_stmt";
+ return DW_DLV_OK;
+ case DW_TAG_access_declaration:
+ *s_out = "DW_TAG_access_declaration";
+ return DW_DLV_OK;
+ case DW_TAG_base_type:
+ *s_out = "DW_TAG_base_type";
+ return DW_DLV_OK;
+ case DW_TAG_catch_block:
+ *s_out = "DW_TAG_catch_block";
+ return DW_DLV_OK;
+ case DW_TAG_const_type:
+ *s_out = "DW_TAG_const_type";
+ return DW_DLV_OK;
+ case DW_TAG_constant:
+ *s_out = "DW_TAG_constant";
+ return DW_DLV_OK;
+ case DW_TAG_enumerator:
+ *s_out = "DW_TAG_enumerator";
+ return DW_DLV_OK;
+ case DW_TAG_file_type:
+ *s_out = "DW_TAG_file_type";
+ return DW_DLV_OK;
+ case DW_TAG_friend:
+ *s_out = "DW_TAG_friend";
+ return DW_DLV_OK;
+ case DW_TAG_namelist:
+ *s_out = "DW_TAG_namelist";
+ return DW_DLV_OK;
+ case DW_TAG_namelist_item:
+ *s_out = "DW_TAG_namelist_item";
+ return DW_DLV_OK;
+ case DW_TAG_packed_type:
+ *s_out = "DW_TAG_packed_type";
+ return DW_DLV_OK;
+ case DW_TAG_subprogram:
+ *s_out = "DW_TAG_subprogram";
+ return DW_DLV_OK;
+ case DW_TAG_template_type_parameter:
+ *s_out = "DW_TAG_template_type_parameter";
+ return DW_DLV_OK;
+ case DW_TAG_template_value_parameter:
+ *s_out = "DW_TAG_template_value_parameter";
+ return DW_DLV_OK;
+ case DW_TAG_thrown_type:
+ *s_out = "DW_TAG_thrown_type";
+ return DW_DLV_OK;
+ case DW_TAG_try_block:
+ *s_out = "DW_TAG_try_block";
+ return DW_DLV_OK;
+ case DW_TAG_variant_part:
+ *s_out = "DW_TAG_variant_part";
+ return DW_DLV_OK;
+ case DW_TAG_variable:
+ *s_out = "DW_TAG_variable";
+ return DW_DLV_OK;
+ case DW_TAG_volatile_type:
+ *s_out = "DW_TAG_volatile_type";
+ return DW_DLV_OK;
+ case DW_TAG_dwarf_procedure:
+ *s_out = "DW_TAG_dwarf_procedure";
+ return DW_DLV_OK;
+ case DW_TAG_restrict_type:
+ *s_out = "DW_TAG_restrict_type";
+ return DW_DLV_OK;
+ case DW_TAG_interface_type:
+ *s_out = "DW_TAG_interface_type";
+ return DW_DLV_OK;
+ case DW_TAG_namespace:
+ *s_out = "DW_TAG_namespace";
+ return DW_DLV_OK;
+ case DW_TAG_imported_module:
+ *s_out = "DW_TAG_imported_module";
+ return DW_DLV_OK;
+ case DW_TAG_unspecified_type:
+ *s_out = "DW_TAG_unspecified_type";
+ return DW_DLV_OK;
+ case DW_TAG_partial_unit:
+ *s_out = "DW_TAG_partial_unit";
+ return DW_DLV_OK;
+ case DW_TAG_imported_unit:
+ *s_out = "DW_TAG_imported_unit";
+ return DW_DLV_OK;
+ case DW_TAG_mutable_type:
+ *s_out = "DW_TAG_mutable_type";
+ return DW_DLV_OK;
+ case DW_TAG_condition:
+ *s_out = "DW_TAG_condition";
+ return DW_DLV_OK;
+ case DW_TAG_shared_type:
+ *s_out = "DW_TAG_shared_type";
+ return DW_DLV_OK;
+ case DW_TAG_type_unit:
+ *s_out = "DW_TAG_type_unit";
+ return DW_DLV_OK;
+ case DW_TAG_rvalue_reference_type:
+ *s_out = "DW_TAG_rvalue_reference_type";
+ return DW_DLV_OK;
+ case DW_TAG_template_alias:
+ *s_out = "DW_TAG_template_alias";
+ return DW_DLV_OK;
+ case DW_TAG_lo_user:
+ *s_out = "DW_TAG_lo_user";
+ return DW_DLV_OK;
+ case DW_TAG_MIPS_loop:
+ *s_out = "DW_TAG_MIPS_loop";
+ return DW_DLV_OK;
+ case DW_TAG_HP_array_descriptor:
+ *s_out = "DW_TAG_HP_array_descriptor";
+ return DW_DLV_OK;
+ case DW_TAG_format_label:
+ *s_out = "DW_TAG_format_label";
+ return DW_DLV_OK;
+ case DW_TAG_function_template:
+ *s_out = "DW_TAG_function_template";
+ return DW_DLV_OK;
+ case DW_TAG_class_template:
+ *s_out = "DW_TAG_class_template";
+ return DW_DLV_OK;
+ case DW_TAG_GNU_BINCL:
+ *s_out = "DW_TAG_GNU_BINCL";
+ return DW_DLV_OK;
+ case DW_TAG_GNU_EINCL:
+ *s_out = "DW_TAG_GNU_EINCL";
+ return DW_DLV_OK;
+ case DW_TAG_GNU_template_template_parameter:
+ *s_out = "DW_TAG_GNU_template_template_parameter";
+ return DW_DLV_OK;
+ case DW_TAG_GNU_template_parameter_pack:
+ *s_out = "DW_TAG_GNU_template_parameter_pack";
+ return DW_DLV_OK;
+ case DW_TAG_GNU_formal_parameter_pack:
+ *s_out = "DW_TAG_GNU_formal_parameter_pack";
+ return DW_DLV_OK;
+ case DW_TAG_SUN_function_template:
+ *s_out = "DW_TAG_SUN_function_template";
+ return DW_DLV_OK;
+ case DW_TAG_SUN_class_template:
+ *s_out = "DW_TAG_SUN_class_template";
+ return DW_DLV_OK;
+ case DW_TAG_SUN_struct_template:
+ *s_out = "DW_TAG_SUN_struct_template";
+ return DW_DLV_OK;
+ case DW_TAG_SUN_union_template:
+ *s_out = "DW_TAG_SUN_union_template";
+ return DW_DLV_OK;
+ case DW_TAG_SUN_indirect_inheritance:
+ *s_out = "DW_TAG_SUN_indirect_inheritance";
+ return DW_DLV_OK;
+ case DW_TAG_SUN_codeflags:
+ *s_out = "DW_TAG_SUN_codeflags";
+ return DW_DLV_OK;
+ case DW_TAG_SUN_memop_info:
+ *s_out = "DW_TAG_SUN_memop_info";
+ return DW_DLV_OK;
+ case DW_TAG_SUN_omp_child_func:
+ *s_out = "DW_TAG_SUN_omp_child_func";
+ return DW_DLV_OK;
+ case DW_TAG_SUN_rtti_descriptor:
+ *s_out = "DW_TAG_SUN_rtti_descriptor";
+ return DW_DLV_OK;
+ case DW_TAG_SUN_dtor_info:
+ *s_out = "DW_TAG_SUN_dtor_info";
+ return DW_DLV_OK;
+ case DW_TAG_SUN_dtor:
+ *s_out = "DW_TAG_SUN_dtor";
+ return DW_DLV_OK;
+ case DW_TAG_SUN_f90_interface:
+ *s_out = "DW_TAG_SUN_f90_interface";
+ return DW_DLV_OK;
+ case DW_TAG_SUN_fortran_vax_structure:
+ *s_out = "DW_TAG_SUN_fortran_vax_structure";
+ return DW_DLV_OK;
+ case DW_TAG_SUN_hi:
+ *s_out = "DW_TAG_SUN_hi";
+ return DW_DLV_OK;
+ case DW_TAG_ALTIUM_circ_type:
+ *s_out = "DW_TAG_ALTIUM_circ_type";
+ return DW_DLV_OK;
+ case DW_TAG_ALTIUM_mwa_circ_type:
+ *s_out = "DW_TAG_ALTIUM_mwa_circ_type";
+ return DW_DLV_OK;
+ case DW_TAG_ALTIUM_rev_carry_type:
+ *s_out = "DW_TAG_ALTIUM_rev_carry_type";
+ return DW_DLV_OK;
+ case DW_TAG_ALTIUM_rom:
+ *s_out = "DW_TAG_ALTIUM_rom";
+ return DW_DLV_OK;
+ case DW_TAG_upc_shared_type:
+ *s_out = "DW_TAG_upc_shared_type";
+ return DW_DLV_OK;
+ case DW_TAG_upc_strict_type:
+ *s_out = "DW_TAG_upc_strict_type";
+ return DW_DLV_OK;
+ case DW_TAG_upc_relaxed_type:
+ *s_out = "DW_TAG_upc_relaxed_type";
+ return DW_DLV_OK;
+ case DW_TAG_PGI_kanji_type:
+ *s_out = "DW_TAG_PGI_kanji_type";
+ return DW_DLV_OK;
+ case DW_TAG_PGI_interface_block:
+ *s_out = "DW_TAG_PGI_interface_block";
+ return DW_DLV_OK;
+ case DW_TAG_hi_user:
+ *s_out = "DW_TAG_hi_user";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_children_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_children_no:
+ *s_out = "DW_children_no";
+ return DW_DLV_OK;
+ case DW_children_yes:
+ *s_out = "DW_children_yes";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_FORM_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_FORM_addr:
+ *s_out = "DW_FORM_addr";
+ return DW_DLV_OK;
+ case DW_FORM_block2:
+ *s_out = "DW_FORM_block2";
+ return DW_DLV_OK;
+ case DW_FORM_block4:
+ *s_out = "DW_FORM_block4";
+ return DW_DLV_OK;
+ case DW_FORM_data2:
+ *s_out = "DW_FORM_data2";
+ return DW_DLV_OK;
+ case DW_FORM_data4:
+ *s_out = "DW_FORM_data4";
+ return DW_DLV_OK;
+ case DW_FORM_data8:
+ *s_out = "DW_FORM_data8";
+ return DW_DLV_OK;
+ case DW_FORM_string:
+ *s_out = "DW_FORM_string";
+ return DW_DLV_OK;
+ case DW_FORM_block:
+ *s_out = "DW_FORM_block";
+ return DW_DLV_OK;
+ case DW_FORM_block1:
+ *s_out = "DW_FORM_block1";
+ return DW_DLV_OK;
+ case DW_FORM_data1:
+ *s_out = "DW_FORM_data1";
+ return DW_DLV_OK;
+ case DW_FORM_flag:
+ *s_out = "DW_FORM_flag";
+ return DW_DLV_OK;
+ case DW_FORM_sdata:
+ *s_out = "DW_FORM_sdata";
+ return DW_DLV_OK;
+ case DW_FORM_strp:
+ *s_out = "DW_FORM_strp";
+ return DW_DLV_OK;
+ case DW_FORM_udata:
+ *s_out = "DW_FORM_udata";
+ return DW_DLV_OK;
+ case DW_FORM_ref_addr:
+ *s_out = "DW_FORM_ref_addr";
+ return DW_DLV_OK;
+ case DW_FORM_ref1:
+ *s_out = "DW_FORM_ref1";
+ return DW_DLV_OK;
+ case DW_FORM_ref2:
+ *s_out = "DW_FORM_ref2";
+ return DW_DLV_OK;
+ case DW_FORM_ref4:
+ *s_out = "DW_FORM_ref4";
+ return DW_DLV_OK;
+ case DW_FORM_ref8:
+ *s_out = "DW_FORM_ref8";
+ return DW_DLV_OK;
+ case DW_FORM_ref_udata:
+ *s_out = "DW_FORM_ref_udata";
+ return DW_DLV_OK;
+ case DW_FORM_indirect:
+ *s_out = "DW_FORM_indirect";
+ return DW_DLV_OK;
+ case DW_FORM_sec_offset:
+ *s_out = "DW_FORM_sec_offset";
+ return DW_DLV_OK;
+ case DW_FORM_exprloc:
+ *s_out = "DW_FORM_exprloc";
+ return DW_DLV_OK;
+ case DW_FORM_flag_present:
+ *s_out = "DW_FORM_flag_present";
+ return DW_DLV_OK;
+ case DW_FORM_ref_sig8:
+ *s_out = "DW_FORM_ref_sig8";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_AT_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_AT_sibling:
+ *s_out = "DW_AT_sibling";
+ return DW_DLV_OK;
+ case DW_AT_location:
+ *s_out = "DW_AT_location";
+ return DW_DLV_OK;
+ case DW_AT_name:
+ *s_out = "DW_AT_name";
+ return DW_DLV_OK;
+ case DW_AT_ordering:
+ *s_out = "DW_AT_ordering";
+ return DW_DLV_OK;
+ case DW_AT_subscr_data:
+ *s_out = "DW_AT_subscr_data";
+ return DW_DLV_OK;
+ case DW_AT_byte_size:
+ *s_out = "DW_AT_byte_size";
+ return DW_DLV_OK;
+ case DW_AT_bit_offset:
+ *s_out = "DW_AT_bit_offset";
+ return DW_DLV_OK;
+ case DW_AT_bit_size:
+ *s_out = "DW_AT_bit_size";
+ return DW_DLV_OK;
+ case DW_AT_element_list:
+ *s_out = "DW_AT_element_list";
+ return DW_DLV_OK;
+ case DW_AT_stmt_list:
+ *s_out = "DW_AT_stmt_list";
+ return DW_DLV_OK;
+ case DW_AT_low_pc:
+ *s_out = "DW_AT_low_pc";
+ return DW_DLV_OK;
+ case DW_AT_high_pc:
+ *s_out = "DW_AT_high_pc";
+ return DW_DLV_OK;
+ case DW_AT_language:
+ *s_out = "DW_AT_language";
+ return DW_DLV_OK;
+ case DW_AT_member:
+ *s_out = "DW_AT_member";
+ return DW_DLV_OK;
+ case DW_AT_discr:
+ *s_out = "DW_AT_discr";
+ return DW_DLV_OK;
+ case DW_AT_discr_value:
+ *s_out = "DW_AT_discr_value";
+ return DW_DLV_OK;
+ case DW_AT_visibility:
+ *s_out = "DW_AT_visibility";
+ return DW_DLV_OK;
+ case DW_AT_import:
+ *s_out = "DW_AT_import";
+ return DW_DLV_OK;
+ case DW_AT_string_length:
+ *s_out = "DW_AT_string_length";
+ return DW_DLV_OK;
+ case DW_AT_common_reference:
+ *s_out = "DW_AT_common_reference";
+ return DW_DLV_OK;
+ case DW_AT_comp_dir:
+ *s_out = "DW_AT_comp_dir";
+ return DW_DLV_OK;
+ case DW_AT_const_value:
+ *s_out = "DW_AT_const_value";
+ return DW_DLV_OK;
+ case DW_AT_containing_type:
+ *s_out = "DW_AT_containing_type";
+ return DW_DLV_OK;
+ case DW_AT_default_value:
+ *s_out = "DW_AT_default_value";
+ return DW_DLV_OK;
+ case DW_AT_inline:
+ *s_out = "DW_AT_inline";
+ return DW_DLV_OK;
+ case DW_AT_is_optional:
+ *s_out = "DW_AT_is_optional";
+ return DW_DLV_OK;
+ case DW_AT_lower_bound:
+ *s_out = "DW_AT_lower_bound";
+ return DW_DLV_OK;
+ case DW_AT_producer:
+ *s_out = "DW_AT_producer";
+ return DW_DLV_OK;
+ case DW_AT_prototyped:
+ *s_out = "DW_AT_prototyped";
+ return DW_DLV_OK;
+ case DW_AT_return_addr:
+ *s_out = "DW_AT_return_addr";
+ return DW_DLV_OK;
+ case DW_AT_start_scope:
+ *s_out = "DW_AT_start_scope";
+ return DW_DLV_OK;
+ case DW_AT_bit_stride:
+ *s_out = "DW_AT_bit_stride";
+ return DW_DLV_OK;
+ case DW_AT_upper_bound:
+ *s_out = "DW_AT_upper_bound";
+ return DW_DLV_OK;
+ case DW_AT_abstract_origin:
+ *s_out = "DW_AT_abstract_origin";
+ return DW_DLV_OK;
+ case DW_AT_accessibility:
+ *s_out = "DW_AT_accessibility";
+ return DW_DLV_OK;
+ case DW_AT_address_class:
+ *s_out = "DW_AT_address_class";
+ return DW_DLV_OK;
+ case DW_AT_artificial:
+ *s_out = "DW_AT_artificial";
+ return DW_DLV_OK;
+ case DW_AT_base_types:
+ *s_out = "DW_AT_base_types";
+ return DW_DLV_OK;
+ case DW_AT_calling_convention:
+ *s_out = "DW_AT_calling_convention";
+ return DW_DLV_OK;
+ case DW_AT_count:
+ *s_out = "DW_AT_count";
+ return DW_DLV_OK;
+ case DW_AT_data_member_location:
+ *s_out = "DW_AT_data_member_location";
+ return DW_DLV_OK;
+ case DW_AT_decl_column:
+ *s_out = "DW_AT_decl_column";
+ return DW_DLV_OK;
+ case DW_AT_decl_file:
+ *s_out = "DW_AT_decl_file";
+ return DW_DLV_OK;
+ case DW_AT_decl_line:
+ *s_out = "DW_AT_decl_line";
+ return DW_DLV_OK;
+ case DW_AT_declaration:
+ *s_out = "DW_AT_declaration";
+ return DW_DLV_OK;
+ case DW_AT_discr_list:
+ *s_out = "DW_AT_discr_list";
+ return DW_DLV_OK;
+ case DW_AT_encoding:
+ *s_out = "DW_AT_encoding";
+ return DW_DLV_OK;
+ case DW_AT_external:
+ *s_out = "DW_AT_external";
+ return DW_DLV_OK;
+ case DW_AT_frame_base:
+ *s_out = "DW_AT_frame_base";
+ return DW_DLV_OK;
+ case DW_AT_friend:
+ *s_out = "DW_AT_friend";
+ return DW_DLV_OK;
+ case DW_AT_identifier_case:
+ *s_out = "DW_AT_identifier_case";
+ return DW_DLV_OK;
+ case DW_AT_macro_info:
+ *s_out = "DW_AT_macro_info";
+ return DW_DLV_OK;
+ case DW_AT_namelist_item:
+ *s_out = "DW_AT_namelist_item";
+ return DW_DLV_OK;
+ case DW_AT_priority:
+ *s_out = "DW_AT_priority";
+ return DW_DLV_OK;
+ case DW_AT_segment:
+ *s_out = "DW_AT_segment";
+ return DW_DLV_OK;
+ case DW_AT_specification:
+ *s_out = "DW_AT_specification";
+ return DW_DLV_OK;
+ case DW_AT_static_link:
+ *s_out = "DW_AT_static_link";
+ return DW_DLV_OK;
+ case DW_AT_type:
+ *s_out = "DW_AT_type";
+ return DW_DLV_OK;
+ case DW_AT_use_location:
+ *s_out = "DW_AT_use_location";
+ return DW_DLV_OK;
+ case DW_AT_variable_parameter:
+ *s_out = "DW_AT_variable_parameter";
+ return DW_DLV_OK;
+ case DW_AT_virtuality:
+ *s_out = "DW_AT_virtuality";
+ return DW_DLV_OK;
+ case DW_AT_vtable_elem_location:
+ *s_out = "DW_AT_vtable_elem_location";
+ return DW_DLV_OK;
+ case DW_AT_allocated:
+ *s_out = "DW_AT_allocated";
+ return DW_DLV_OK;
+ case DW_AT_associated:
+ *s_out = "DW_AT_associated";
+ return DW_DLV_OK;
+ case DW_AT_data_location:
+ *s_out = "DW_AT_data_location";
+ return DW_DLV_OK;
+ case DW_AT_stride:
+ *s_out = "DW_AT_stride";
+ return DW_DLV_OK;
+ case DW_AT_entry_pc:
+ *s_out = "DW_AT_entry_pc";
+ return DW_DLV_OK;
+ case DW_AT_use_UTF8:
+ *s_out = "DW_AT_use_UTF8";
+ return DW_DLV_OK;
+ case DW_AT_extension:
+ *s_out = "DW_AT_extension";
+ return DW_DLV_OK;
+ case DW_AT_ranges:
+ *s_out = "DW_AT_ranges";
+ return DW_DLV_OK;
+ case DW_AT_trampoline:
+ *s_out = "DW_AT_trampoline";
+ return DW_DLV_OK;
+ case DW_AT_call_column:
+ *s_out = "DW_AT_call_column";
+ return DW_DLV_OK;
+ case DW_AT_call_file:
+ *s_out = "DW_AT_call_file";
+ return DW_DLV_OK;
+ case DW_AT_call_line:
+ *s_out = "DW_AT_call_line";
+ return DW_DLV_OK;
+ case DW_AT_description:
+ *s_out = "DW_AT_description";
+ return DW_DLV_OK;
+ case DW_AT_binary_scale:
+ *s_out = "DW_AT_binary_scale";
+ return DW_DLV_OK;
+ case DW_AT_decimal_scale:
+ *s_out = "DW_AT_decimal_scale";
+ return DW_DLV_OK;
+ case DW_AT_small:
+ *s_out = "DW_AT_small";
+ return DW_DLV_OK;
+ case DW_AT_decimal_sign:
+ *s_out = "DW_AT_decimal_sign";
+ return DW_DLV_OK;
+ case DW_AT_digit_count:
+ *s_out = "DW_AT_digit_count";
+ return DW_DLV_OK;
+ case DW_AT_picture_string:
+ *s_out = "DW_AT_picture_string";
+ return DW_DLV_OK;
+ case DW_AT_mutable:
+ *s_out = "DW_AT_mutable";
+ return DW_DLV_OK;
+ case DW_AT_threads_scaled:
+ *s_out = "DW_AT_threads_scaled";
+ return DW_DLV_OK;
+ case DW_AT_explicit:
+ *s_out = "DW_AT_explicit";
+ return DW_DLV_OK;
+ case DW_AT_object_pointer:
+ *s_out = "DW_AT_object_pointer";
+ return DW_DLV_OK;
+ case DW_AT_endianity:
+ *s_out = "DW_AT_endianity";
+ return DW_DLV_OK;
+ case DW_AT_elemental:
+ *s_out = "DW_AT_elemental";
+ return DW_DLV_OK;
+ case DW_AT_pure:
+ *s_out = "DW_AT_pure";
+ return DW_DLV_OK;
+ case DW_AT_recursive:
+ *s_out = "DW_AT_recursive";
+ return DW_DLV_OK;
+ case DW_AT_signature:
+ *s_out = "DW_AT_signature";
+ return DW_DLV_OK;
+ case DW_AT_main_subprogram:
+ *s_out = "DW_AT_main_subprogram";
+ return DW_DLV_OK;
+ case DW_AT_data_bit_offset:
+ *s_out = "DW_AT_data_bit_offset";
+ return DW_DLV_OK;
+ case DW_AT_const_expr:
+ *s_out = "DW_AT_const_expr";
+ return DW_DLV_OK;
+ case DW_AT_enum_class:
+ *s_out = "DW_AT_enum_class";
+ return DW_DLV_OK;
+ case DW_AT_linkage_name:
+ *s_out = "DW_AT_linkage_name";
+ return DW_DLV_OK;
+ case DW_AT_lo_user:
+ *s_out = "DW_AT_lo_user";
+ return DW_DLV_OK;
+ case DW_AT_HP_unmodifiable:
+ *s_out = "DW_AT_HP_unmodifiable";
+ return DW_DLV_OK;
+ case DW_AT_MIPS_loop_begin:
+ *s_out = "DW_AT_MIPS_loop_begin";
+ return DW_DLV_OK;
+ case DW_AT_CPQ_split_lifetimes_var:
+ *s_out = "DW_AT_CPQ_split_lifetimes_var";
+ return DW_DLV_OK;
+ case DW_AT_MIPS_epilog_begin:
+ *s_out = "DW_AT_MIPS_epilog_begin";
+ return DW_DLV_OK;
+ case DW_AT_CPQ_prologue_length:
+ *s_out = "DW_AT_CPQ_prologue_length";
+ return DW_DLV_OK;
+ case DW_AT_MIPS_software_pipeline_depth:
+ *s_out = "DW_AT_MIPS_software_pipeline_depth";
+ return DW_DLV_OK;
+ case DW_AT_MIPS_linkage_name:
+ *s_out = "DW_AT_MIPS_linkage_name";
+ return DW_DLV_OK;
+ case DW_AT_MIPS_stride:
+ *s_out = "DW_AT_MIPS_stride";
+ return DW_DLV_OK;
+ case DW_AT_MIPS_abstract_name:
+ *s_out = "DW_AT_MIPS_abstract_name";
+ return DW_DLV_OK;
+ case DW_AT_MIPS_clone_origin:
+ *s_out = "DW_AT_MIPS_clone_origin";
+ return DW_DLV_OK;
+ case DW_AT_MIPS_has_inlines:
+ *s_out = "DW_AT_MIPS_has_inlines";
+ return DW_DLV_OK;
+ case DW_AT_MIPS_stride_byte:
+ *s_out = "DW_AT_MIPS_stride_byte";
+ return DW_DLV_OK;
+ case DW_AT_MIPS_stride_elem:
+ *s_out = "DW_AT_MIPS_stride_elem";
+ return DW_DLV_OK;
+ case DW_AT_MIPS_ptr_dopetype:
+ *s_out = "DW_AT_MIPS_ptr_dopetype";
+ return DW_DLV_OK;
+ case DW_AT_MIPS_allocatable_dopetype:
+ *s_out = "DW_AT_MIPS_allocatable_dopetype";
+ return DW_DLV_OK;
+ case DW_AT_MIPS_assumed_shape_dopetype:
+ *s_out = "DW_AT_MIPS_assumed_shape_dopetype";
+ return DW_DLV_OK;
+ case DW_AT_HP_proc_per_section:
+ *s_out = "DW_AT_HP_proc_per_section";
+ return DW_DLV_OK;
+ case DW_AT_HP_raw_data_ptr:
+ *s_out = "DW_AT_HP_raw_data_ptr";
+ return DW_DLV_OK;
+ case DW_AT_HP_pass_by_reference:
+ *s_out = "DW_AT_HP_pass_by_reference";
+ return DW_DLV_OK;
+ case DW_AT_HP_opt_level:
+ *s_out = "DW_AT_HP_opt_level";
+ return DW_DLV_OK;
+ case DW_AT_HP_prof_version_id:
+ *s_out = "DW_AT_HP_prof_version_id";
+ return DW_DLV_OK;
+ case DW_AT_HP_opt_flags:
+ *s_out = "DW_AT_HP_opt_flags";
+ return DW_DLV_OK;
+ case DW_AT_HP_cold_region_low_pc:
+ *s_out = "DW_AT_HP_cold_region_low_pc";
+ return DW_DLV_OK;
+ case DW_AT_HP_cold_region_high_pc:
+ *s_out = "DW_AT_HP_cold_region_high_pc";
+ return DW_DLV_OK;
+ case DW_AT_HP_all_variables_modifiable:
+ *s_out = "DW_AT_HP_all_variables_modifiable";
+ return DW_DLV_OK;
+ case DW_AT_HP_linkage_name:
+ *s_out = "DW_AT_HP_linkage_name";
+ return DW_DLV_OK;
+ case DW_AT_HP_prof_flags:
+ *s_out = "DW_AT_HP_prof_flags";
+ return DW_DLV_OK;
+ case DW_AT_INTEL_other_endian:
+ *s_out = "DW_AT_INTEL_other_endian";
+ return DW_DLV_OK;
+ case DW_AT_sf_names:
+ *s_out = "DW_AT_sf_names";
+ return DW_DLV_OK;
+ case DW_AT_src_info:
+ *s_out = "DW_AT_src_info";
+ return DW_DLV_OK;
+ case DW_AT_mac_info:
+ *s_out = "DW_AT_mac_info";
+ return DW_DLV_OK;
+ case DW_AT_src_coords:
+ *s_out = "DW_AT_src_coords";
+ return DW_DLV_OK;
+ case DW_AT_body_begin:
+ *s_out = "DW_AT_body_begin";
+ return DW_DLV_OK;
+ case DW_AT_body_end:
+ *s_out = "DW_AT_body_end";
+ return DW_DLV_OK;
+ case DW_AT_GNU_vector:
+ *s_out = "DW_AT_GNU_vector";
+ return DW_DLV_OK;
+ case DW_AT_GNU_template_name:
+ *s_out = "DW_AT_GNU_template_name";
+ return DW_DLV_OK;
+ case DW_AT_VMS_rtnbeg_pd_address:
+ *s_out = "DW_AT_VMS_rtnbeg_pd_address";
+ return DW_DLV_OK;
+ case DW_AT_SUN_alignment:
+ *s_out = "DW_AT_SUN_alignment";
+ return DW_DLV_OK;
+ case DW_AT_SUN_vtable:
+ *s_out = "DW_AT_SUN_vtable";
+ return DW_DLV_OK;
+ case DW_AT_SUN_count_guarantee:
+ *s_out = "DW_AT_SUN_count_guarantee";
+ return DW_DLV_OK;
+ case DW_AT_SUN_command_line:
+ *s_out = "DW_AT_SUN_command_line";
+ return DW_DLV_OK;
+ case DW_AT_SUN_vbase:
+ *s_out = "DW_AT_SUN_vbase";
+ return DW_DLV_OK;
+ case DW_AT_SUN_compile_options:
+ *s_out = "DW_AT_SUN_compile_options";
+ return DW_DLV_OK;
+ case DW_AT_SUN_language:
+ *s_out = "DW_AT_SUN_language";
+ return DW_DLV_OK;
+ case DW_AT_SUN_browser_file:
+ *s_out = "DW_AT_SUN_browser_file";
+ return DW_DLV_OK;
+ case DW_AT_SUN_vtable_abi:
+ *s_out = "DW_AT_SUN_vtable_abi";
+ return DW_DLV_OK;
+ case DW_AT_SUN_func_offsets:
+ *s_out = "DW_AT_SUN_func_offsets";
+ return DW_DLV_OK;
+ case DW_AT_SUN_cf_kind:
+ *s_out = "DW_AT_SUN_cf_kind";
+ return DW_DLV_OK;
+ case DW_AT_SUN_vtable_index:
+ *s_out = "DW_AT_SUN_vtable_index";
+ return DW_DLV_OK;
+ case DW_AT_SUN_omp_tpriv_addr:
+ *s_out = "DW_AT_SUN_omp_tpriv_addr";
+ return DW_DLV_OK;
+ case DW_AT_SUN_omp_child_func:
+ *s_out = "DW_AT_SUN_omp_child_func";
+ return DW_DLV_OK;
+ case DW_AT_SUN_func_offset:
+ *s_out = "DW_AT_SUN_func_offset";
+ return DW_DLV_OK;
+ case DW_AT_SUN_memop_type_ref:
+ *s_out = "DW_AT_SUN_memop_type_ref";
+ return DW_DLV_OK;
+ case DW_AT_SUN_profile_id:
+ *s_out = "DW_AT_SUN_profile_id";
+ return DW_DLV_OK;
+ case DW_AT_SUN_memop_signature:
+ *s_out = "DW_AT_SUN_memop_signature";
+ return DW_DLV_OK;
+ case DW_AT_SUN_obj_dir:
+ *s_out = "DW_AT_SUN_obj_dir";
+ return DW_DLV_OK;
+ case DW_AT_SUN_obj_file:
+ *s_out = "DW_AT_SUN_obj_file";
+ return DW_DLV_OK;
+ case DW_AT_SUN_original_name:
+ *s_out = "DW_AT_SUN_original_name";
+ return DW_DLV_OK;
+ case DW_AT_SUN_hwcprof_signature:
+ *s_out = "DW_AT_SUN_hwcprof_signature";
+ return DW_DLV_OK;
+ case DW_AT_SUN_amd64_parmdump:
+ *s_out = "DW_AT_SUN_amd64_parmdump";
+ return DW_DLV_OK;
+ case DW_AT_SUN_part_link_name:
+ *s_out = "DW_AT_SUN_part_link_name";
+ return DW_DLV_OK;
+ case DW_AT_SUN_link_name:
+ *s_out = "DW_AT_SUN_link_name";
+ return DW_DLV_OK;
+ case DW_AT_SUN_pass_with_const:
+ *s_out = "DW_AT_SUN_pass_with_const";
+ return DW_DLV_OK;
+ case DW_AT_SUN_return_with_const:
+ *s_out = "DW_AT_SUN_return_with_const";
+ return DW_DLV_OK;
+ case DW_AT_SUN_import_by_name:
+ *s_out = "DW_AT_SUN_import_by_name";
+ return DW_DLV_OK;
+ case DW_AT_SUN_f90_pointer:
+ *s_out = "DW_AT_SUN_f90_pointer";
+ return DW_DLV_OK;
+ case DW_AT_SUN_pass_by_ref:
+ *s_out = "DW_AT_SUN_pass_by_ref";
+ return DW_DLV_OK;
+ case DW_AT_SUN_f90_allocatable:
+ *s_out = "DW_AT_SUN_f90_allocatable";
+ return DW_DLV_OK;
+ case DW_AT_SUN_f90_assumed_shape_array:
+ *s_out = "DW_AT_SUN_f90_assumed_shape_array";
+ return DW_DLV_OK;
+ case DW_AT_SUN_c_vla:
+ *s_out = "DW_AT_SUN_c_vla";
+ return DW_DLV_OK;
+ case DW_AT_SUN_return_value_ptr:
+ *s_out = "DW_AT_SUN_return_value_ptr";
+ return DW_DLV_OK;
+ case DW_AT_SUN_dtor_start:
+ *s_out = "DW_AT_SUN_dtor_start";
+ return DW_DLV_OK;
+ case DW_AT_SUN_dtor_length:
+ *s_out = "DW_AT_SUN_dtor_length";
+ return DW_DLV_OK;
+ case DW_AT_SUN_dtor_state_initial:
+ *s_out = "DW_AT_SUN_dtor_state_initial";
+ return DW_DLV_OK;
+ case DW_AT_SUN_dtor_state_final:
+ *s_out = "DW_AT_SUN_dtor_state_final";
+ return DW_DLV_OK;
+ case DW_AT_SUN_dtor_state_deltas:
+ *s_out = "DW_AT_SUN_dtor_state_deltas";
+ return DW_DLV_OK;
+ case DW_AT_SUN_import_by_lname:
+ *s_out = "DW_AT_SUN_import_by_lname";
+ return DW_DLV_OK;
+ case DW_AT_SUN_f90_use_only:
+ *s_out = "DW_AT_SUN_f90_use_only";
+ return DW_DLV_OK;
+ case DW_AT_SUN_namelist_spec:
+ *s_out = "DW_AT_SUN_namelist_spec";
+ return DW_DLV_OK;
+ case DW_AT_SUN_is_omp_child_func:
+ *s_out = "DW_AT_SUN_is_omp_child_func";
+ return DW_DLV_OK;
+ case DW_AT_SUN_fortran_main_alias:
+ *s_out = "DW_AT_SUN_fortran_main_alias";
+ return DW_DLV_OK;
+ case DW_AT_SUN_fortran_based:
+ *s_out = "DW_AT_SUN_fortran_based";
+ return DW_DLV_OK;
+ case DW_AT_ALTIUM_loclist:
+ *s_out = "DW_AT_ALTIUM_loclist";
+ return DW_DLV_OK;
+ case DW_AT_upc_threads_scaled:
+ *s_out = "DW_AT_upc_threads_scaled";
+ return DW_DLV_OK;
+ case DW_AT_PGI_lbase:
+ *s_out = "DW_AT_PGI_lbase";
+ return DW_DLV_OK;
+ case DW_AT_PGI_soffset:
+ *s_out = "DW_AT_PGI_soffset";
+ return DW_DLV_OK;
+ case DW_AT_PGI_lstride:
+ *s_out = "DW_AT_PGI_lstride";
+ return DW_DLV_OK;
+ case DW_AT_APPLE_closure:
+ *s_out = "DW_AT_APPLE_closure";
+ return DW_DLV_OK;
+ case DW_AT_APPLE_major_runtime_vers:
+ *s_out = "DW_AT_APPLE_major_runtime_vers";
+ return DW_DLV_OK;
+ case DW_AT_APPLE_runtime_class:
+ *s_out = "DW_AT_APPLE_runtime_class";
+ return DW_DLV_OK;
+ case DW_AT_hi_user:
+ *s_out = "DW_AT_hi_user";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_OP_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_OP_addr:
+ *s_out = "DW_OP_addr";
+ return DW_DLV_OK;
+ case DW_OP_deref:
+ *s_out = "DW_OP_deref";
+ return DW_DLV_OK;
+ case DW_OP_const1u:
+ *s_out = "DW_OP_const1u";
+ return DW_DLV_OK;
+ case DW_OP_const1s:
+ *s_out = "DW_OP_const1s";
+ return DW_DLV_OK;
+ case DW_OP_const2u:
+ *s_out = "DW_OP_const2u";
+ return DW_DLV_OK;
+ case DW_OP_const2s:
+ *s_out = "DW_OP_const2s";
+ return DW_DLV_OK;
+ case DW_OP_const4u:
+ *s_out = "DW_OP_const4u";
+ return DW_DLV_OK;
+ case DW_OP_const4s:
+ *s_out = "DW_OP_const4s";
+ return DW_DLV_OK;
+ case DW_OP_const8u:
+ *s_out = "DW_OP_const8u";
+ return DW_DLV_OK;
+ case DW_OP_const8s:
+ *s_out = "DW_OP_const8s";
+ return DW_DLV_OK;
+ case DW_OP_constu:
+ *s_out = "DW_OP_constu";
+ return DW_DLV_OK;
+ case DW_OP_consts:
+ *s_out = "DW_OP_consts";
+ return DW_DLV_OK;
+ case DW_OP_dup:
+ *s_out = "DW_OP_dup";
+ return DW_DLV_OK;
+ case DW_OP_drop:
+ *s_out = "DW_OP_drop";
+ return DW_DLV_OK;
+ case DW_OP_over:
+ *s_out = "DW_OP_over";
+ return DW_DLV_OK;
+ case DW_OP_pick:
+ *s_out = "DW_OP_pick";
+ return DW_DLV_OK;
+ case DW_OP_swap:
+ *s_out = "DW_OP_swap";
+ return DW_DLV_OK;
+ case DW_OP_rot:
+ *s_out = "DW_OP_rot";
+ return DW_DLV_OK;
+ case DW_OP_xderef:
+ *s_out = "DW_OP_xderef";
+ return DW_DLV_OK;
+ case DW_OP_abs:
+ *s_out = "DW_OP_abs";
+ return DW_DLV_OK;
+ case DW_OP_and:
+ *s_out = "DW_OP_and";
+ return DW_DLV_OK;
+ case DW_OP_div:
+ *s_out = "DW_OP_div";
+ return DW_DLV_OK;
+ case DW_OP_minus:
+ *s_out = "DW_OP_minus";
+ return DW_DLV_OK;
+ case DW_OP_mod:
+ *s_out = "DW_OP_mod";
+ return DW_DLV_OK;
+ case DW_OP_mul:
+ *s_out = "DW_OP_mul";
+ return DW_DLV_OK;
+ case DW_OP_neg:
+ *s_out = "DW_OP_neg";
+ return DW_DLV_OK;
+ case DW_OP_not:
+ *s_out = "DW_OP_not";
+ return DW_DLV_OK;
+ case DW_OP_or:
+ *s_out = "DW_OP_or";
+ return DW_DLV_OK;
+ case DW_OP_plus:
+ *s_out = "DW_OP_plus";
+ return DW_DLV_OK;
+ case DW_OP_plus_uconst:
+ *s_out = "DW_OP_plus_uconst";
+ return DW_DLV_OK;
+ case DW_OP_shl:
+ *s_out = "DW_OP_shl";
+ return DW_DLV_OK;
+ case DW_OP_shr:
+ *s_out = "DW_OP_shr";
+ return DW_DLV_OK;
+ case DW_OP_shra:
+ *s_out = "DW_OP_shra";
+ return DW_DLV_OK;
+ case DW_OP_xor:
+ *s_out = "DW_OP_xor";
+ return DW_DLV_OK;
+ case DW_OP_bra:
+ *s_out = "DW_OP_bra";
+ return DW_DLV_OK;
+ case DW_OP_eq:
+ *s_out = "DW_OP_eq";
+ return DW_DLV_OK;
+ case DW_OP_ge:
+ *s_out = "DW_OP_ge";
+ return DW_DLV_OK;
+ case DW_OP_gt:
+ *s_out = "DW_OP_gt";
+ return DW_DLV_OK;
+ case DW_OP_le:
+ *s_out = "DW_OP_le";
+ return DW_DLV_OK;
+ case DW_OP_lt:
+ *s_out = "DW_OP_lt";
+ return DW_DLV_OK;
+ case DW_OP_ne:
+ *s_out = "DW_OP_ne";
+ return DW_DLV_OK;
+ case DW_OP_skip:
+ *s_out = "DW_OP_skip";
+ return DW_DLV_OK;
+ case DW_OP_lit0:
+ *s_out = "DW_OP_lit0";
+ return DW_DLV_OK;
+ case DW_OP_lit1:
+ *s_out = "DW_OP_lit1";
+ return DW_DLV_OK;
+ case DW_OP_lit2:
+ *s_out = "DW_OP_lit2";
+ return DW_DLV_OK;
+ case DW_OP_lit3:
+ *s_out = "DW_OP_lit3";
+ return DW_DLV_OK;
+ case DW_OP_lit4:
+ *s_out = "DW_OP_lit4";
+ return DW_DLV_OK;
+ case DW_OP_lit5:
+ *s_out = "DW_OP_lit5";
+ return DW_DLV_OK;
+ case DW_OP_lit6:
+ *s_out = "DW_OP_lit6";
+ return DW_DLV_OK;
+ case DW_OP_lit7:
+ *s_out = "DW_OP_lit7";
+ return DW_DLV_OK;
+ case DW_OP_lit8:
+ *s_out = "DW_OP_lit8";
+ return DW_DLV_OK;
+ case DW_OP_lit9:
+ *s_out = "DW_OP_lit9";
+ return DW_DLV_OK;
+ case DW_OP_lit10:
+ *s_out = "DW_OP_lit10";
+ return DW_DLV_OK;
+ case DW_OP_lit11:
+ *s_out = "DW_OP_lit11";
+ return DW_DLV_OK;
+ case DW_OP_lit12:
+ *s_out = "DW_OP_lit12";
+ return DW_DLV_OK;
+ case DW_OP_lit13:
+ *s_out = "DW_OP_lit13";
+ return DW_DLV_OK;
+ case DW_OP_lit14:
+ *s_out = "DW_OP_lit14";
+ return DW_DLV_OK;
+ case DW_OP_lit15:
+ *s_out = "DW_OP_lit15";
+ return DW_DLV_OK;
+ case DW_OP_lit16:
+ *s_out = "DW_OP_lit16";
+ return DW_DLV_OK;
+ case DW_OP_lit17:
+ *s_out = "DW_OP_lit17";
+ return DW_DLV_OK;
+ case DW_OP_lit18:
+ *s_out = "DW_OP_lit18";
+ return DW_DLV_OK;
+ case DW_OP_lit19:
+ *s_out = "DW_OP_lit19";
+ return DW_DLV_OK;
+ case DW_OP_lit20:
+ *s_out = "DW_OP_lit20";
+ return DW_DLV_OK;
+ case DW_OP_lit21:
+ *s_out = "DW_OP_lit21";
+ return DW_DLV_OK;
+ case DW_OP_lit22:
+ *s_out = "DW_OP_lit22";
+ return DW_DLV_OK;
+ case DW_OP_lit23:
+ *s_out = "DW_OP_lit23";
+ return DW_DLV_OK;
+ case DW_OP_lit24:
+ *s_out = "DW_OP_lit24";
+ return DW_DLV_OK;
+ case DW_OP_lit25:
+ *s_out = "DW_OP_lit25";
+ return DW_DLV_OK;
+ case DW_OP_lit26:
+ *s_out = "DW_OP_lit26";
+ return DW_DLV_OK;
+ case DW_OP_lit27:
+ *s_out = "DW_OP_lit27";
+ return DW_DLV_OK;
+ case DW_OP_lit28:
+ *s_out = "DW_OP_lit28";
+ return DW_DLV_OK;
+ case DW_OP_lit29:
+ *s_out = "DW_OP_lit29";
+ return DW_DLV_OK;
+ case DW_OP_lit30:
+ *s_out = "DW_OP_lit30";
+ return DW_DLV_OK;
+ case DW_OP_lit31:
+ *s_out = "DW_OP_lit31";
+ return DW_DLV_OK;
+ case DW_OP_reg0:
+ *s_out = "DW_OP_reg0";
+ return DW_DLV_OK;
+ case DW_OP_reg1:
+ *s_out = "DW_OP_reg1";
+ return DW_DLV_OK;
+ case DW_OP_reg2:
+ *s_out = "DW_OP_reg2";
+ return DW_DLV_OK;
+ case DW_OP_reg3:
+ *s_out = "DW_OP_reg3";
+ return DW_DLV_OK;
+ case DW_OP_reg4:
+ *s_out = "DW_OP_reg4";
+ return DW_DLV_OK;
+ case DW_OP_reg5:
+ *s_out = "DW_OP_reg5";
+ return DW_DLV_OK;
+ case DW_OP_reg6:
+ *s_out = "DW_OP_reg6";
+ return DW_DLV_OK;
+ case DW_OP_reg7:
+ *s_out = "DW_OP_reg7";
+ return DW_DLV_OK;
+ case DW_OP_reg8:
+ *s_out = "DW_OP_reg8";
+ return DW_DLV_OK;
+ case DW_OP_reg9:
+ *s_out = "DW_OP_reg9";
+ return DW_DLV_OK;
+ case DW_OP_reg10:
+ *s_out = "DW_OP_reg10";
+ return DW_DLV_OK;
+ case DW_OP_reg11:
+ *s_out = "DW_OP_reg11";
+ return DW_DLV_OK;
+ case DW_OP_reg12:
+ *s_out = "DW_OP_reg12";
+ return DW_DLV_OK;
+ case DW_OP_reg13:
+ *s_out = "DW_OP_reg13";
+ return DW_DLV_OK;
+ case DW_OP_reg14:
+ *s_out = "DW_OP_reg14";
+ return DW_DLV_OK;
+ case DW_OP_reg15:
+ *s_out = "DW_OP_reg15";
+ return DW_DLV_OK;
+ case DW_OP_reg16:
+ *s_out = "DW_OP_reg16";
+ return DW_DLV_OK;
+ case DW_OP_reg17:
+ *s_out = "DW_OP_reg17";
+ return DW_DLV_OK;
+ case DW_OP_reg18:
+ *s_out = "DW_OP_reg18";
+ return DW_DLV_OK;
+ case DW_OP_reg19:
+ *s_out = "DW_OP_reg19";
+ return DW_DLV_OK;
+ case DW_OP_reg20:
+ *s_out = "DW_OP_reg20";
+ return DW_DLV_OK;
+ case DW_OP_reg21:
+ *s_out = "DW_OP_reg21";
+ return DW_DLV_OK;
+ case DW_OP_reg22:
+ *s_out = "DW_OP_reg22";
+ return DW_DLV_OK;
+ case DW_OP_reg23:
+ *s_out = "DW_OP_reg23";
+ return DW_DLV_OK;
+ case DW_OP_reg24:
+ *s_out = "DW_OP_reg24";
+ return DW_DLV_OK;
+ case DW_OP_reg25:
+ *s_out = "DW_OP_reg25";
+ return DW_DLV_OK;
+ case DW_OP_reg26:
+ *s_out = "DW_OP_reg26";
+ return DW_DLV_OK;
+ case DW_OP_reg27:
+ *s_out = "DW_OP_reg27";
+ return DW_DLV_OK;
+ case DW_OP_reg28:
+ *s_out = "DW_OP_reg28";
+ return DW_DLV_OK;
+ case DW_OP_reg29:
+ *s_out = "DW_OP_reg29";
+ return DW_DLV_OK;
+ case DW_OP_reg30:
+ *s_out = "DW_OP_reg30";
+ return DW_DLV_OK;
+ case DW_OP_reg31:
+ *s_out = "DW_OP_reg31";
+ return DW_DLV_OK;
+ case DW_OP_breg0:
+ *s_out = "DW_OP_breg0";
+ return DW_DLV_OK;
+ case DW_OP_breg1:
+ *s_out = "DW_OP_breg1";
+ return DW_DLV_OK;
+ case DW_OP_breg2:
+ *s_out = "DW_OP_breg2";
+ return DW_DLV_OK;
+ case DW_OP_breg3:
+ *s_out = "DW_OP_breg3";
+ return DW_DLV_OK;
+ case DW_OP_breg4:
+ *s_out = "DW_OP_breg4";
+ return DW_DLV_OK;
+ case DW_OP_breg5:
+ *s_out = "DW_OP_breg5";
+ return DW_DLV_OK;
+ case DW_OP_breg6:
+ *s_out = "DW_OP_breg6";
+ return DW_DLV_OK;
+ case DW_OP_breg7:
+ *s_out = "DW_OP_breg7";
+ return DW_DLV_OK;
+ case DW_OP_breg8:
+ *s_out = "DW_OP_breg8";
+ return DW_DLV_OK;
+ case DW_OP_breg9:
+ *s_out = "DW_OP_breg9";
+ return DW_DLV_OK;
+ case DW_OP_breg10:
+ *s_out = "DW_OP_breg10";
+ return DW_DLV_OK;
+ case DW_OP_breg11:
+ *s_out = "DW_OP_breg11";
+ return DW_DLV_OK;
+ case DW_OP_breg12:
+ *s_out = "DW_OP_breg12";
+ return DW_DLV_OK;
+ case DW_OP_breg13:
+ *s_out = "DW_OP_breg13";
+ return DW_DLV_OK;
+ case DW_OP_breg14:
+ *s_out = "DW_OP_breg14";
+ return DW_DLV_OK;
+ case DW_OP_breg15:
+ *s_out = "DW_OP_breg15";
+ return DW_DLV_OK;
+ case DW_OP_breg16:
+ *s_out = "DW_OP_breg16";
+ return DW_DLV_OK;
+ case DW_OP_breg17:
+ *s_out = "DW_OP_breg17";
+ return DW_DLV_OK;
+ case DW_OP_breg18:
+ *s_out = "DW_OP_breg18";
+ return DW_DLV_OK;
+ case DW_OP_breg19:
+ *s_out = "DW_OP_breg19";
+ return DW_DLV_OK;
+ case DW_OP_breg20:
+ *s_out = "DW_OP_breg20";
+ return DW_DLV_OK;
+ case DW_OP_breg21:
+ *s_out = "DW_OP_breg21";
+ return DW_DLV_OK;
+ case DW_OP_breg22:
+ *s_out = "DW_OP_breg22";
+ return DW_DLV_OK;
+ case DW_OP_breg23:
+ *s_out = "DW_OP_breg23";
+ return DW_DLV_OK;
+ case DW_OP_breg24:
+ *s_out = "DW_OP_breg24";
+ return DW_DLV_OK;
+ case DW_OP_breg25:
+ *s_out = "DW_OP_breg25";
+ return DW_DLV_OK;
+ case DW_OP_breg26:
+ *s_out = "DW_OP_breg26";
+ return DW_DLV_OK;
+ case DW_OP_breg27:
+ *s_out = "DW_OP_breg27";
+ return DW_DLV_OK;
+ case DW_OP_breg28:
+ *s_out = "DW_OP_breg28";
+ return DW_DLV_OK;
+ case DW_OP_breg29:
+ *s_out = "DW_OP_breg29";
+ return DW_DLV_OK;
+ case DW_OP_breg30:
+ *s_out = "DW_OP_breg30";
+ return DW_DLV_OK;
+ case DW_OP_breg31:
+ *s_out = "DW_OP_breg31";
+ return DW_DLV_OK;
+ case DW_OP_regx:
+ *s_out = "DW_OP_regx";
+ return DW_DLV_OK;
+ case DW_OP_fbreg:
+ *s_out = "DW_OP_fbreg";
+ return DW_DLV_OK;
+ case DW_OP_bregx:
+ *s_out = "DW_OP_bregx";
+ return DW_DLV_OK;
+ case DW_OP_piece:
+ *s_out = "DW_OP_piece";
+ return DW_DLV_OK;
+ case DW_OP_deref_size:
+ *s_out = "DW_OP_deref_size";
+ return DW_DLV_OK;
+ case DW_OP_xderef_size:
+ *s_out = "DW_OP_xderef_size";
+ return DW_DLV_OK;
+ case DW_OP_nop:
+ *s_out = "DW_OP_nop";
+ return DW_DLV_OK;
+ case DW_OP_push_object_address:
+ *s_out = "DW_OP_push_object_address";
+ return DW_DLV_OK;
+ case DW_OP_call2:
+ *s_out = "DW_OP_call2";
+ return DW_DLV_OK;
+ case DW_OP_call4:
+ *s_out = "DW_OP_call4";
+ return DW_DLV_OK;
+ case DW_OP_call_ref:
+ *s_out = "DW_OP_call_ref";
+ return DW_DLV_OK;
+ case DW_OP_form_tls_address:
+ *s_out = "DW_OP_form_tls_address";
+ return DW_DLV_OK;
+ case DW_OP_call_frame_cfa:
+ *s_out = "DW_OP_call_frame_cfa";
+ return DW_DLV_OK;
+ case DW_OP_bit_piece:
+ *s_out = "DW_OP_bit_piece";
+ return DW_DLV_OK;
+ case DW_OP_implicit_value:
+ *s_out = "DW_OP_implicit_value";
+ return DW_DLV_OK;
+ case DW_OP_stack_value:
+ *s_out = "DW_OP_stack_value";
+ return DW_DLV_OK;
+ case DW_OP_lo_user:
+ *s_out = "DW_OP_lo_user";
+ return DW_DLV_OK;
+ case DW_OP_HP_is_value:
+ *s_out = "DW_OP_HP_is_value";
+ return DW_DLV_OK;
+ case DW_OP_HP_fltconst4:
+ *s_out = "DW_OP_HP_fltconst4";
+ return DW_DLV_OK;
+ case DW_OP_HP_fltconst8:
+ *s_out = "DW_OP_HP_fltconst8";
+ return DW_DLV_OK;
+ case DW_OP_HP_mod_range:
+ *s_out = "DW_OP_HP_mod_range";
+ return DW_DLV_OK;
+ case DW_OP_HP_unmod_range:
+ *s_out = "DW_OP_HP_unmod_range";
+ return DW_DLV_OK;
+ case DW_OP_HP_tls:
+ *s_out = "DW_OP_HP_tls";
+ return DW_DLV_OK;
+ case DW_OP_INTEL_bit_piece:
+ *s_out = "DW_OP_INTEL_bit_piece";
+ return DW_DLV_OK;
+ case DW_OP_APPLE_uninit:
+ *s_out = "DW_OP_APPLE_uninit";
+ return DW_DLV_OK;
+ case DW_OP_hi_user:
+ *s_out = "DW_OP_hi_user";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_ATE_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_ATE_address:
+ *s_out = "DW_ATE_address";
+ return DW_DLV_OK;
+ case DW_ATE_boolean:
+ *s_out = "DW_ATE_boolean";
+ return DW_DLV_OK;
+ case DW_ATE_complex_float:
+ *s_out = "DW_ATE_complex_float";
+ return DW_DLV_OK;
+ case DW_ATE_float:
+ *s_out = "DW_ATE_float";
+ return DW_DLV_OK;
+ case DW_ATE_signed:
+ *s_out = "DW_ATE_signed";
+ return DW_DLV_OK;
+ case DW_ATE_signed_char:
+ *s_out = "DW_ATE_signed_char";
+ return DW_DLV_OK;
+ case DW_ATE_unsigned:
+ *s_out = "DW_ATE_unsigned";
+ return DW_DLV_OK;
+ case DW_ATE_unsigned_char:
+ *s_out = "DW_ATE_unsigned_char";
+ return DW_DLV_OK;
+ case DW_ATE_imaginary_float:
+ *s_out = "DW_ATE_imaginary_float";
+ return DW_DLV_OK;
+ case DW_ATE_packed_decimal:
+ *s_out = "DW_ATE_packed_decimal";
+ return DW_DLV_OK;
+ case DW_ATE_numeric_string:
+ *s_out = "DW_ATE_numeric_string";
+ return DW_DLV_OK;
+ case DW_ATE_edited:
+ *s_out = "DW_ATE_edited";
+ return DW_DLV_OK;
+ case DW_ATE_signed_fixed:
+ *s_out = "DW_ATE_signed_fixed";
+ return DW_DLV_OK;
+ case DW_ATE_unsigned_fixed:
+ *s_out = "DW_ATE_unsigned_fixed";
+ return DW_DLV_OK;
+ case DW_ATE_decimal_float:
+ *s_out = "DW_ATE_decimal_float";
+ return DW_DLV_OK;
+ case DW_ATE_HP_float80:
+ *s_out = "DW_ATE_HP_float80";
+ return DW_DLV_OK;
+ case DW_ATE_HP_complex_float80:
+ *s_out = "DW_ATE_HP_complex_float80";
+ return DW_DLV_OK;
+ case DW_ATE_HP_float128:
+ *s_out = "DW_ATE_HP_float128";
+ return DW_DLV_OK;
+ case DW_ATE_HP_complex_float128:
+ *s_out = "DW_ATE_HP_complex_float128";
+ return DW_DLV_OK;
+ case DW_ATE_HP_floathpintel:
+ *s_out = "DW_ATE_HP_floathpintel";
+ return DW_DLV_OK;
+ case DW_ATE_HP_imaginary_float80:
+ *s_out = "DW_ATE_HP_imaginary_float80";
+ return DW_DLV_OK;
+ case DW_ATE_HP_imaginary_float128:
+ *s_out = "DW_ATE_HP_imaginary_float128";
+ return DW_DLV_OK;
+ case DW_ATE_SUN_interval_float:
+ *s_out = "DW_ATE_SUN_interval_float";
+ return DW_DLV_OK;
+ case DW_ATE_SUN_imaginary_float:
+ *s_out = "DW_ATE_SUN_imaginary_float";
+ return DW_DLV_OK;
+ case DW_ATE_hi_user:
+ *s_out = "DW_ATE_hi_user";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_DS_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_DS_unsigned:
+ *s_out = "DW_DS_unsigned";
+ return DW_DLV_OK;
+ case DW_DS_leading_overpunch:
+ *s_out = "DW_DS_leading_overpunch";
+ return DW_DLV_OK;
+ case DW_DS_trailing_overpunch:
+ *s_out = "DW_DS_trailing_overpunch";
+ return DW_DLV_OK;
+ case DW_DS_leading_separate:
+ *s_out = "DW_DS_leading_separate";
+ return DW_DLV_OK;
+ case DW_DS_trailing_separate:
+ *s_out = "DW_DS_trailing_separate";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_END_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_END_default:
+ *s_out = "DW_END_default";
+ return DW_DLV_OK;
+ case DW_END_big:
+ *s_out = "DW_END_big";
+ return DW_DLV_OK;
+ case DW_END_little:
+ *s_out = "DW_END_little";
+ return DW_DLV_OK;
+ case DW_END_lo_user:
+ *s_out = "DW_END_lo_user";
+ return DW_DLV_OK;
+ case DW_END_hi_user:
+ *s_out = "DW_END_hi_user";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_ATCF_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_ATCF_lo_user:
+ *s_out = "DW_ATCF_lo_user";
+ return DW_DLV_OK;
+ case DW_ATCF_SUN_mop_bitfield:
+ *s_out = "DW_ATCF_SUN_mop_bitfield";
+ return DW_DLV_OK;
+ case DW_ATCF_SUN_mop_spill:
+ *s_out = "DW_ATCF_SUN_mop_spill";
+ return DW_DLV_OK;
+ case DW_ATCF_SUN_mop_scopy:
+ *s_out = "DW_ATCF_SUN_mop_scopy";
+ return DW_DLV_OK;
+ case DW_ATCF_SUN_func_start:
+ *s_out = "DW_ATCF_SUN_func_start";
+ return DW_DLV_OK;
+ case DW_ATCF_SUN_end_ctors:
+ *s_out = "DW_ATCF_SUN_end_ctors";
+ return DW_DLV_OK;
+ case DW_ATCF_SUN_branch_target:
+ *s_out = "DW_ATCF_SUN_branch_target";
+ return DW_DLV_OK;
+ case DW_ATCF_SUN_mop_stack_probe:
+ *s_out = "DW_ATCF_SUN_mop_stack_probe";
+ return DW_DLV_OK;
+ case DW_ATCF_SUN_func_epilog:
+ *s_out = "DW_ATCF_SUN_func_epilog";
+ return DW_DLV_OK;
+ case DW_ATCF_hi_user:
+ *s_out = "DW_ATCF_hi_user";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_ACCESS_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_ACCESS_public:
+ *s_out = "DW_ACCESS_public";
+ return DW_DLV_OK;
+ case DW_ACCESS_protected:
+ *s_out = "DW_ACCESS_protected";
+ return DW_DLV_OK;
+ case DW_ACCESS_private:
+ *s_out = "DW_ACCESS_private";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_VIS_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_VIS_local:
+ *s_out = "DW_VIS_local";
+ return DW_DLV_OK;
+ case DW_VIS_exported:
+ *s_out = "DW_VIS_exported";
+ return DW_DLV_OK;
+ case DW_VIS_qualified:
+ *s_out = "DW_VIS_qualified";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_VIRTUALITY_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_VIRTUALITY_none:
+ *s_out = "DW_VIRTUALITY_none";
+ return DW_DLV_OK;
+ case DW_VIRTUALITY_virtual:
+ *s_out = "DW_VIRTUALITY_virtual";
+ return DW_DLV_OK;
+ case DW_VIRTUALITY_pure_virtual:
+ *s_out = "DW_VIRTUALITY_pure_virtual";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_LANG_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_LANG_C89:
+ *s_out = "DW_LANG_C89";
+ return DW_DLV_OK;
+ case DW_LANG_C:
+ *s_out = "DW_LANG_C";
+ return DW_DLV_OK;
+ case DW_LANG_Ada83:
+ *s_out = "DW_LANG_Ada83";
+ return DW_DLV_OK;
+ case DW_LANG_C_plus_plus:
+ *s_out = "DW_LANG_C_plus_plus";
+ return DW_DLV_OK;
+ case DW_LANG_Cobol74:
+ *s_out = "DW_LANG_Cobol74";
+ return DW_DLV_OK;
+ case DW_LANG_Cobol85:
+ *s_out = "DW_LANG_Cobol85";
+ return DW_DLV_OK;
+ case DW_LANG_Fortran77:
+ *s_out = "DW_LANG_Fortran77";
+ return DW_DLV_OK;
+ case DW_LANG_Fortran90:
+ *s_out = "DW_LANG_Fortran90";
+ return DW_DLV_OK;
+ case DW_LANG_Pascal83:
+ *s_out = "DW_LANG_Pascal83";
+ return DW_DLV_OK;
+ case DW_LANG_Modula2:
+ *s_out = "DW_LANG_Modula2";
+ return DW_DLV_OK;
+ case DW_LANG_Java:
+ *s_out = "DW_LANG_Java";
+ return DW_DLV_OK;
+ case DW_LANG_C99:
+ *s_out = "DW_LANG_C99";
+ return DW_DLV_OK;
+ case DW_LANG_Ada95:
+ *s_out = "DW_LANG_Ada95";
+ return DW_DLV_OK;
+ case DW_LANG_Fortran95:
+ *s_out = "DW_LANG_Fortran95";
+ return DW_DLV_OK;
+ case DW_LANG_PLI:
+ *s_out = "DW_LANG_PLI";
+ return DW_DLV_OK;
+ case DW_LANG_ObjC:
+ *s_out = "DW_LANG_ObjC";
+ return DW_DLV_OK;
+ case DW_LANG_ObjC_plus_plus:
+ *s_out = "DW_LANG_ObjC_plus_plus";
+ return DW_DLV_OK;
+ case DW_LANG_UPC:
+ *s_out = "DW_LANG_UPC";
+ return DW_DLV_OK;
+ case DW_LANG_D:
+ *s_out = "DW_LANG_D";
+ return DW_DLV_OK;
+ case DW_LANG_Python:
+ *s_out = "DW_LANG_Python";
+ return DW_DLV_OK;
+ case DW_LANG_OpenCL:
+ *s_out = "DW_LANG_OpenCL";
+ return DW_DLV_OK;
+ case DW_LANG_Go:
+ *s_out = "DW_LANG_Go";
+ return DW_DLV_OK;
+ case DW_LANG_lo_user:
+ *s_out = "DW_LANG_lo_user";
+ return DW_DLV_OK;
+ case DW_LANG_Mips_Assembler:
+ *s_out = "DW_LANG_Mips_Assembler";
+ return DW_DLV_OK;
+ case DW_LANG_Upc:
+ *s_out = "DW_LANG_Upc";
+ return DW_DLV_OK;
+ case DW_LANG_SUN_Assembler:
+ *s_out = "DW_LANG_SUN_Assembler";
+ return DW_DLV_OK;
+ case DW_LANG_ALTIUM_Assembler:
+ *s_out = "DW_LANG_ALTIUM_Assembler";
+ return DW_DLV_OK;
+ case DW_LANG_hi_user:
+ *s_out = "DW_LANG_hi_user";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_ID_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_ID_case_sensitive:
+ *s_out = "DW_ID_case_sensitive";
+ return DW_DLV_OK;
+ case DW_ID_up_case:
+ *s_out = "DW_ID_up_case";
+ return DW_DLV_OK;
+ case DW_ID_down_case:
+ *s_out = "DW_ID_down_case";
+ return DW_DLV_OK;
+ case DW_ID_case_insensitive:
+ *s_out = "DW_ID_case_insensitive";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_CC_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_CC_normal:
+ *s_out = "DW_CC_normal";
+ return DW_DLV_OK;
+ case DW_CC_program:
+ *s_out = "DW_CC_program";
+ return DW_DLV_OK;
+ case DW_CC_nocall:
+ *s_out = "DW_CC_nocall";
+ return DW_DLV_OK;
+ case DW_CC_lo_user:
+ *s_out = "DW_CC_lo_user";
+ return DW_DLV_OK;
+ case DW_CC_ALTIUM_interrupt:
+ *s_out = "DW_CC_ALTIUM_interrupt";
+ return DW_DLV_OK;
+ case DW_CC_ALTIUM_near_system_stack:
+ *s_out = "DW_CC_ALTIUM_near_system_stack";
+ return DW_DLV_OK;
+ case DW_CC_ALTIUM_near_user_stack:
+ *s_out = "DW_CC_ALTIUM_near_user_stack";
+ return DW_DLV_OK;
+ case DW_CC_ALTIUM_huge_user_stack:
+ *s_out = "DW_CC_ALTIUM_huge_user_stack";
+ return DW_DLV_OK;
+ case DW_CC_hi_user:
+ *s_out = "DW_CC_hi_user";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_INL_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_INL_not_inlined:
+ *s_out = "DW_INL_not_inlined";
+ return DW_DLV_OK;
+ case DW_INL_inlined:
+ *s_out = "DW_INL_inlined";
+ return DW_DLV_OK;
+ case DW_INL_declared_not_inlined:
+ *s_out = "DW_INL_declared_not_inlined";
+ return DW_DLV_OK;
+ case DW_INL_declared_inlined:
+ *s_out = "DW_INL_declared_inlined";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_ORD_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_ORD_row_major:
+ *s_out = "DW_ORD_row_major";
+ return DW_DLV_OK;
+ case DW_ORD_col_major:
+ *s_out = "DW_ORD_col_major";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_DSC_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_DSC_label:
+ *s_out = "DW_DSC_label";
+ return DW_DLV_OK;
+ case DW_DSC_range:
+ *s_out = "DW_DSC_range";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_LNS_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_LNS_copy:
+ *s_out = "DW_LNS_copy";
+ return DW_DLV_OK;
+ case DW_LNS_advance_pc:
+ *s_out = "DW_LNS_advance_pc";
+ return DW_DLV_OK;
+ case DW_LNS_advance_line:
+ *s_out = "DW_LNS_advance_line";
+ return DW_DLV_OK;
+ case DW_LNS_set_file:
+ *s_out = "DW_LNS_set_file";
+ return DW_DLV_OK;
+ case DW_LNS_set_column:
+ *s_out = "DW_LNS_set_column";
+ return DW_DLV_OK;
+ case DW_LNS_negate_stmt:
+ *s_out = "DW_LNS_negate_stmt";
+ return DW_DLV_OK;
+ case DW_LNS_set_basic_block:
+ *s_out = "DW_LNS_set_basic_block";
+ return DW_DLV_OK;
+ case DW_LNS_const_add_pc:
+ *s_out = "DW_LNS_const_add_pc";
+ return DW_DLV_OK;
+ case DW_LNS_fixed_advance_pc:
+ *s_out = "DW_LNS_fixed_advance_pc";
+ return DW_DLV_OK;
+ case DW_LNS_set_prologue_end:
+ *s_out = "DW_LNS_set_prologue_end";
+ return DW_DLV_OK;
+ case DW_LNS_set_epilogue_begin:
+ *s_out = "DW_LNS_set_epilogue_begin";
+ return DW_DLV_OK;
+ case DW_LNS_set_isa:
+ *s_out = "DW_LNS_set_isa";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_LNE_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_LNE_end_sequence:
+ *s_out = "DW_LNE_end_sequence";
+ return DW_DLV_OK;
+ case DW_LNE_set_address:
+ *s_out = "DW_LNE_set_address";
+ return DW_DLV_OK;
+ case DW_LNE_define_file:
+ *s_out = "DW_LNE_define_file";
+ return DW_DLV_OK;
+ case DW_LNE_set_discriminator:
+ *s_out = "DW_LNE_set_discriminator";
+ return DW_DLV_OK;
+ case DW_LNE_HP_negate_is_UV_update:
+ *s_out = "DW_LNE_HP_negate_is_UV_update";
+ return DW_DLV_OK;
+ case DW_LNE_HP_push_context:
+ *s_out = "DW_LNE_HP_push_context";
+ return DW_DLV_OK;
+ case DW_LNE_HP_pop_context:
+ *s_out = "DW_LNE_HP_pop_context";
+ return DW_DLV_OK;
+ case DW_LNE_HP_set_file_line_column:
+ *s_out = "DW_LNE_HP_set_file_line_column";
+ return DW_DLV_OK;
+ case DW_LNE_HP_set_routine_name:
+ *s_out = "DW_LNE_HP_set_routine_name";
+ return DW_DLV_OK;
+ case DW_LNE_HP_set_sequence:
+ *s_out = "DW_LNE_HP_set_sequence";
+ return DW_DLV_OK;
+ case DW_LNE_HP_negate_post_semantics:
+ *s_out = "DW_LNE_HP_negate_post_semantics";
+ return DW_DLV_OK;
+ case DW_LNE_HP_negate_function_exit:
+ *s_out = "DW_LNE_HP_negate_function_exit";
+ return DW_DLV_OK;
+ case DW_LNE_HP_negate_front_end_logical:
+ *s_out = "DW_LNE_HP_negate_front_end_logical";
+ return DW_DLV_OK;
+ case DW_LNE_HP_define_proc:
+ *s_out = "DW_LNE_HP_define_proc";
+ return DW_DLV_OK;
+ case DW_LNE_lo_user:
+ *s_out = "DW_LNE_lo_user";
+ return DW_DLV_OK;
+ case DW_LNE_hi_user:
+ *s_out = "DW_LNE_hi_user";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_ISA_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_ISA_UNKNOWN:
+ *s_out = "DW_ISA_UNKNOWN";
+ return DW_DLV_OK;
+ case DW_ISA_ARM_thumb:
+ *s_out = "DW_ISA_ARM_thumb";
+ return DW_DLV_OK;
+ case DW_ISA_ARM_arm:
+ *s_out = "DW_ISA_ARM_arm";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_MACINFO_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_MACINFO_define:
+ *s_out = "DW_MACINFO_define";
+ return DW_DLV_OK;
+ case DW_MACINFO_undef:
+ *s_out = "DW_MACINFO_undef";
+ return DW_DLV_OK;
+ case DW_MACINFO_start_file:
+ *s_out = "DW_MACINFO_start_file";
+ return DW_DLV_OK;
+ case DW_MACINFO_end_file:
+ *s_out = "DW_MACINFO_end_file";
+ return DW_DLV_OK;
+ case DW_MACINFO_vendor_ext:
+ *s_out = "DW_MACINFO_vendor_ext";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_CFA_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_CFA_extended:
+ *s_out = "DW_CFA_extended";
+ return DW_DLV_OK;
+ case DW_CFA_set_loc:
+ *s_out = "DW_CFA_set_loc";
+ return DW_DLV_OK;
+ case DW_CFA_advance_loc1:
+ *s_out = "DW_CFA_advance_loc1";
+ return DW_DLV_OK;
+ case DW_CFA_advance_loc2:
+ *s_out = "DW_CFA_advance_loc2";
+ return DW_DLV_OK;
+ case DW_CFA_advance_loc4:
+ *s_out = "DW_CFA_advance_loc4";
+ return DW_DLV_OK;
+ case DW_CFA_offset_extended:
+ *s_out = "DW_CFA_offset_extended";
+ return DW_DLV_OK;
+ case DW_CFA_restore_extended:
+ *s_out = "DW_CFA_restore_extended";
+ return DW_DLV_OK;
+ case DW_CFA_undefined:
+ *s_out = "DW_CFA_undefined";
+ return DW_DLV_OK;
+ case DW_CFA_same_value:
+ *s_out = "DW_CFA_same_value";
+ return DW_DLV_OK;
+ case DW_CFA_register:
+ *s_out = "DW_CFA_register";
+ return DW_DLV_OK;
+ case DW_CFA_remember_state:
+ *s_out = "DW_CFA_remember_state";
+ return DW_DLV_OK;
+ case DW_CFA_restore_state:
+ *s_out = "DW_CFA_restore_state";
+ return DW_DLV_OK;
+ case DW_CFA_def_cfa:
+ *s_out = "DW_CFA_def_cfa";
+ return DW_DLV_OK;
+ case DW_CFA_def_cfa_register:
+ *s_out = "DW_CFA_def_cfa_register";
+ return DW_DLV_OK;
+ case DW_CFA_def_cfa_offset:
+ *s_out = "DW_CFA_def_cfa_offset";
+ return DW_DLV_OK;
+ case DW_CFA_def_cfa_expression:
+ *s_out = "DW_CFA_def_cfa_expression";
+ return DW_DLV_OK;
+ case DW_CFA_expression:
+ *s_out = "DW_CFA_expression";
+ return DW_DLV_OK;
+ case DW_CFA_offset_extended_sf:
+ *s_out = "DW_CFA_offset_extended_sf";
+ return DW_DLV_OK;
+ case DW_CFA_def_cfa_sf:
+ *s_out = "DW_CFA_def_cfa_sf";
+ return DW_DLV_OK;
+ case DW_CFA_def_cfa_offset_sf:
+ *s_out = "DW_CFA_def_cfa_offset_sf";
+ return DW_DLV_OK;
+ case DW_CFA_val_offset:
+ *s_out = "DW_CFA_val_offset";
+ return DW_DLV_OK;
+ case DW_CFA_val_offset_sf:
+ *s_out = "DW_CFA_val_offset_sf";
+ return DW_DLV_OK;
+ case DW_CFA_val_expression:
+ *s_out = "DW_CFA_val_expression";
+ return DW_DLV_OK;
+ case DW_CFA_lo_user:
+ *s_out = "DW_CFA_lo_user";
+ return DW_DLV_OK;
+ case DW_CFA_MIPS_advance_loc8:
+ *s_out = "DW_CFA_MIPS_advance_loc8";
+ return DW_DLV_OK;
+ case DW_CFA_GNU_window_save:
+ *s_out = "DW_CFA_GNU_window_save";
+ return DW_DLV_OK;
+ case DW_CFA_GNU_args_size:
+ *s_out = "DW_CFA_GNU_args_size";
+ return DW_DLV_OK;
+ case DW_CFA_GNU_negative_offset_extended:
+ *s_out = "DW_CFA_GNU_negative_offset_extended";
+ return DW_DLV_OK;
+ case DW_CFA_high_user:
+ *s_out = "DW_CFA_high_user";
+ return DW_DLV_OK;
+ case DW_CFA_advance_loc:
+ *s_out = "DW_CFA_advance_loc";
+ return DW_DLV_OK;
+ case DW_CFA_offset:
+ *s_out = "DW_CFA_offset";
+ return DW_DLV_OK;
+ case DW_CFA_restore:
+ *s_out = "DW_CFA_restore";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_EH_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_EH_PE_absptr:
+ *s_out = "DW_EH_PE_absptr";
+ return DW_DLV_OK;
+ case DW_EH_PE_uleb128:
+ *s_out = "DW_EH_PE_uleb128";
+ return DW_DLV_OK;
+ case DW_EH_PE_udata2:
+ *s_out = "DW_EH_PE_udata2";
+ return DW_DLV_OK;
+ case DW_EH_PE_udata4:
+ *s_out = "DW_EH_PE_udata4";
+ return DW_DLV_OK;
+ case DW_EH_PE_udata8:
+ *s_out = "DW_EH_PE_udata8";
+ return DW_DLV_OK;
+ case DW_EH_PE_sleb128:
+ *s_out = "DW_EH_PE_sleb128";
+ return DW_DLV_OK;
+ case DW_EH_PE_sdata2:
+ *s_out = "DW_EH_PE_sdata2";
+ return DW_DLV_OK;
+ case DW_EH_PE_sdata4:
+ *s_out = "DW_EH_PE_sdata4";
+ return DW_DLV_OK;
+ case DW_EH_PE_sdata8:
+ *s_out = "DW_EH_PE_sdata8";
+ return DW_DLV_OK;
+ case DW_EH_PE_pcrel:
+ *s_out = "DW_EH_PE_pcrel";
+ return DW_DLV_OK;
+ case DW_EH_PE_textrel:
+ *s_out = "DW_EH_PE_textrel";
+ return DW_DLV_OK;
+ case DW_EH_PE_datarel:
+ *s_out = "DW_EH_PE_datarel";
+ return DW_DLV_OK;
+ case DW_EH_PE_funcrel:
+ *s_out = "DW_EH_PE_funcrel";
+ return DW_DLV_OK;
+ case DW_EH_PE_aligned:
+ *s_out = "DW_EH_PE_aligned";
+ return DW_DLV_OK;
+ case DW_EH_PE_omit:
+ *s_out = "DW_EH_PE_omit";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_FRAME_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_FRAME_CFA_COL:
+ *s_out = "DW_FRAME_CFA_COL";
+ return DW_DLV_OK;
+ case DW_FRAME_REG1:
+ *s_out = "DW_FRAME_REG1";
+ return DW_DLV_OK;
+ case DW_FRAME_REG2:
+ *s_out = "DW_FRAME_REG2";
+ return DW_DLV_OK;
+ case DW_FRAME_REG3:
+ *s_out = "DW_FRAME_REG3";
+ return DW_DLV_OK;
+ case DW_FRAME_REG4:
+ *s_out = "DW_FRAME_REG4";
+ return DW_DLV_OK;
+ case DW_FRAME_REG5:
+ *s_out = "DW_FRAME_REG5";
+ return DW_DLV_OK;
+ case DW_FRAME_REG6:
+ *s_out = "DW_FRAME_REG6";
+ return DW_DLV_OK;
+ case DW_FRAME_REG7:
+ *s_out = "DW_FRAME_REG7";
+ return DW_DLV_OK;
+ case DW_FRAME_REG8:
+ *s_out = "DW_FRAME_REG8";
+ return DW_DLV_OK;
+ case DW_FRAME_REG9:
+ *s_out = "DW_FRAME_REG9";
+ return DW_DLV_OK;
+ case DW_FRAME_REG10:
+ *s_out = "DW_FRAME_REG10";
+ return DW_DLV_OK;
+ case DW_FRAME_REG11:
+ *s_out = "DW_FRAME_REG11";
+ return DW_DLV_OK;
+ case DW_FRAME_REG12:
+ *s_out = "DW_FRAME_REG12";
+ return DW_DLV_OK;
+ case DW_FRAME_REG13:
+ *s_out = "DW_FRAME_REG13";
+ return DW_DLV_OK;
+ case DW_FRAME_REG14:
+ *s_out = "DW_FRAME_REG14";
+ return DW_DLV_OK;
+ case DW_FRAME_REG15:
+ *s_out = "DW_FRAME_REG15";
+ return DW_DLV_OK;
+ case DW_FRAME_REG16:
+ *s_out = "DW_FRAME_REG16";
+ return DW_DLV_OK;
+ case DW_FRAME_REG17:
+ *s_out = "DW_FRAME_REG17";
+ return DW_DLV_OK;
+ case DW_FRAME_REG18:
+ *s_out = "DW_FRAME_REG18";
+ return DW_DLV_OK;
+ case DW_FRAME_REG19:
+ *s_out = "DW_FRAME_REG19";
+ return DW_DLV_OK;
+ case DW_FRAME_REG20:
+ *s_out = "DW_FRAME_REG20";
+ return DW_DLV_OK;
+ case DW_FRAME_REG21:
+ *s_out = "DW_FRAME_REG21";
+ return DW_DLV_OK;
+ case DW_FRAME_REG22:
+ *s_out = "DW_FRAME_REG22";
+ return DW_DLV_OK;
+ case DW_FRAME_REG23:
+ *s_out = "DW_FRAME_REG23";
+ return DW_DLV_OK;
+ case DW_FRAME_REG24:
+ *s_out = "DW_FRAME_REG24";
+ return DW_DLV_OK;
+ case DW_FRAME_REG25:
+ *s_out = "DW_FRAME_REG25";
+ return DW_DLV_OK;
+ case DW_FRAME_REG26:
+ *s_out = "DW_FRAME_REG26";
+ return DW_DLV_OK;
+ case DW_FRAME_REG27:
+ *s_out = "DW_FRAME_REG27";
+ return DW_DLV_OK;
+ case DW_FRAME_REG28:
+ *s_out = "DW_FRAME_REG28";
+ return DW_DLV_OK;
+ case DW_FRAME_REG29:
+ *s_out = "DW_FRAME_REG29";
+ return DW_DLV_OK;
+ case DW_FRAME_REG30:
+ *s_out = "DW_FRAME_REG30";
+ return DW_DLV_OK;
+ case DW_FRAME_REG31:
+ *s_out = "DW_FRAME_REG31";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG0:
+ *s_out = "DW_FRAME_FREG0";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG1:
+ *s_out = "DW_FRAME_FREG1";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG2:
+ *s_out = "DW_FRAME_FREG2";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG3:
+ *s_out = "DW_FRAME_FREG3";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG4:
+ *s_out = "DW_FRAME_FREG4";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG5:
+ *s_out = "DW_FRAME_FREG5";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG6:
+ *s_out = "DW_FRAME_FREG6";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG7:
+ *s_out = "DW_FRAME_FREG7";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG8:
+ *s_out = "DW_FRAME_FREG8";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG9:
+ *s_out = "DW_FRAME_FREG9";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG10:
+ *s_out = "DW_FRAME_FREG10";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG11:
+ *s_out = "DW_FRAME_FREG11";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG12:
+ *s_out = "DW_FRAME_FREG12";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG13:
+ *s_out = "DW_FRAME_FREG13";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG14:
+ *s_out = "DW_FRAME_FREG14";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG15:
+ *s_out = "DW_FRAME_FREG15";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG16:
+ *s_out = "DW_FRAME_FREG16";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG17:
+ *s_out = "DW_FRAME_FREG17";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG18:
+ *s_out = "DW_FRAME_FREG18";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG19:
+ *s_out = "DW_FRAME_FREG19";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG20:
+ *s_out = "DW_FRAME_FREG20";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG21:
+ *s_out = "DW_FRAME_FREG21";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG22:
+ *s_out = "DW_FRAME_FREG22";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG23:
+ *s_out = "DW_FRAME_FREG23";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG24:
+ *s_out = "DW_FRAME_FREG24";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG25:
+ *s_out = "DW_FRAME_FREG25";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG26:
+ *s_out = "DW_FRAME_FREG26";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG27:
+ *s_out = "DW_FRAME_FREG27";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG28:
+ *s_out = "DW_FRAME_FREG28";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG29:
+ *s_out = "DW_FRAME_FREG29";
+ return DW_DLV_OK;
+ case DW_FRAME_FREG30:
+ *s_out = "DW_FRAME_FREG30";
+ return DW_DLV_OK;
+ case DW_FRAME_HIGHEST_NORMAL_REGISTER:
+ *s_out = "DW_FRAME_HIGHEST_NORMAL_REGISTER";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_CHILDREN_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_CHILDREN_no:
+ *s_out = "DW_CHILDREN_no";
+ return DW_DLV_OK;
+ case DW_CHILDREN_yes:
+ *s_out = "DW_CHILDREN_yes";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+/* ARGSUSED */
+int
+dwarf_get_ADDR_name (unsigned int val,const char ** s_out)
+{
+ switch (val) {
+ case DW_ADDR_none:
+ *s_out = "DW_ADDR_none";
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+
+/* END FILE */
diff --git a/usr/src/lib/libdwarf/common/dwarf_names.h b/usr/src/lib/libdwarf/common/dwarf_names.h
new file mode 100644
index 0000000000..6edafa5fdd
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_names.h
@@ -0,0 +1,34 @@
+/* Generated routines, do not edit. */
+/* Generated on May 22 2011 03:05:33 */
+
+/* BEGIN FILE */
+
+extern int dwarf_get_TAG_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_children_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_FORM_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_AT_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_OP_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_ATE_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_DS_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_END_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_ATCF_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_ACCESS_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_VIS_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_VIRTUALITY_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_LANG_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_ID_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_CC_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_INL_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_ORD_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_DSC_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_LNS_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_LNE_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_ISA_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_MACINFO_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_CFA_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_EH_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_FRAME_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_CHILDREN_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_ADDR_name(unsigned int /*val_in*/, const char ** /*s_out */);
+
+/* END FILE */
diff --git a/usr/src/lib/libdwarf/common/dwarf_opaque.h b/usr/src/lib/libdwarf/common/dwarf_opaque.h
new file mode 100644
index 0000000000..b235a9c7b4
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_opaque.h
@@ -0,0 +1,339 @@
+/*
+
+ Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2007-2010 David Anderson. All Rights Reserved.
+ Portions Copyright (C) 2008-2010 Arxan Technologies, 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
+
+*/
+/* The versions applicable by section are:
+ DWARF2 DWARF3 DWARF4
+ .debug_abbrev - - -
+ .debug_aranges 2 2 2
+ .debug_frame 1 3 4
+ .debug_info 2 3 4
+ .debug_line 2 3 4
+ .debug_loc - - -
+ .debug_macinfo - - -
+ .debug_pubtypes x 2 2
+ .debug_pubnames 2 2 2
+ .debug_ranges x - -
+ .debug_str - - -
+ .debug_types x x 4
+*/
+
+#include <stddef.h>
+
+
+struct Dwarf_Die_s {
+ Dwarf_Byte_Ptr di_debug_info_ptr;
+ Dwarf_Abbrev_List di_abbrev_list;
+ Dwarf_CU_Context di_cu_context;
+ int di_abbrev_code;
+};
+
+struct Dwarf_Attribute_s {
+ Dwarf_Half ar_attribute; /* Attribute Value. */
+ Dwarf_Half ar_attribute_form; /* Attribute Form. */
+ Dwarf_Half ar_attribute_form_direct;
+ /* Identical to ar_attribute_form except that if
+ the original form uleb was DW_FORM_indirect,
+ ar_attribute_form_direct contains DW_FORM_indirect
+ but ar_attribute_form contains the true form. */
+
+ Dwarf_CU_Context ar_cu_context;
+ Dwarf_Small *ar_debug_info_ptr;
+ Dwarf_Attribute ar_next;
+};
+
+/*
+ This structure provides the context for a compilation unit.
+ Thus, it contains the Dwarf_Debug, cc_dbg, that this cu
+ belongs to. It contains the information in the compilation
+ unit header, cc_length, cc_version_stamp, cc_abbrev_offset,
+ and cc_address_size, in the .debug_info section for that cu.
+ In addition, it contains the count, cc_count_cu, of the cu
+ number of that cu in the list of cu's in the .debug_info.
+ The count starts at 1, ie cc_count_cu is 1 for the first cu,
+ 2 for the second and so on. This struct also contains a
+ pointer, cc_abbrev_table, to a list of pairs of abbrev code
+ and a pointer to the start of that abbrev
+ in the .debug_abbrev section.
+
+ Each die will also contain a pointer to such a struct to
+ record the context for that die.
+
+ Notice that a pointer to the CU DIE itself is
+ Dwarf_Off off2 = cu_context->cc_debug_info_offset;
+ cu_die_info_ptr = dbg->de_debug_info.dss_data +
+ off2 + _dwarf_length_of_cu_header(dbg, off2);
+
+ **Updated by dwarf_next_cu_header in dwarf_die_deliv.c
+*/
+struct Dwarf_CU_Context_s {
+ Dwarf_Debug cc_dbg;
+ /* The sum of cc_length, cc_length_size, and cc_extension_size
+ is the total length of the CU including its header. */
+ Dwarf_Word cc_length;
+ /* cc_length_size is the size in bytes of an offset.
+ 4 for 32bit dwarf, 8 for 64bit dwarf (whether MIPS/IRIX
+ 64bit dwarf or standard 64bit dwarf using the extension
+ mechanism). */
+ Dwarf_Small cc_length_size;
+ /* cc_extension_size is zero unless this is standard
+ DWARF3 and later 64bit dwarf using the extension mechanism.
+ If it is the DWARF3 and later 64bit dwarf cc_extension
+ size is 4. So for 32bit dwarf and MIPS/IRIX 64bit dwarf
+ cc_extension_size is zero. */
+ Dwarf_Small cc_extension_size;
+ Dwarf_Half cc_version_stamp;
+ Dwarf_Sword cc_abbrev_offset;
+ Dwarf_Small cc_address_size;
+ /* cc_debug_info_offset is the offset in the section
+ of the CU header of this CU. Dwarf_Word
+ should be large enough. */
+ Dwarf_Word cc_debug_info_offset;
+ Dwarf_Byte_Ptr cc_last_abbrev_ptr;
+ Dwarf_Hash_Table cc_abbrev_hash_table;
+ Dwarf_CU_Context cc_next;
+ /*unsigned char cc_offset_length; */
+};
+
+/* Consolidates section-specific data in one place.
+ Section is an Elf specific term, intended as a general
+ term (for non-Elf objects some code must synthesize the
+ values somehow).
+ Makes adding more section-data much simpler. */
+struct Dwarf_Section_s {
+ Dwarf_Small * dss_data;
+ Dwarf_Unsigned dss_size;
+ Dwarf_Word dss_index;
+ /* dss_addr is the 'section address' which is only
+ non-zero for a GNU eh section.
+ Purpose: to handle DW_EH_PE_pcrel encoding. Leaving
+ it zero is fine for non-elf. */
+ Dwarf_Addr dss_addr;
+ Dwarf_Small dss_data_was_malloc;
+
+ /* For non-elf, leaving the following fields zero
+ will mean they are ignored. */
+ /* dss_link should be zero unless a section has a link
+ to another (sh_link). Used to access relocation data for
+ a section (and for symtab section, access its strtab). */
+ Dwarf_Word dss_link;
+ /* The following is used when reading .rela sections
+ (such sections appear in some .o files). */
+ Dwarf_Half dss_reloc_index; /* Zero means ignore the reloc fields. */
+ Dwarf_Small * dss_reloc_data;
+ Dwarf_Unsigned dss_reloc_size;
+ Dwarf_Addr dss_reloc_addr;
+ /* dss_reloc_symtab is the sh_link of a .rela to its .symtab, leave
+ it 0 if non-meaningful. */
+ Dwarf_Addr dss_reloc_symtab;
+ /* dss_reloc_link should be zero unless a reloc section has a link
+ to another (sh_link). Used to access the symtab for relocations
+ a section. */
+ Dwarf_Word dss_reloc_link;
+ /* Pointer to the elf symtab, used for elf .rela. Leave it 0
+ if not relevant. */
+ struct Dwarf_Section_s *dss_symtab;
+};
+
+/* Overview: if next_to_use== first, no error slots are used.
+ If next_to_use+1 (mod maxcount) == first the slots are all used
+*/
+struct Dwarf_Harmless_s {
+ unsigned dh_maxcount;
+ unsigned dh_next_to_use;
+ unsigned dh_first;
+ unsigned dh_errs_count;
+ char ** dh_errors;
+};
+
+struct Dwarf_Debug_s {
+ /* All file access methods and support data
+ are hidden in this structure.
+ We get a pointer, callers control the lifetime of the
+ structure and contents. */
+ struct Dwarf_Obj_Access_Interface_s *de_obj_file;
+
+ Dwarf_Handler de_errhand;
+ Dwarf_Ptr de_errarg;
+
+ /*
+ Context for the compilation_unit just read by a call to
+ dwarf_next_cu_header. **Updated by dwarf_next_cu_header in
+ dwarf_die_deliv.c */
+ Dwarf_CU_Context de_cu_context;
+
+ /*
+ Points to linked list of CU Contexts for the CU's already read.
+ These are only CU's read by dwarf_next_cu_header(). */
+ Dwarf_CU_Context de_cu_context_list;
+
+ /*
+ Points to the last CU Context added to the list by
+ dwarf_next_cu_header(). */
+ Dwarf_CU_Context de_cu_context_list_end;
+
+ /*
+ This is the list of CU contexts read for dwarf_offdie(). These
+ may read ahead of dwarf_next_cu_header(). */
+ Dwarf_CU_Context de_offdie_cu_context;
+ Dwarf_CU_Context de_offdie_cu_context_end;
+
+ /* Offset of last byte of last CU read. */
+ Dwarf_Word de_info_last_offset;
+
+ /*
+ Number of bytes in the length, and offset field in various
+ .debug_* sections. It's not very meaningful, and is
+ only used in one 'approximate' calculation. */
+ Dwarf_Small de_length_size;
+
+ /* number of bytes in a pointer of the target in various .debug_
+ sections. 4 in 32bit, 8 in MIPS 64, ia64. */
+ Dwarf_Small de_pointer_size;
+
+ /* set at creation of a Dwarf_Debug to say if form_string should be
+ checked for valid length at every call. 0 means do the check.
+ non-zero means do not do the check. */
+ Dwarf_Small de_assume_string_in_bounds;
+
+ /*
+ Dwarf_Alloc_Hdr_s structs used to manage chunks that are
+ malloc'ed for each allocation type for structs. */
+ struct Dwarf_Alloc_Hdr_s de_alloc_hdr[ALLOC_AREA_REAL_TABLE_MAX];
+#ifdef DWARF_SIMPLE_MALLOC
+ struct simple_malloc_record_s * de_simple_malloc_base;
+#endif
+
+
+ /*
+ These fields are used to process debug_frame section. **Updated
+ by dwarf_get_fde_list in dwarf_frame.h */
+ /*
+ Points to contiguous block of pointers to Dwarf_Cie_s structs. */
+ Dwarf_Cie *de_cie_data;
+ /* Count of number of Dwarf_Cie_s structs. */
+ Dwarf_Signed de_cie_count;
+ /* Keep eh (GNU) separate!. */
+ Dwarf_Cie *de_cie_data_eh;
+ Dwarf_Signed de_cie_count_eh;
+ /*
+ Points to contiguous block of pointers to Dwarf_Fde_s structs. */
+ Dwarf_Fde *de_fde_data;
+ /* Count of number of Dwarf_Fde_s structs. */
+ Dwarf_Signed de_fde_count;
+ /* Keep eh (GNU) separate!. */
+ Dwarf_Fde *de_fde_data_eh;
+ Dwarf_Signed de_fde_count_eh;
+
+ struct Dwarf_Section_s de_debug_info;
+ struct Dwarf_Section_s de_debug_abbrev;
+ struct Dwarf_Section_s de_debug_line;
+ struct Dwarf_Section_s de_debug_loc;
+ struct Dwarf_Section_s de_debug_aranges;
+ struct Dwarf_Section_s de_debug_macinfo;
+ struct Dwarf_Section_s de_debug_pubnames;
+ struct Dwarf_Section_s de_debug_str;
+ struct Dwarf_Section_s de_debug_frame;
+
+ /* gnu: the g++ eh_frame section */
+ struct Dwarf_Section_s de_debug_frame_eh_gnu;
+
+ struct Dwarf_Section_s de_debug_pubtypes; /* DWARF3 .debug_pubtypes */
+
+ struct Dwarf_Section_s de_debug_funcnames;
+ struct Dwarf_Section_s de_debug_typenames; /* SGI IRIX extension essentially
+ identical to DWARF3 .debug_pubtypes. */
+ struct Dwarf_Section_s de_debug_varnames;
+ struct Dwarf_Section_s de_debug_weaknames;
+ struct Dwarf_Section_s de_debug_ranges;
+
+ /* For non-elf, simply leave the following two structs zeroed and
+ they will be ignored. */
+ struct Dwarf_Section_s de_elf_symtab;
+ struct Dwarf_Section_s de_elf_strtab;
+
+
+ void *(*de_copy_word) (void *, const void *, size_t);
+ unsigned char de_same_endian;
+ unsigned char de_elf_must_close; /* if non-zero, then
+ it was dwarf_init (not dwarf_elf_init)
+ so must elf_end() */
+
+ /* Default is DW_FRAME_INITIAL_VALUE from header. */
+ Dwarf_Half de_frame_rule_initial_value;
+
+ /* Default is DW_FRAME_LAST_REG_NUM. */
+ Dwarf_Half de_frame_reg_rules_entry_count;
+
+ Dwarf_Half de_frame_cfa_col_number;
+ Dwarf_Half de_frame_same_value_number;
+ Dwarf_Half de_frame_undefined_value_number;
+
+ unsigned char de_big_endian_object; /* non-zero if big-endian
+ object opened. */
+
+ struct Dwarf_Harmless_s de_harmless_errors;
+};
+
+typedef struct Dwarf_Chain_s *Dwarf_Chain;
+struct Dwarf_Chain_s {
+ void *ch_item;
+ Dwarf_Chain ch_next;
+};
+
+
+#define CURRENT_VERSION_STAMP 2 /* DWARF2 */
+#define CURRENT_VERSION_STAMP3 3 /* DWARF3 */
+#define CURRENT_VERSION_STAMP4 4 /* DWARF4 */
+
+ /* Size of cu header version stamp field. */
+#define CU_VERSION_STAMP_SIZE sizeof(Dwarf_Half)
+
+ /* Size of cu header address size field. */
+#define CU_ADDRESS_SIZE_SIZE sizeof(Dwarf_Small)
+
+void *_dwarf_memcpy_swap_bytes(void *s1, const void *s2, size_t len);
+
+#define ORIGINAL_DWARF_OFFSET_SIZE 4
+#define DISTINGUISHED_VALUE 0xffffffff
+#define DISTINGUISHED_VALUE_OFFSET_SIZE 8
+
+/*
+ We don't load the sections until they are needed. This function is
+ used to load the section.
+ */
+int _dwarf_load_section(Dwarf_Debug,
+ struct Dwarf_Section_s *,
+ Dwarf_Error *);
diff --git a/usr/src/lib/libdwarf/common/dwarf_original_elf_init.c b/usr/src/lib/libdwarf/common/dwarf_original_elf_init.c
new file mode 100644
index 0000000000..a6d943da0a
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_original_elf_init.c
@@ -0,0 +1,209 @@
+/*
+
+ Copyright (C) 2000,2001,2002,2005,2006 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright 2007-2010 Sun Microsystems, Inc. All rights reserved.
+ Portions Copyright 2008-2010 Arxan Technologies, 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
+
+*/
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include "dwarf_elf_access.h"
+
+#ifdef HAVE_ELF_H
+#include <elf.h>
+#endif
+#ifdef HAVE_LIBELF_H
+#include <libelf.h>
+#else
+#ifdef HAVE_LIBELF_LIBELF_H
+#include <libelf/libelf.h>
+#endif
+#endif
+
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define DWARF_DBG_ERROR(dbg,errval,retval) \
+ _dwarf_error(dbg, error, errval); return(retval);
+
+#define FALSE 0
+#define TRUE 1
+
+static int
+dwarf_elf_init_file_ownership(dwarf_elf_handle elf_file_pointer,
+ int libdwarf_owns_elf,
+ Dwarf_Unsigned access,
+ Dwarf_Handler errhand,
+ Dwarf_Ptr errarg,
+ Dwarf_Debug * ret_dbg,
+ Dwarf_Error * error);
+
+
+/*
+ The basic dwarf initializer function for consumers using
+ libelf.
+ Return a libdwarf error code on error, return DW_DLV_OK
+ if this succeeds.
+*/
+int
+dwarf_init(int fd,
+ Dwarf_Unsigned access,
+ Dwarf_Handler errhand,
+ Dwarf_Ptr errarg, Dwarf_Debug * ret_dbg, Dwarf_Error * error)
+{
+ struct stat fstat_buf;
+ dwarf_elf_handle elf_file_pointer = 0;
+ /* ELF_C_READ is a portable value */
+ Elf_Cmd what_kind_of_elf_read = ELF_C_READ;
+
+#if !defined(S_ISREG)
+#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
+#endif
+ if (fstat(fd, &fstat_buf) != 0) {
+ DWARF_DBG_ERROR(NULL, DW_DLE_FSTAT_ERROR, DW_DLV_ERROR);
+ }
+ if (!S_ISREG(fstat_buf.st_mode)) {
+ DWARF_DBG_ERROR(NULL, DW_DLE_FSTAT_MODE_ERROR, DW_DLV_ERROR);
+ }
+
+ if (access != DW_DLC_READ) {
+ DWARF_DBG_ERROR(NULL, DW_DLE_INIT_ACCESS_WRONG, DW_DLV_ERROR);
+ }
+
+ elf_version(EV_CURRENT);
+ /* changed to mmap request per bug 281217. 6/95 */
+#ifdef HAVE_ELF_C_READ_MMAP
+ /* ELF_C_READ_MMAP is an SGI IRIX specific enum value from IRIX
+ libelf.h meaning read but use mmap */
+ what_kind_of_elf_read = ELF_C_READ_MMAP;
+#endif /* !HAVE_ELF_C_READ_MMAP */
+
+ elf_file_pointer = elf_begin(fd, what_kind_of_elf_read, 0);
+ if (elf_file_pointer == NULL) {
+ DWARF_DBG_ERROR(NULL, DW_DLE_ELF_BEGIN_ERROR, DW_DLV_ERROR);
+ }
+
+ return dwarf_elf_init_file_ownership(elf_file_pointer,
+ TRUE,
+ access,
+ errhand,
+ errarg,
+ ret_dbg,
+ error);
+}
+
+/*
+ An alternate dwarf setup call for consumers using
+ libelf.
+ When the caller has opened libelf already, so the
+ caller must free libelf.
+*/
+int
+dwarf_elf_init(dwarf_elf_handle elf_file_pointer,
+ Dwarf_Unsigned access,
+ Dwarf_Handler errhand,
+ Dwarf_Ptr errarg,
+ Dwarf_Debug * ret_dbg, Dwarf_Error * error)
+{
+ return dwarf_elf_init_file_ownership(elf_file_pointer,
+ FALSE,
+ access,
+ errhand,
+ errarg,
+ ret_dbg,
+ error);
+}
+
+
+/*
+ Initialize the ELF object access for libdwarf.
+ */
+static int
+dwarf_elf_init_file_ownership(dwarf_elf_handle elf_file_pointer,
+ int libdwarf_owns_elf,
+ Dwarf_Unsigned access,
+ Dwarf_Handler errhand,
+ Dwarf_Ptr errarg,
+ Dwarf_Debug * ret_dbg,
+ Dwarf_Error * error)
+{
+ /* ELF is no longer tied to libdwarf. */
+ Dwarf_Obj_Access_Interface *binary_interface = 0;
+ int res = DW_DLV_OK;
+ int err = 0;
+
+ if (access != DW_DLC_READ) {
+ DWARF_DBG_ERROR(NULL, DW_DLE_INIT_ACCESS_WRONG, DW_DLV_ERROR);
+ }
+
+ /* This allocates and fills in *binary_interface. */
+ res = dwarf_elf_object_access_init(
+ elf_file_pointer,
+ libdwarf_owns_elf,
+ &binary_interface,
+ &err);
+ if(res != DW_DLV_OK){
+ DWARF_DBG_ERROR(NULL, err, DW_DLV_ERROR);
+ }
+
+ /* This mallocs space and returns pointer thru ret_dbg,
+ saving the binary interface in 'ret-dbg' */
+ res = dwarf_object_init(binary_interface, errhand, errarg,
+ ret_dbg, error);
+ if(res != DW_DLV_OK){
+ dwarf_elf_object_access_finish(binary_interface);
+ }
+ return res;
+}
+
+
+/*
+ Frees all memory that was not previously freed
+ by dwarf_dealloc.
+ Aside from certain categories.
+
+ This is only applicable when dwarf_init() or dwarf_elf_init()
+ was used to init 'dbg'.
+*/
+int
+dwarf_finish(Dwarf_Debug dbg, Dwarf_Error * error)
+{
+ dwarf_elf_object_access_finish(dbg->de_obj_file);
+
+ return dwarf_object_finish(dbg, error);
+}
+
diff --git a/usr/src/lib/libdwarf/common/dwarf_print_lines.c b/usr/src/lib/libdwarf/common/dwarf_print_lines.c
new file mode 100644
index 0000000000..30c4889ee5
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_print_lines.c
@@ -0,0 +1,737 @@
+/*
+
+ Copyright (C) 2000,2002,2004,2005,2006 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2007-2010 David Anderson. 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
+
+*/
+/* The address of the Free Software Foundation is
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ SGI has moved from the Crittenden Lane address.
+*/
+
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+#include <time.h>
+#include "dwarf_line.h"
+
+/* FIXME Need to add prologue_end epilogue_begin isa fields. */
+static void
+print_line_header(void)
+{
+ printf
+ (" s b e\n"
+ " t l s\n"
+ " m c e\n"
+ " section op col t k q\n"
+ " offset code address file line umn ? ? ?\n");
+}
+
+/* FIXME: print new line values: prologue_end epilogue_begin isa */
+static void
+print_line_detail(char *prefix,
+ int opcode,
+ Dwarf_Unsigned address,
+ unsigned long file,
+ unsigned long line,
+ unsigned long column,
+ int is_stmt, int basic_block, int end_sequence,
+ int prologue_end, int epilogue_begin, int isa)
+{
+ printf("%-15s %2d 0x%08" DW_PR_DUx " "
+ "%2lu %4lu %2lu %1d %1d %1d\n",
+ prefix,
+ (int) opcode,
+ (Dwarf_Unsigned) address,
+ (unsigned long) file,
+ (unsigned long) line,
+ (unsigned long) column,
+ (int) is_stmt, (int) basic_block, (int) end_sequence);
+
+}
+
+
+/*
+ return DW_DLV_OK if ok. else DW_DLV_NO_ENTRY or DW_DLV_ERROR
+ If err_count_out is non-NULL, this is a special 'check'
+ call.
+*/
+int
+_dwarf_internal_printlines(Dwarf_Die die, Dwarf_Error * error,
+ int * err_count_out, int only_line_header)
+{
+ /*
+ This pointer is used to scan the portion of the .debug_line
+ section for the current cu. */
+ Dwarf_Small *line_ptr = 0;
+ Dwarf_Small *orig_line_ptr = 0;
+
+ /*
+ This points to the last byte of the .debug_line portion for the
+ current cu. */
+ Dwarf_Small *line_ptr_end = 0;
+
+ /*
+ Pointer to a DW_AT_stmt_list attribute in case it exists in the
+ die. */
+ Dwarf_Attribute stmt_list_attr = 0;
+
+ /* Pointer to DW_AT_comp_dir attribute in die. */
+ Dwarf_Attribute comp_dir_attr = 0;
+
+ /* Pointer to name of compilation directory. */
+ Dwarf_Small *comp_dir = NULL;
+
+ /*
+ Offset into .debug_line specified by a DW_AT_stmt_list
+ attribute. */
+ Dwarf_Unsigned line_offset = 0;
+
+ struct Line_Table_Prefix_s prefix;
+
+
+ /* These are the state machine state variables. */
+ Dwarf_Addr address = 0;
+ Dwarf_Word file = 1;
+ Dwarf_Word line = 1;
+ Dwarf_Word column = 0;
+ Dwarf_Bool is_stmt = false;
+ Dwarf_Bool basic_block = false;
+ Dwarf_Bool end_sequence = false;
+ Dwarf_Bool prologue_end = false;
+ Dwarf_Bool epilogue_begin = false;
+ Dwarf_Small isa = 0;
+
+
+ Dwarf_Sword i=0;
+
+ /*
+ This is the current opcode read from the statement program. */
+ Dwarf_Small opcode=0;
+
+
+ /*
+ These variables are used to decode leb128 numbers. Leb128_num
+ holds the decoded number, and leb128_length is its length in
+ bytes. */
+ Dwarf_Word leb128_num=0;
+ Dwarf_Word leb128_length=0;
+ Dwarf_Sword advance_line=0;
+ Dwarf_Half attrform = 0;
+ /*
+ This is the operand of the latest fixed_advance_pc extended
+ opcode. */
+ Dwarf_Half fixed_advance_pc=0;
+
+ /* In case there are wierd bytes 'after' the line table
+ * prologue this lets us print something. This is a gcc
+ * compiler bug and we expect the bytes count to be 12.
+ */
+ Dwarf_Small* bogus_bytes_ptr = 0;
+ Dwarf_Unsigned bogus_bytes_count = 0;
+
+
+ /* The Dwarf_Debug this die belongs to. */
+ Dwarf_Debug dbg=0;
+ int resattr = DW_DLV_ERROR;
+ int lres = DW_DLV_ERROR;
+ int res = DW_DLV_ERROR;
+
+ /* ***** BEGIN CODE ***** */
+
+ if (error != NULL) {
+ *error = NULL;
+ }
+
+ CHECK_DIE(die, DW_DLV_ERROR);
+ dbg = die->di_cu_context->cc_dbg;
+
+ res = _dwarf_load_section(dbg, &dbg->de_debug_line,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ resattr = dwarf_attr(die, DW_AT_stmt_list, &stmt_list_attr, error);
+ if (resattr != DW_DLV_OK) {
+ return resattr;
+ }
+
+
+ /* The list of relevant FORMs is small.
+ DW_FORM_data4, DW_FORM_data8, DW_FORM_sec_offset
+ */
+ lres = dwarf_whatform(stmt_list_attr,&attrform,error);
+ if (lres != DW_DLV_OK) {
+ return lres;
+ }
+ if (attrform != DW_FORM_data4 && attrform != DW_FORM_data8 &&
+ attrform != DW_FORM_sec_offset ) {
+ _dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD);
+ return (DW_DLV_ERROR);
+ }
+ lres = dwarf_global_formref(stmt_list_attr, &line_offset, error);
+ if (lres != DW_DLV_OK) {
+ return lres;
+ }
+
+ if (line_offset >= dbg->de_debug_line.dss_size) {
+ _dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD);
+ return (DW_DLV_ERROR);
+ }
+ orig_line_ptr = dbg->de_debug_line.dss_data;
+ line_ptr = dbg->de_debug_line.dss_data + line_offset;
+ dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR);
+
+ /*
+ If die has DW_AT_comp_dir attribute, get the string that names
+ the compilation directory. */
+ resattr = dwarf_attr(die, DW_AT_comp_dir, &comp_dir_attr, error);
+ if (resattr == DW_DLV_ERROR) {
+ return resattr;
+ }
+ if (resattr == DW_DLV_OK) {
+ int cres = DW_DLV_ERROR;
+ char *cdir = 0;
+
+ cres = dwarf_formstring(comp_dir_attr, &cdir, error);
+ if (cres == DW_DLV_ERROR) {
+ return cres;
+ } else if (cres == DW_DLV_OK) {
+ comp_dir = (Dwarf_Small *) cdir;
+ }
+ }
+ if (resattr == DW_DLV_OK) {
+ dwarf_dealloc(dbg, comp_dir_attr, DW_DLA_ATTR);
+ }
+
+ dwarf_init_line_table_prefix(&prefix);
+ {
+ Dwarf_Small *line_ptr_out = 0;
+ int dres = dwarf_read_line_table_prefix(dbg,
+ line_ptr,dbg->de_debug_line.dss_size - line_offset,
+ &line_ptr_out,
+ &prefix,
+ &bogus_bytes_ptr,
+ &bogus_bytes_count,
+ error,
+ err_count_out);
+ if (dres == DW_DLV_ERROR) {
+ dwarf_free_line_table_prefix(&prefix);
+ return dres;
+ }
+ if (dres == DW_DLV_NO_ENTRY) {
+ dwarf_free_line_table_prefix(&prefix);
+ return dres;
+ }
+ line_ptr_end = prefix.pf_line_ptr_end;
+ line_ptr = line_ptr_out;
+ }
+ if(only_line_header) {
+ /* Just checking for header errors, nothing more here.*/
+ dwarf_free_line_table_prefix(&prefix);
+ return DW_DLV_OK;
+ }
+
+
+ printf("total line info length %ld bytes, "
+ "line offset 0x%" DW_PR_DUx " %" DW_PR_DSd "\n",
+ (long) prefix.pf_total_length,
+ (Dwarf_Unsigned) line_offset,
+ (Dwarf_Signed) line_offset);
+ printf("line table version %d\n",(int) prefix.pf_version);
+ printf("line table length field length %d prologue length %d\n",
+ (int)prefix.pf_length_field_length,
+ (int)prefix.pf_prologue_length);
+ printf("compilation_directory %s\n",
+ comp_dir ? ((char *) comp_dir) : "");
+
+ printf(" min instruction length %d\n",
+ (int) prefix.pf_minimum_instruction_length);
+ printf(" default is stmt %d\n", (int)
+ prefix.pf_default_is_stmt);
+ printf(" line base %d\n", (int)
+ prefix.pf_line_base);
+ printf(" line_range %d\n", (int)
+ prefix.pf_line_range);
+ printf(" opcode base %d\n", (int)
+ prefix.pf_opcode_base);
+ printf(" standard opcode count %d\n", (int)
+ prefix.pf_std_op_count);
+
+ for (i = 1; i < prefix.pf_opcode_base; i++) {
+ printf(" opcode[%2d] length %d\n", (int) i,
+ (int) prefix.pf_opcode_length_table[i - 1]);
+ }
+ printf(" include directories count %d\n", (int)
+ prefix.pf_include_directories_count);
+
+
+ for (i = 0; i < prefix.pf_include_directories_count; ++i) {
+ printf(" include dir[%d] %s\n",
+ (int) i, prefix.pf_include_directories[i]);
+ }
+ printf(" files count %d\n", (int)
+ prefix.pf_files_count);
+
+ for (i = 0; i < prefix.pf_files_count; ++i) {
+ struct Line_Table_File_Entry_s *lfile =
+ prefix.pf_line_table_file_entries + i;
+
+ Dwarf_Unsigned tlm2 = lfile->lte_last_modification_time;
+ Dwarf_Unsigned di = lfile->lte_directory_index;
+ Dwarf_Unsigned fl = lfile->lte_length_of_file;
+
+ printf(" file[%d] %s (file-number: %d) \n",
+ (int) i, (char *) lfile->lte_filename,
+ (int)(i+1));
+
+ printf(" dir index %d\n", (int) di);
+ {
+ time_t tt = (time_t) tlm2;
+
+ printf(" last time 0x%x %s", /* ctime supplies
+ newline */
+ (unsigned) tlm2, ctime(&tt));
+ }
+ printf(" file length %ld 0x%lx\n",
+ (long) fl, (unsigned long) fl);
+
+
+ }
+
+
+ {
+ Dwarf_Unsigned offset = 0;
+ if(bogus_bytes_count > 0) {
+ Dwarf_Unsigned wcount = bogus_bytes_count;
+ Dwarf_Unsigned boffset = bogus_bytes_ptr - orig_line_ptr;
+ printf("*** DWARF CHECK: the line table prologue header_length "
+ " is %" DW_PR_DUu " too high, we pretend it is smaller."
+ "Section offset: %" DW_PR_DUu " (0x%" DW_PR_DUx ") ***\n",
+ wcount, boffset,boffset);
+ *err_count_out += 1;
+ }
+ offset = line_ptr - orig_line_ptr;
+
+ printf(" statement prog offset in section: %" DW_PR_DUu " 0x%" DW_PR_DUx "\n",
+ offset, offset);
+ }
+
+ /* Initialize the part of the state machine dependent on the
+ prefix. */
+ is_stmt = prefix.pf_default_is_stmt;
+
+
+ print_line_header();
+ /* Start of statement program. */
+ while (line_ptr < line_ptr_end) {
+ int type = 0;
+
+ printf(" [0x%06" DW_PR_DSx "] ",
+ (Dwarf_Signed) (line_ptr - orig_line_ptr));
+ opcode = *(Dwarf_Small *) line_ptr;
+ line_ptr++;
+ /* 'type' is the output */
+ WHAT_IS_OPCODE(type, opcode, prefix.pf_opcode_base,
+ prefix.pf_opcode_length_table, line_ptr,
+ prefix.pf_std_op_count);
+
+ if (type == LOP_DISCARD) {
+ int oc;
+ int opcnt = prefix.pf_opcode_length_table[opcode];
+
+ printf("*** DWARF CHECK: DISCARD standard opcode %d "
+ "with %d operands: "
+ "not understood.", opcode, opcnt);
+ *err_count_out += 1;
+ for (oc = 0; oc < opcnt; oc++) {
+ /*
+ * Read and discard operands we don't
+ * understand.
+ * Arbitrary choice of unsigned read.
+ * Signed read would work as well.
+ */
+ Dwarf_Unsigned utmp2;
+
+ DECODE_LEB128_UWORD(line_ptr, utmp2);
+ printf(" %" DW_PR_DUu " (0x%" DW_PR_DUx ")",
+ (Dwarf_Unsigned) utmp2,
+ (Dwarf_Unsigned) utmp2);
+ }
+
+ printf("***\n");
+ /* do nothing, necessary ops done */
+ } else if (type == LOP_SPECIAL) {
+ /* This op code is a special op in the object, no matter
+ that it might fall into the standard op range in this
+ compile Thatis, these are special opcodes between
+ special_opcode_base and MAX_LINE_OP_CODE. (including
+ special_opcode_base and MAX_LINE_OP_CODE) */
+ char special[50];
+ unsigned origop = opcode;
+
+ opcode = opcode - prefix.pf_opcode_base;
+ address = address + prefix.pf_minimum_instruction_length *
+ (opcode / prefix.pf_line_range);
+ line =
+ line + prefix.pf_line_base +
+ opcode % prefix.pf_line_range;
+
+ sprintf(special, "Specialop %3u", origop);
+ print_line_detail(special,
+ opcode, address, (int) file, line, column,
+ is_stmt, basic_block, end_sequence,
+ prologue_end, epilogue_begin, isa);
+
+ basic_block = false;
+
+ } else if (type == LOP_STANDARD) {
+ switch (opcode) {
+
+ case DW_LNS_copy:{
+
+ print_line_detail("DW_LNS_copy",
+ opcode, address, file, line,
+ column, is_stmt, basic_block,
+ end_sequence, prologue_end,
+ epilogue_begin, isa);
+
+ basic_block = false;
+ break;
+ }
+
+ case DW_LNS_advance_pc:{
+ Dwarf_Unsigned utmp2;
+
+
+ DECODE_LEB128_UWORD(line_ptr, utmp2);
+ printf("DW_LNS_advance_pc val %" DW_PR_DSd " 0x%" DW_PR_DUx "\n",
+ (Dwarf_Signed) (Dwarf_Word) utmp2,
+ (Dwarf_Unsigned) (Dwarf_Word) utmp2);
+ leb128_num = (Dwarf_Word) utmp2;
+ address =
+ address +
+ prefix.pf_minimum_instruction_length *
+ leb128_num;
+ break;
+ }
+
+ case DW_LNS_advance_line:{
+ Dwarf_Signed stmp;
+
+
+ DECODE_LEB128_SWORD(line_ptr, stmp);
+ advance_line = (Dwarf_Sword) stmp;
+ printf("DW_LNS_advance_line val %" DW_PR_DSd " 0x%" DW_PR_DSx "\n",
+ (Dwarf_Signed) advance_line,
+ (Dwarf_Signed) advance_line);
+ line = line + advance_line;
+ break;
+ }
+
+ case DW_LNS_set_file:{
+ Dwarf_Unsigned utmp2;
+
+
+ DECODE_LEB128_UWORD(line_ptr, utmp2);
+ file = (Dwarf_Word) utmp2;
+ printf("DW_LNS_set_file %ld\n", (long) file);
+ break;
+ }
+
+ case DW_LNS_set_column:{
+ Dwarf_Unsigned utmp2;
+
+
+ DECODE_LEB128_UWORD(line_ptr, utmp2);
+ column = (Dwarf_Word) utmp2;
+ printf("DW_LNS_set_column val %" DW_PR_DSd " 0x%" DW_PR_DSx "\n",
+ (Dwarf_Signed) column, (Dwarf_Signed) column);
+ break;
+ }
+
+ case DW_LNS_negate_stmt:{
+ is_stmt = !is_stmt;
+ printf("DW_LNS_negate_stmt\n");
+ break;
+ }
+
+ case DW_LNS_set_basic_block:{
+
+ printf("DW_LNS_set_basic_block\n");
+ basic_block = true;
+ break;
+ }
+
+ case DW_LNS_const_add_pc:{
+ opcode = MAX_LINE_OP_CODE - prefix.pf_opcode_base;
+ address =
+ address +
+ prefix.pf_minimum_instruction_length * (opcode /
+ prefix.
+ pf_line_range);
+
+ printf("DW_LNS_const_add_pc new address 0x%" DW_PR_DSx "\n",
+ (Dwarf_Signed) address);
+ break;
+ }
+
+ case DW_LNS_fixed_advance_pc:{
+
+ READ_UNALIGNED(dbg, fixed_advance_pc, Dwarf_Half,
+ line_ptr, sizeof(Dwarf_Half));
+ line_ptr += sizeof(Dwarf_Half);
+ address = address + fixed_advance_pc;
+ printf("DW_LNS_fixed_advance_pc val %" DW_PR_DSd
+ " 0x%" DW_PR_DSx " new address 0x%" DW_PR_DSx "\n",
+ (Dwarf_Signed) fixed_advance_pc,
+ (Dwarf_Signed) fixed_advance_pc,
+ (Dwarf_Signed) address);
+ break;
+ }
+ case DW_LNS_set_prologue_end:{
+
+ prologue_end = true;
+ printf("DW_LNS_set_prologue_end set true.\n");
+ break;
+
+
+ }
+ /* New in DWARF3 */
+ case DW_LNS_set_epilogue_begin:{
+ epilogue_begin = true;
+ printf("DW_LNS_set_epilogue_begin set true.\n");
+ break;
+ }
+
+ /* New in DWARF3 */
+ case DW_LNS_set_isa:{
+ Dwarf_Unsigned utmp2;
+
+ DECODE_LEB128_UWORD(line_ptr, utmp2);
+ isa = utmp2;
+ printf("DW_LNS_set_isa new value 0x%" DW_PR_DUx ".\n",
+ (Dwarf_Unsigned) utmp2);
+ if (isa != utmp2) {
+ /* The value of the isa did not fit in our
+ local so we record it wrong. declare an
+ error. */
+ dwarf_free_line_table_prefix(&prefix);
+
+ _dwarf_error(dbg, error,
+ DW_DLE_LINE_NUM_OPERANDS_BAD);
+ return (DW_DLV_ERROR);
+ }
+ break;
+ }
+ }
+
+
+ } else if (type == LOP_EXTENDED) {
+ Dwarf_Unsigned utmp3 = 0;
+ Dwarf_Word instr_length = 0;
+ Dwarf_Small ext_opcode = 0;
+
+ DECODE_LEB128_UWORD(line_ptr, utmp3);
+ instr_length = (Dwarf_Word) utmp3;
+ ext_opcode = *(Dwarf_Small *) line_ptr;
+ line_ptr++;
+ switch (ext_opcode) {
+
+ case DW_LNE_end_sequence:{
+ end_sequence = true;
+
+ print_line_detail("DW_LNE_end_sequence extended",
+ opcode, address, file, line,
+ column, is_stmt, basic_block,
+ end_sequence, prologue_end,
+ epilogue_begin, isa);
+
+ address = 0;
+ file = 1;
+ line = 1;
+ column = 0;
+ is_stmt = prefix.pf_default_is_stmt;
+ basic_block = false;
+ end_sequence = false;
+ prologue_end = false;
+ epilogue_begin = false;
+
+
+ break;
+ }
+
+ case DW_LNE_set_address:{
+ {
+ READ_UNALIGNED(dbg, address, Dwarf_Addr,
+ line_ptr,
+ die->di_cu_context->cc_address_size);
+
+ line_ptr += die->di_cu_context->cc_address_size;
+ printf("DW_LNE_set_address address 0x%" DW_PR_DUx "\n",
+ (Dwarf_Unsigned) address);
+ }
+
+ break;
+ }
+
+ case DW_LNE_define_file:{
+ Dwarf_Unsigned di = 0;
+ Dwarf_Unsigned tlm = 0;
+ Dwarf_Unsigned fl = 0;
+
+ Dwarf_Small *fn = (Dwarf_Small *) line_ptr;
+ line_ptr = line_ptr + strlen((char *) line_ptr) + 1;
+
+ di = _dwarf_decode_u_leb128(line_ptr,
+ &leb128_length);
+ line_ptr = line_ptr + leb128_length;
+
+ tlm = _dwarf_decode_u_leb128(line_ptr,
+ &leb128_length);
+ line_ptr = line_ptr + leb128_length;
+
+ fl = _dwarf_decode_u_leb128(line_ptr,
+ &leb128_length);
+ line_ptr = line_ptr + leb128_length;
+
+
+ printf("DW_LNE_define_file %s \n", fn);
+ printf(" dir index %d\n", (int) di);
+ {
+ time_t tt3 = (time_t) tlm;
+
+ /* ctime supplies newline */
+ printf(" last time 0x%x %s",
+ (unsigned) tlm, ctime(&tt3));
+ }
+ printf(" file length %ld 0x%lx\n",
+ (long) fl, (unsigned long) fl);
+
+ break;
+ }
+
+ default:{
+ /* This is an extended op code we do not know about,
+ other than we know now many bytes it is
+ (and the op code and the bytes of operand). */
+
+ Dwarf_Unsigned remaining_bytes = instr_length -1;
+ if(instr_length < 1 || remaining_bytes > DW_LNE_LEN_MAX) {
+ dwarf_free_line_table_prefix(&prefix);
+ _dwarf_error(dbg, error,
+ DW_DLE_LINE_EXT_OPCODE_BAD);
+ return (DW_DLV_ERROR);
+ }
+ printf("DW_LNE extended op 0x%x ",ext_opcode);
+ printf("Bytecount: " DW_PR_DUu , instr_length);
+ if(remaining_bytes > 0) {
+ printf(" linedata: 0x");
+ while (remaining_bytes > 0) {
+ printf("%02x",(unsigned char)(*(line_ptr)));
+ line_ptr++;
+ remaining_bytes--;
+ }
+ }
+ printf("\n");
+ }
+ break;
+ }
+
+ }
+ }
+
+ dwarf_free_line_table_prefix(&prefix);
+ return (DW_DLV_OK);
+}
+
+/*
+ This is support for dwarfdump: making it possible
+ for clients wanting line detail info on stdout
+ to get that detail without including internal libdwarf
+ header information.
+ Caller passes in compilation unit DIE.
+ The _dwarf_ version is obsolete (though supported for
+ compatibility).
+ The dwarf_ version is preferred.
+ The functions are intentionally identical: having
+ _dwarf_print_lines call dwarf_print_lines might
+ better emphasize they are intentionally identical, but
+ that seemed slightly silly given how short the functions are.
+ Interface adds error_count (output value) February 2009.
+*/
+int
+dwarf_print_lines(Dwarf_Die die, Dwarf_Error * error,int *error_count)
+{
+ int only_line_header = 0;
+ int res = _dwarf_internal_printlines(die, error,
+ error_count,
+ only_line_header);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ return res;
+}
+int
+_dwarf_print_lines(Dwarf_Die die, Dwarf_Error * error)
+{
+ int only_line_header = 0;
+ int err_count = 0;
+ int res = _dwarf_internal_printlines(die, error,
+ &err_count,
+ only_line_header);
+ /* No way to get error count back in this interface */
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ return res;
+}
+
+/* The check is in case we are not printing full line data,
+ this gets some of the issues noted with .debug_line,
+ but not all. Call dwarf_print_lines() to get all issues.
+ Intended for apps like dwarfdump.
+*/
+void
+dwarf_check_lineheader(Dwarf_Die die, int *err_count_out)
+{
+ Dwarf_Error err;
+ int only_line_header = 1;
+ _dwarf_internal_printlines(die, &err,err_count_out,
+ only_line_header);
+ return;
+}
+
diff --git a/usr/src/lib/libdwarf/common/dwarf_pubtypes.c b/usr/src/lib/libdwarf/common/dwarf_pubtypes.c
new file mode 100644
index 0000000000..330c1c6adc
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_pubtypes.c
@@ -0,0 +1,138 @@
+/*
+
+ Copyright (C) 2000,2002,2004,2005 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2009-2010 David Anderson. 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
+
+*/
+
+/* Reads DWARF3 .debug_pubtypes section. */
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+#include "dwarf_types.h"
+#include "dwarf_global.h"
+
+int
+dwarf_get_pubtypes(Dwarf_Debug dbg,
+ Dwarf_Type ** types,
+ Dwarf_Signed * ret_type_count, Dwarf_Error * error)
+{
+ int res = _dwarf_load_section(dbg, &dbg->de_debug_pubtypes,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ return _dwarf_internal_get_pubnames_like_data(dbg,
+ dbg->de_debug_pubtypes.dss_data,
+ dbg->de_debug_pubtypes.dss_size,
+ (Dwarf_Global **) types, /* Type punning for sections
+ with identical format. */
+ ret_type_count, error,
+ DW_DLA_PUBTYPES_CONTEXT,
+ DW_DLA_GLOBAL, /* We don't have DW_DLA_PUBTYPES,
+ so use DW_DLA_GLOBAL. */
+ DW_DLE_DEBUG_PUBTYPES_LENGTH_BAD,
+ DW_DLE_DEBUG_PUBTYPES_VERSION_ERROR);
+}
+
+/* Deallocating fully requires deallocating the list
+ and all entries. But some internal data is
+ not exposed, so we need a function with internal knowledge.
+*/
+
+void
+dwarf_pubtypes_dealloc(Dwarf_Debug dbg, Dwarf_Type * dwgl,
+ Dwarf_Signed count)
+{
+ _dwarf_internal_globals_dealloc(dbg,
+ (Dwarf_Global *) dwgl,
+ count,
+ DW_DLA_PUBTYPES_CONTEXT,
+ DW_DLA_GLOBAL, /* We don't have DW_DLA_PUBTYPES,
+ so use DW_DLA_GLOBAL. */
+ DW_DLA_LIST);
+ return;
+}
+
+
+
+int
+dwarf_pubtypename(Dwarf_Type type_in, char **ret_name,
+ Dwarf_Error * error)
+{
+ Dwarf_Global type = (Dwarf_Global) type_in;
+ if (type == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_TYPE_NULL);
+ return (DW_DLV_ERROR);
+ }
+ *ret_name = (char *) (type->gl_name);
+ return DW_DLV_OK;
+}
+
+
+int
+dwarf_pubtype_type_die_offset(Dwarf_Type type_in,
+ Dwarf_Off * ret_offset,
+ Dwarf_Error * error)
+{
+ Dwarf_Global type = (Dwarf_Global) type_in;
+
+ return dwarf_global_die_offset(type, ret_offset, error);
+}
+
+
+int
+dwarf_pubtype_cu_offset(Dwarf_Type type_in,
+ Dwarf_Off * ret_offset, Dwarf_Error * error)
+{
+ Dwarf_Global type = (Dwarf_Global) type_in;
+
+ return dwarf_global_cu_offset(type, ret_offset, error);
+
+}
+
+
+int
+dwarf_pubtype_name_offsets(Dwarf_Type type_in,
+ char **returned_name,
+ Dwarf_Off * die_offset,
+ Dwarf_Off * cu_die_offset,
+ Dwarf_Error * error)
+{
+ Dwarf_Global type = (Dwarf_Global) type_in;
+
+ return dwarf_global_name_offsets(type,
+ returned_name,
+ die_offset, cu_die_offset, error);
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_query.c b/usr/src/lib/libdwarf/common/dwarf_query.c
new file mode 100644
index 0000000000..3f21abd039
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_query.c
@@ -0,0 +1,789 @@
+/*
+
+ Copyright (C) 2000,2002,2004 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2007-2010 David Anderson. 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
+
+*/
+/* The address of the Free Software Foundation is
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ SGI has moved from the Crittenden Lane address.
+*/
+
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+#include "dwarf_die_deliv.h"
+
+/* This is normally reliable.
+But not always.
+If different compilation
+units have different address sizes
+this may not give the correct value in all contexts.
+If the Elf offset size != address_size
+(for example if address_size = 4 but recorded in elf64 object)
+this may not give the correct value in all contexts.
+*/
+int
+dwarf_get_address_size(Dwarf_Debug dbg,
+ Dwarf_Half * ret_addr_size, Dwarf_Error * error)
+{
+ Dwarf_Half address_size = 0;
+
+ if (dbg == 0) {
+ _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ address_size = dbg->de_pointer_size;
+ *ret_addr_size = address_size;
+ return DW_DLV_OK;
+}
+
+/* This will be correct in all contexts where the
+ CU context of a DIE is known.
+*/
+int
+dwarf_get_die_address_size(Dwarf_Die die,
+ Dwarf_Half * ret_addr_size, Dwarf_Error * error)
+{
+ Dwarf_Half address_size = 0;
+ CHECK_DIE(die, DW_DLV_ERROR);
+ address_size = die->di_cu_context->cc_address_size;
+ *ret_addr_size = address_size;
+ return DW_DLV_OK;
+}
+
+int
+dwarf_dieoffset(Dwarf_Die die,
+ Dwarf_Off * ret_offset, Dwarf_Error * error)
+{
+ CHECK_DIE(die, DW_DLV_ERROR);
+
+ *ret_offset = (die->di_debug_info_ptr -
+ die->di_cu_context->cc_dbg->de_debug_info.dss_data);
+ return DW_DLV_OK;
+}
+
+
+/*
+ This function returns the offset of
+ the die relative to the start of its
+ compilation-unit rather than .debug_info.
+ Returns DW_DLV_ERROR on error.
+*/
+int
+dwarf_die_CU_offset(Dwarf_Die die,
+ Dwarf_Off * cu_off, Dwarf_Error * error)
+{
+ Dwarf_CU_Context cu_context = 0;
+
+ CHECK_DIE(die, DW_DLV_ERROR);
+ cu_context = die->di_cu_context;
+
+ *cu_off =
+ (die->di_debug_info_ptr - cu_context->cc_dbg->de_debug_info.dss_data -
+ cu_context->cc_debug_info_offset);
+ return DW_DLV_OK;
+}
+
+/*
+ This function returns the global offset
+ (meaning the section offset) and length of
+ the CU that this die is a part of.
+ Used for correctness checking by dwarfdump.
+*/
+int
+dwarf_die_CU_offset_range(Dwarf_Die die,
+ Dwarf_Off * cu_off,
+ Dwarf_Off * cu_length,
+ Dwarf_Error * error)
+{
+ Dwarf_CU_Context cu_context = 0;
+
+ CHECK_DIE(die, DW_DLV_ERROR);
+ cu_context = die->di_cu_context;
+
+ *cu_off = cu_context->cc_debug_info_offset;
+ *cu_length = cu_context->cc_length + cu_context->cc_length_size
+ + cu_context->cc_extension_size;
+ return DW_DLV_OK;
+}
+
+
+
+int
+dwarf_tag(Dwarf_Die die, Dwarf_Half * tag, Dwarf_Error * error)
+{
+ CHECK_DIE(die, DW_DLV_ERROR);
+ *tag = (die->di_abbrev_list->ab_tag);
+ return DW_DLV_OK;
+}
+
+
+int
+dwarf_attrlist(Dwarf_Die die,
+ Dwarf_Attribute ** attrbuf,
+ Dwarf_Signed * attrcnt, Dwarf_Error * error)
+{
+ Dwarf_Word attr_count = 0;
+ Dwarf_Word i = 0;
+ Dwarf_Half attr = 0;
+ Dwarf_Half attr_form = 0;
+ Dwarf_Byte_Ptr abbrev_ptr = 0;
+ Dwarf_Abbrev_List abbrev_list = 0;
+ Dwarf_Attribute new_attr = 0;
+ Dwarf_Attribute head_attr = NULL;
+ Dwarf_Attribute curr_attr = NULL;
+ Dwarf_Attribute *attr_ptr = 0;
+ Dwarf_Debug dbg = 0;
+ Dwarf_Byte_Ptr info_ptr = 0;
+
+ CHECK_DIE(die, DW_DLV_ERROR);
+ dbg = die->di_cu_context->cc_dbg;
+
+ abbrev_list = _dwarf_get_abbrev_for_code(die->di_cu_context,
+ die->di_abbrev_list->
+ ab_code);
+ if (abbrev_list == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_DIE_ABBREV_BAD);
+ return (DW_DLV_ERROR);
+ }
+ abbrev_ptr = abbrev_list->ab_abbrev_ptr;
+
+ info_ptr = die->di_debug_info_ptr;
+ SKIP_LEB128_WORD(info_ptr);
+
+ do {
+ Dwarf_Unsigned utmp2;
+
+ DECODE_LEB128_UWORD(abbrev_ptr, utmp2);
+ attr = (Dwarf_Half) utmp2;
+ DECODE_LEB128_UWORD(abbrev_ptr, utmp2);
+ attr_form = (Dwarf_Half) utmp2;
+
+ if (attr != 0) {
+ new_attr =
+ (Dwarf_Attribute) _dwarf_get_alloc(dbg, DW_DLA_ATTR, 1);
+ if (new_attr == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ new_attr->ar_attribute = attr;
+ new_attr->ar_attribute_form_direct = attr_form;
+ new_attr->ar_attribute_form = attr_form;
+ if (attr_form == DW_FORM_indirect) {
+ Dwarf_Unsigned utmp6;
+
+ /* DECODE_LEB128_UWORD does info_ptr update */
+ DECODE_LEB128_UWORD(info_ptr, utmp6);
+ attr_form = (Dwarf_Half) utmp6;
+ new_attr->ar_attribute_form = attr_form;
+ }
+ new_attr->ar_cu_context = die->di_cu_context;
+ new_attr->ar_debug_info_ptr = info_ptr;
+
+ {
+ Dwarf_Unsigned sov = _dwarf_get_size_of_val(dbg,
+ attr_form,
+ die->di_cu_context->cc_address_size,
+ info_ptr,
+ die->di_cu_context->cc_length_size);
+ info_ptr += sov;
+ }
+
+
+ if (head_attr == NULL)
+ head_attr = curr_attr = new_attr;
+ else {
+ curr_attr->ar_next = new_attr;
+ curr_attr = new_attr;
+ }
+ attr_count++;
+ }
+ } while (attr != 0 || attr_form != 0);
+
+ if (attr_count == 0) {
+ *attrbuf = NULL;
+ *attrcnt = 0;
+ return (DW_DLV_NO_ENTRY);
+ }
+
+ attr_ptr = (Dwarf_Attribute *)
+ _dwarf_get_alloc(dbg, DW_DLA_LIST, attr_count);
+ if (attr_ptr == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ curr_attr = head_attr;
+ for (i = 0; i < attr_count; i++) {
+ *(attr_ptr + i) = curr_attr;
+ curr_attr = curr_attr->ar_next;
+ }
+
+ *attrbuf = attr_ptr;
+ *attrcnt = attr_count;
+ return (DW_DLV_OK);
+}
+
+
+/*
+ This function takes a die, and an attr, and returns
+ a pointer to the start of the value of that attr in
+ the given die in the .debug_info section. The form
+ is returned in *attr_form.
+
+ Returns NULL on error, or if attr is not found.
+ However, *attr_form is 0 on error, and positive
+ otherwise.
+*/
+static Dwarf_Byte_Ptr
+_dwarf_get_value_ptr(Dwarf_Die die,
+ Dwarf_Half attr, Dwarf_Half * attr_form)
+{
+ Dwarf_Byte_Ptr abbrev_ptr = 0;
+ Dwarf_Abbrev_List abbrev_list;
+ Dwarf_Half curr_attr = 0;
+ Dwarf_Half curr_attr_form = 0;
+ Dwarf_Byte_Ptr info_ptr = 0;
+
+ abbrev_list = _dwarf_get_abbrev_for_code(die->di_cu_context,
+ die->di_abbrev_list->ab_code);
+ if (abbrev_list == NULL) {
+ *attr_form = 0;
+ return (NULL);
+ }
+ abbrev_ptr = abbrev_list->ab_abbrev_ptr;
+
+ info_ptr = die->di_debug_info_ptr;
+ SKIP_LEB128_WORD(info_ptr);
+
+ do {
+ Dwarf_Unsigned utmp3;
+
+ DECODE_LEB128_UWORD(abbrev_ptr, utmp3);
+ curr_attr = (Dwarf_Half) utmp3;
+ DECODE_LEB128_UWORD(abbrev_ptr, utmp3);
+ curr_attr_form = (Dwarf_Half) utmp3;
+ if (curr_attr_form == DW_FORM_indirect) {
+ Dwarf_Unsigned utmp6;
+
+ /* DECODE_LEB128_UWORD updates info_ptr */
+ DECODE_LEB128_UWORD(info_ptr, utmp6);
+ curr_attr_form = (Dwarf_Half) utmp6;
+ }
+
+ if (curr_attr == attr) {
+ *attr_form = curr_attr_form;
+ return (info_ptr);
+ }
+
+ info_ptr += _dwarf_get_size_of_val(die->di_cu_context->cc_dbg,
+ curr_attr_form,
+ die->di_cu_context->cc_address_size,
+ info_ptr,
+ die->di_cu_context->cc_length_size);
+ } while (curr_attr != 0 || curr_attr_form != 0);
+
+ *attr_form = 1;
+ return (NULL);
+}
+
+
+int
+dwarf_diename(Dwarf_Die die, char **ret_name, Dwarf_Error * error)
+{
+ Dwarf_Half attr_form = 0;
+ Dwarf_Debug dbg = 0;
+ Dwarf_Byte_Ptr info_ptr = 0;
+ Dwarf_Unsigned string_offset = 0;
+ int res = DW_DLV_ERROR;
+
+ CHECK_DIE(die, DW_DLV_ERROR);
+
+ info_ptr = _dwarf_get_value_ptr(die, DW_AT_name, &attr_form);
+ if (info_ptr == NULL) {
+ if (attr_form == 0) {
+ _dwarf_error(die->di_cu_context->cc_dbg, error,
+ DW_DLE_DIE_BAD);
+ return (DW_DLV_ERROR);
+ }
+ return DW_DLV_NO_ENTRY;
+ }
+
+ if (attr_form == DW_FORM_string) {
+ *ret_name = (char *) (info_ptr);
+ return DW_DLV_OK;
+ }
+
+ dbg = die->di_cu_context->cc_dbg;
+ if (attr_form != DW_FORM_strp) {
+ _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_BAD);
+ return (DW_DLV_ERROR);
+ }
+
+ READ_UNALIGNED(dbg, string_offset, Dwarf_Unsigned,
+ info_ptr, die->di_cu_context->cc_length_size);
+
+ if (string_offset >= dbg->de_debug_str.dss_size) {
+ _dwarf_error(dbg, error, DW_DLE_STRING_OFFSET_BAD);
+ return (DW_DLV_ERROR);
+ }
+
+ res = _dwarf_load_section(dbg, &dbg->de_debug_str,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ *ret_name = (char *) (dbg->de_debug_str.dss_data + string_offset);
+ return DW_DLV_OK;
+}
+
+
+int
+dwarf_hasattr(Dwarf_Die die,
+ Dwarf_Half attr,
+ Dwarf_Bool * return_bool, Dwarf_Error * error)
+{
+ Dwarf_Half attr_form = 0;
+
+ CHECK_DIE(die, DW_DLV_ERROR);
+
+ if (_dwarf_get_value_ptr(die, attr, &attr_form) == NULL) {
+ if (attr_form == 0) {
+ _dwarf_error(die->di_cu_context->cc_dbg, error,
+ DW_DLE_DIE_BAD);
+ return (DW_DLV_ERROR);
+ }
+ *return_bool = false;
+ return DW_DLV_OK;
+ }
+
+ *return_bool = (true);
+ return DW_DLV_OK;
+}
+
+
+int
+dwarf_attr(Dwarf_Die die,
+ Dwarf_Half attr,
+ Dwarf_Attribute * ret_attr, Dwarf_Error * error)
+{
+ Dwarf_Half attr_form = 0;
+ Dwarf_Attribute attrib = 0;
+ Dwarf_Byte_Ptr info_ptr = 0;
+ Dwarf_Debug dbg = 0;
+
+ CHECK_DIE(die, DW_DLV_ERROR);
+ dbg = die->di_cu_context->cc_dbg;
+
+ info_ptr = _dwarf_get_value_ptr(die, attr, &attr_form);
+ if (info_ptr == NULL) {
+ if (attr_form == 0) {
+ _dwarf_error(dbg, error, DW_DLE_DIE_BAD);
+ return (DW_DLV_ERROR);
+ }
+ return DW_DLV_NO_ENTRY;
+ }
+
+ attrib = (Dwarf_Attribute) _dwarf_get_alloc(dbg, DW_DLA_ATTR, 1);
+ if (attrib == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (DW_DLV_ERROR);
+ }
+
+ attrib->ar_attribute = attr;
+ attrib->ar_attribute_form = attr_form;
+ attrib->ar_attribute_form_direct = attr_form;
+ attrib->ar_cu_context = die->di_cu_context;
+ attrib->ar_debug_info_ptr = info_ptr;
+ *ret_attr = (attrib);
+ return DW_DLV_OK;
+}
+
+
+int
+dwarf_lowpc(Dwarf_Die die,
+ Dwarf_Addr * return_addr, Dwarf_Error * error)
+{
+ Dwarf_Addr ret_addr = 0;
+ Dwarf_Byte_Ptr info_ptr = 0;
+ Dwarf_Half attr_form = 0;
+ Dwarf_Debug dbg = 0;
+ Dwarf_Half address_size = 0;
+
+ CHECK_DIE(die, DW_DLV_ERROR);
+
+ dbg = die->di_cu_context->cc_dbg;
+ address_size = die->di_cu_context->cc_address_size;
+ info_ptr = _dwarf_get_value_ptr(die, DW_AT_low_pc, &attr_form);
+ if ((info_ptr == NULL && attr_form == 0) ||
+ (info_ptr != NULL && attr_form != DW_FORM_addr)) {
+ _dwarf_error(dbg, error, DW_DLE_DIE_BAD);
+ return (DW_DLV_ERROR);
+ }
+ if (info_ptr == NULL) {
+ return (DW_DLV_NO_ENTRY);
+ }
+
+
+ READ_UNALIGNED(dbg, ret_addr, Dwarf_Addr,
+ info_ptr, address_size);
+
+ *return_addr = ret_addr;
+ return (DW_DLV_OK);
+}
+
+
+int
+dwarf_highpc(Dwarf_Die die,
+ Dwarf_Addr * return_addr, Dwarf_Error * error)
+{
+ Dwarf_Addr ret_addr = 0;
+ Dwarf_Byte_Ptr info_ptr = 0;
+ Dwarf_Half attr_form = 0;
+ Dwarf_Debug dbg = 0;
+ Dwarf_Half address_size = 0;
+
+ CHECK_DIE(die, DW_DLV_ERROR);
+ dbg = die->di_cu_context->cc_dbg;
+ address_size = die->di_cu_context->cc_address_size;
+ info_ptr = _dwarf_get_value_ptr(die, DW_AT_high_pc, &attr_form);
+ if ((info_ptr == NULL && attr_form == 0) ||
+ (info_ptr != NULL && attr_form != DW_FORM_addr)) {
+ _dwarf_error(dbg, error, DW_DLE_DIE_BAD);
+ return (DW_DLV_ERROR);
+ }
+ if (info_ptr == NULL) {
+ return (DW_DLV_NO_ENTRY);
+ }
+
+ READ_UNALIGNED(dbg, ret_addr, Dwarf_Addr,
+ info_ptr, address_size);
+
+ *return_addr = ret_addr;
+ return (DW_DLV_OK);
+}
+
+
+/*
+ Takes a die, an attribute attr, and checks if attr
+ occurs in die. Attr is required to be an attribute
+ whose form is in the "constant" class. If attr occurs
+ in die, the value is returned.
+ Returns DW_DLV_OK, DW_DLV_ERROR, or DW_DLV_NO_ENTRY as
+ appropriate. Sets the value thru the pointer return_val.
+ This function is meant to do all the
+ processing for dwarf_bytesize, dwarf_bitsize, dwarf_bitoffset,
+ and dwarf_srclang.
+*/
+static int
+_dwarf_die_attr_unsigned_constant(Dwarf_Die die,
+ Dwarf_Half attr,
+ Dwarf_Unsigned * return_val,
+ Dwarf_Error * error)
+{
+ Dwarf_Byte_Ptr info_ptr;
+ Dwarf_Half attr_form;
+ Dwarf_Unsigned ret_value;
+ Dwarf_Debug dbg;
+
+ CHECK_DIE(die, DW_DLV_ERROR);
+
+ dbg = die->di_cu_context->cc_dbg;
+ info_ptr = _dwarf_get_value_ptr(die, attr, &attr_form);
+ if (info_ptr != NULL) {
+ switch (attr_form) {
+
+ case DW_FORM_data1:
+ *return_val = (*(Dwarf_Small *) info_ptr);
+ return (DW_DLV_OK);
+
+ case DW_FORM_data2:
+ READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
+ info_ptr, sizeof(Dwarf_Shalf));
+ *return_val = ret_value;
+ return (DW_DLV_OK);
+
+ case DW_FORM_data4:
+ READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
+ info_ptr, sizeof(Dwarf_sfixed));
+ *return_val = ret_value;
+ return (DW_DLV_OK);
+
+ case DW_FORM_data8:
+ READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
+ info_ptr, sizeof(Dwarf_Unsigned));
+ *return_val = ret_value;
+ return (DW_DLV_OK);
+
+ case DW_FORM_udata:
+ *return_val = (_dwarf_decode_u_leb128(info_ptr, NULL));
+ return (DW_DLV_OK);
+
+ default:
+ _dwarf_error(dbg, error, DW_DLE_DIE_BAD);
+ return (DW_DLV_ERROR);
+ }
+ }
+ if (attr_form == 0) {
+ _dwarf_error(dbg, error, DW_DLE_DIE_BAD);
+ return (DW_DLV_ERROR);
+ }
+ return DW_DLV_NO_ENTRY;
+}
+
+
+int
+dwarf_bytesize(Dwarf_Die die,
+ Dwarf_Unsigned * ret_size, Dwarf_Error * error)
+{
+ Dwarf_Unsigned luns = 0;
+ int res = _dwarf_die_attr_unsigned_constant(die, DW_AT_byte_size,
+ &luns, error);
+ *ret_size = luns;
+ return res;
+}
+
+
+int
+dwarf_bitsize(Dwarf_Die die,
+ Dwarf_Unsigned * ret_size, Dwarf_Error * error)
+{
+ Dwarf_Unsigned luns = 0;
+ int res = _dwarf_die_attr_unsigned_constant(die, DW_AT_bit_size,
+ &luns, error);
+ *ret_size = luns;
+ return res;
+}
+
+
+int
+dwarf_bitoffset(Dwarf_Die die,
+ Dwarf_Unsigned * ret_size, Dwarf_Error * error)
+{
+ Dwarf_Unsigned luns = 0;
+ int res = _dwarf_die_attr_unsigned_constant(die,
+ DW_AT_bit_offset, &luns, error);
+ *ret_size = luns;
+ return res;
+}
+
+
+/* Refer section 3.1, page 21 in Dwarf Definition. */
+int
+dwarf_srclang(Dwarf_Die die,
+ Dwarf_Unsigned * ret_size, Dwarf_Error * error)
+{
+ Dwarf_Unsigned luns = 0;
+ int res = _dwarf_die_attr_unsigned_constant(die, DW_AT_language,
+ &luns, error);
+ *ret_size = luns;
+ return res;
+}
+
+
+/* Refer section 5.4, page 37 in Dwarf Definition. */
+int
+dwarf_arrayorder(Dwarf_Die die,
+ Dwarf_Unsigned * ret_size, Dwarf_Error * error)
+{
+ Dwarf_Unsigned luns = 0;
+ int res = _dwarf_die_attr_unsigned_constant(die, DW_AT_ordering,
+ &luns, error);
+ *ret_size = luns;
+ return res;
+}
+
+/*
+ Return DW_DLV_OK if ok
+ DW_DLV_ERROR if failure.
+
+ If the die and the attr are not related the result is
+ meaningless.
+*/
+int
+dwarf_attr_offset(Dwarf_Die die, Dwarf_Attribute attr,
+ Dwarf_Off * offset /* return offset thru this ptr */,
+ Dwarf_Error * error)
+{
+ Dwarf_Off attroff = 0;
+
+ CHECK_DIE(die, DW_DLV_ERROR);
+
+ attroff = (attr->ar_debug_info_ptr -
+ die->di_cu_context->cc_dbg->de_debug_info.dss_data);
+ *offset = attroff;
+ return DW_DLV_OK;
+}
+
+int
+dwarf_die_abbrev_code(Dwarf_Die die)
+{
+ return die->di_abbrev_code;
+}
+
+/* Helper function for finding form class. */
+static enum Dwarf_Form_Class
+dw_get_special_offset(Dwarf_Half attrnum)
+{
+ switch(attrnum) {
+ case DW_AT_stmt_list:
+ return DW_FORM_CLASS_LINEPTR;
+ case DW_AT_macro_info:
+ return DW_FORM_CLASS_MACPTR;
+ case DW_AT_ranges:
+ return DW_FORM_CLASS_RANGELISTPTR;
+ case DW_AT_location:
+ case DW_AT_string_length:
+ case DW_AT_return_addr:
+ case DW_AT_data_member_location:
+ case DW_AT_frame_base:
+ case DW_AT_segment:
+ case DW_AT_static_link:
+ case DW_AT_use_location:
+ case DW_AT_vtable_elem_location:
+ return DW_FORM_CLASS_LOCLISTPTR;
+ case DW_AT_sibling:
+ case DW_AT_byte_size :
+ case DW_AT_bit_offset :
+ case DW_AT_bit_size :
+ case DW_AT_discr :
+ case DW_AT_import :
+ case DW_AT_common_reference:
+ case DW_AT_containing_type:
+ case DW_AT_default_value:
+ case DW_AT_lower_bound:
+ case DW_AT_bit_stride:
+ case DW_AT_upper_bound:
+ case DW_AT_abstract_origin:
+ case DW_AT_base_types:
+ case DW_AT_count:
+ case DW_AT_friend:
+ case DW_AT_namelist_item:
+ case DW_AT_priority:
+ case DW_AT_specification:
+ case DW_AT_type:
+ case DW_AT_allocated:
+ case DW_AT_associated:
+ case DW_AT_byte_stride:
+ case DW_AT_extension:
+ case DW_AT_trampoline:
+ case DW_AT_small:
+ case DW_AT_object_pointer:
+ case DW_AT_signature:
+ return DW_FORM_CLASS_REFERENCE;
+ case DW_AT_MIPS_fde: /* SGI/IRIX extension */
+ return DW_FORM_CLASS_FRAMEPTR;
+ }
+ return DW_FORM_CLASS_UNKNOWN;
+}
+
+/* It takes 4 pieces of data (including the FORM)
+ to accurately determine the form 'class' as documented
+ in the DWARF spec. This is per DWARF4, but will work
+ for DWARF2 or 3 as well. */
+enum Dwarf_Form_Class dwarf_get_form_class(
+ Dwarf_Half dwversion,
+ Dwarf_Half attrnum,
+ Dwarf_Half offset_size,
+ Dwarf_Half form)
+{
+ switch(form) {
+ case DW_FORM_addr: return DW_FORM_CLASS_ADDRESS;
+
+ case DW_FORM_data2: return DW_FORM_CLASS_CONSTANT;
+
+ case DW_FORM_data4:
+ if(dwversion <= 3 && offset_size == 4) {
+ enum Dwarf_Form_Class class = dw_get_special_offset(attrnum);
+ if(class != DW_FORM_CLASS_UNKNOWN) {
+ return class;
+ }
+ }
+ return DW_FORM_CLASS_CONSTANT;
+ case DW_FORM_data8:
+ if(dwversion <= 3 && offset_size == 8) {
+ enum Dwarf_Form_Class class = dw_get_special_offset(attrnum);
+ if(class != DW_FORM_CLASS_UNKNOWN) {
+ return class;
+ }
+ }
+ return DW_FORM_CLASS_CONSTANT;
+
+ case DW_FORM_sec_offset:
+ {
+ enum Dwarf_Form_Class class = dw_get_special_offset(attrnum);
+ if(class != DW_FORM_CLASS_UNKNOWN) {
+ return class;
+ }
+ }
+ /* We do not know what this is. */
+ break;
+
+ case DW_FORM_string: return DW_FORM_CLASS_STRING;
+ case DW_FORM_strp: return DW_FORM_CLASS_STRING;
+
+ case DW_FORM_block: return DW_FORM_CLASS_BLOCK;
+ case DW_FORM_block1: return DW_FORM_CLASS_BLOCK;
+ case DW_FORM_block2: return DW_FORM_CLASS_BLOCK;
+ case DW_FORM_block4: return DW_FORM_CLASS_BLOCK;
+
+ case DW_FORM_data1: return DW_FORM_CLASS_CONSTANT;
+ case DW_FORM_sdata: return DW_FORM_CLASS_CONSTANT;
+ case DW_FORM_udata: return DW_FORM_CLASS_CONSTANT;
+
+ case DW_FORM_ref_addr: return DW_FORM_CLASS_REFERENCE;
+ case DW_FORM_ref1: return DW_FORM_CLASS_REFERENCE;
+ case DW_FORM_ref2: return DW_FORM_CLASS_REFERENCE;
+ case DW_FORM_ref4: return DW_FORM_CLASS_REFERENCE;
+ case DW_FORM_ref8: return DW_FORM_CLASS_REFERENCE;
+ case DW_FORM_ref_udata: return DW_FORM_CLASS_REFERENCE;
+ case DW_FORM_ref_sig8: return DW_FORM_CLASS_REFERENCE;
+
+ case DW_FORM_exprloc: return DW_FORM_CLASS_EXPRLOC;
+
+ case DW_FORM_flag: return DW_FORM_CLASS_FLAG;
+ case DW_FORM_flag_present: return DW_FORM_CLASS_FLAG;
+
+
+ case DW_FORM_indirect:
+ default:
+ break;
+ };
+ return DW_FORM_CLASS_UNKNOWN;
+}
+
diff --git a/usr/src/lib/libdwarf/common/dwarf_ranges.c b/usr/src/lib/libdwarf/common/dwarf_ranges.c
new file mode 100644
index 0000000000..ae6d5cf9b5
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_ranges.c
@@ -0,0 +1,171 @@
+/*
+
+ Copyright (C) 2008-2010 David Anderson. 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
+
+*/
+/* The address of the Free Software Foundation is
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ SGI has moved from the Crittenden Lane address.
+*/
+
+
+
+#include "config.h"
+#include <stdlib.h>
+#include "dwarf_incl.h"
+
+struct ranges_entry {
+ struct ranges_entry *next;
+ Dwarf_Ranges cur;
+};
+
+
+#define MAX_ADDR ((address_size == 8)?0xffffffffffffffffULL:0xffffffff)
+int dwarf_get_ranges_a(Dwarf_Debug dbg,
+ Dwarf_Off rangesoffset,
+ Dwarf_Die die,
+ Dwarf_Ranges ** rangesbuf,
+ Dwarf_Signed * listlen,
+ Dwarf_Unsigned * bytecount,
+ Dwarf_Error * error)
+{
+ Dwarf_Small *rangeptr = 0;
+ Dwarf_Small *beginrangeptr = 0;
+ Dwarf_Small *section_end = 0;
+ unsigned entry_count = 0;
+ struct ranges_entry *base = 0;
+ struct ranges_entry *last = 0;
+ struct ranges_entry *curre = 0;
+ Dwarf_Ranges * ranges_data_out = 0;
+ unsigned copyindex = 0;
+ Dwarf_Half address_size = 0;
+ int res = DW_DLV_ERROR;
+
+ res = _dwarf_load_section(dbg, &dbg->de_debug_ranges,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ if(rangesoffset >= dbg->de_debug_ranges.dss_size) {
+ _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OFFSET_BAD);
+ return (DW_DLV_ERROR);
+
+ }
+ address_size = _dwarf_get_address_size(dbg, die);
+ section_end = dbg->de_debug_ranges.dss_data +
+ dbg->de_debug_ranges.dss_size;
+ rangeptr = dbg->de_debug_ranges.dss_data + rangesoffset;
+ beginrangeptr = rangeptr;
+
+ for(;;) {
+ struct ranges_entry * re = calloc(sizeof(struct ranges_entry),1);
+ if(!re) {
+ _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OUT_OF_MEM);
+ return (DW_DLV_ERROR);
+ }
+ if(rangeptr >= section_end) {
+ return (DW_DLV_NO_ENTRY);
+ }
+ if((rangeptr + (2*address_size)) > section_end) {
+ _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OFFSET_BAD);
+ return (DW_DLV_ERROR);
+ }
+ entry_count++;
+ READ_UNALIGNED(dbg,re->cur.dwr_addr1,
+ Dwarf_Addr, rangeptr,
+ address_size);
+ rangeptr += address_size;
+ READ_UNALIGNED(dbg,re->cur.dwr_addr2 ,
+ Dwarf_Addr, rangeptr,
+ address_size);
+ rangeptr += address_size;
+ if(!base) {
+ base = re;
+ last = re;
+ } else {
+ last->next = re;
+ last = re;
+ }
+ if(re->cur.dwr_addr1 == 0 && re->cur.dwr_addr2 == 0) {
+ re->cur.dwr_type = DW_RANGES_END;
+ break;
+ } else if ( re->cur.dwr_addr1 == MAX_ADDR) {
+ re->cur.dwr_type = DW_RANGES_ADDRESS_SELECTION;
+ } else {
+ re->cur.dwr_type = DW_RANGES_ENTRY;
+ }
+ }
+
+ ranges_data_out = (Dwarf_Ranges *)
+ _dwarf_get_alloc(dbg,DW_DLA_RANGES,entry_count);
+ if(!ranges_data_out) {
+ _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OUT_OF_MEM);
+ return (DW_DLV_ERROR);
+ }
+ curre = base;
+ *rangesbuf = ranges_data_out;
+ *listlen = entry_count;
+ for( copyindex = 0; curre && (copyindex < entry_count);
+ ++copyindex,++ranges_data_out) {
+
+ struct ranges_entry *r = curre;
+ *ranges_data_out = curre->cur;
+ curre = curre->next;
+ free(r);
+ }
+ /* Callers will often not care about the bytes used. */
+ if(bytecount) {
+ *bytecount = rangeptr - beginrangeptr;
+ }
+ return DW_DLV_OK;
+}
+int dwarf_get_ranges(Dwarf_Debug dbg,
+ Dwarf_Off rangesoffset,
+ Dwarf_Ranges ** rangesbuf,
+ Dwarf_Signed * listlen,
+ Dwarf_Unsigned * bytecount,
+ Dwarf_Error * error)
+{
+ Dwarf_Die die = 0;
+ int res = dwarf_get_ranges_a(dbg,rangesoffset,die,
+ rangesbuf,listlen,bytecount,error);
+ return res;
+}
+
+void
+dwarf_ranges_dealloc(Dwarf_Debug dbg, Dwarf_Ranges * rangesbuf,
+ Dwarf_Signed rangecount)
+{
+ dwarf_dealloc(dbg,rangesbuf, DW_DLA_RANGES);
+
+}
+
diff --git a/usr/src/lib/libdwarf/common/dwarf_sort_line.c b/usr/src/lib/libdwarf/common/dwarf_sort_line.c
new file mode 100644
index 0000000000..3576614129
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_sort_line.c
@@ -0,0 +1,733 @@
+/*
+ Copyright (C) 2000,2002,2004,2006 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2007-2010 David Anderson. 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
+
+*/
+/* The address of the Free Software Foundation is
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ SGI has moved from the Crittenden Lane address.
+*/
+
+
+/* This file was designed for SGI IRIX compiler use.
+ The static linker can rearrange the order of functions
+ in the layout in memory
+ and provided each has the right form
+ this will (when called by the SGI IRIX
+ static linker) rearrange the table so the line table
+ is arranged in the same order as the memory layout. */
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include "dwarf_line.h"
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#define MINIMUM_POSSIBLE_PROLOG_LEN 10 /* 10 is based on */
+ /* the definition of the DWARF2/3 line table prolog. The value
+ here should be >8 (accounting for a 64 bit read) and <= the
+ length of a legal DWARF2/3 line prolog, which is at least 10
+ bytes long (but can be longer). What this constant helps
+ avoid is reading past the end of a malloc'd buffer in
+ _dwarf_update_line_sec(). */
+
+static int
+ _dwarf_update_line_sec(Dwarf_Small * line_ptr,
+ unsigned long remaining_bytes,
+ int *any_change,
+ int length_size,
+ int *err_code, Dwarf_Small ** new_line_ptr);
+
+/* Used to construct
+ a linked list of so we can sort and reorder the line info.
+*/
+struct a_line_area {
+ Dwarf_Addr ala_address; /* from DW_LNE_set_address */
+ Dwarf_Unsigned ala_offset; /* byte offset in buffer */
+ Dwarf_Unsigned ala_length; /* byte length in buffer */
+ long ala_entry_num; /* to guarantee stable sort */
+ struct a_line_area *ala_next;
+};
+
+
+/*
+ Written to support the SGI IRIX static linker.
+ It helps SGI IRIX ld
+ rearrange lines in .debug_line in a .o created with a text
+ section per function. The SGI IRIX linker option is:
+ -OPT:procedure_reorder=ON
+ where ld-cord (cord(1)ing by ld,
+ not by cord(1)) may have changed the function order.
+
+ Returns
+ DW_DLV_OK if nothing went wrong.
+ DW_DLV_ERROR if could not do anything due to
+ error. the original buffer is unchanged.
+
+ is_64_bit must be passed in by caller and tells
+ if this is a 32 or 64bit pointer object section
+ being processed.
+
+ err_code must be a non-null pointer to integer.
+ If DW_DLV_ERROR is returned that integer is set
+ to a dwarf error code so the caller may
+ print it for diagnostic purposes.
+
+ *any_change is set here
+ set 0 if no sorting (movement) done.
+ set 1 if some sorting (movement) done.
+ on all returns. On error return sets to 0.
+
+ The _dwarf name form is now obsolete,
+ the dwarf_ name for is preferred.
+ Both names supported.
+
+*/
+int
+_dwarf_ld_sort_lines(void *orig_buffer,
+ unsigned long buffer_len,
+ int is_64_bit, int *any_change, int *err_code)
+{
+ return dwarf_ld_sort_lines(orig_buffer,buffer_len,
+ is_64_bit,any_change,err_code);
+}
+int
+dwarf_ld_sort_lines(void *orig_buffer,
+ unsigned long buffer_len,
+ int is_64_bit, int *any_change, int *err_code)
+{
+
+ int length_size = 4;
+ Dwarf_Small *orig_line_ptr; /* our local copy of the user's input
+ buffer */
+ Dwarf_Small *line_ptr; /* starts at orig_line_ptr, gets
+ incremented thru to end of our copy
+ of the input buffer */
+ Dwarf_Small *new_line_ptr; /* output of _dwarf_update_line_sec(),
+ used to update line_ptr as we pass
+ thru compilation units in a .o
+ .debug_line */
+
+ unsigned long remaining_bytes = buffer_len; /* total length of
+ original area left
+ to be processed.
+ Changes as we pass
+ thru compilation
+ units in a .o
+ .debug_line */
+
+ int sec_res;
+ int lany_change = 0;
+ int did_change = 0;
+
+ if (is_64_bit)
+ length_size = 8;
+
+ *any_change = 0;
+ line_ptr = malloc(buffer_len);
+ if (!line_ptr) {
+ *err_code = DW_DLE_ALLOC_FAIL;
+ return DW_DLV_ERROR;
+ }
+ orig_line_ptr = line_ptr;
+ memcpy(line_ptr, orig_buffer, buffer_len);
+
+
+ /*
+ We must iterate thru each of a set of prologues and line data.
+ We process each set in turn. If all pass, we update the
+ passed-in buffer. */
+ sec_res = DW_DLV_OK;
+
+ for (sec_res = _dwarf_update_line_sec(line_ptr,
+ remaining_bytes,
+ &lany_change,
+ length_size,
+ err_code,
+ &new_line_ptr);
+ (sec_res == DW_DLV_OK) && (remaining_bytes > 0);
+ sec_res = _dwarf_update_line_sec(line_ptr,
+ remaining_bytes,
+ &lany_change,
+ length_size,
+ err_code, &new_line_ptr)) {
+ long bytes_used = new_line_ptr - line_ptr;
+
+ line_ptr = new_line_ptr;
+ remaining_bytes -= bytes_used;
+ if (lany_change) {
+ did_change = 1;
+ }
+ if (remaining_bytes > 0) {
+ continue;
+ }
+ break;
+ }
+ if (sec_res == DW_DLV_ERROR) {
+ free(orig_line_ptr);
+ return sec_res;
+ }
+
+
+ /* all passed */
+ if (did_change) {
+ /* So update the passed in buffer orig_buffer is caller's input
+ area. orig_line_ptr is our modified copy of input area. */
+ memcpy(orig_buffer, orig_line_ptr, buffer_len);
+ *any_change = 1;
+ }
+ free(orig_line_ptr);
+
+ return sec_res;
+}
+
+
+/* By setting ala_entry_num we guarantee a stable sort,
+ no duplicates
+ Sorting in address order.
+*/
+static int
+cmpr(const void *lin, const void *rin)
+{
+ const struct a_line_area *l = lin;
+ const struct a_line_area *r = rin;
+
+ if (l->ala_address < r->ala_address) {
+ return -1;
+ }
+ if (l->ala_address > r->ala_address) {
+ return 1;
+ }
+ if (l->ala_entry_num < r->ala_entry_num) {
+ return -1;
+ }
+ if (l->ala_entry_num > r->ala_entry_num) {
+ return 1;
+ }
+ return 0; /* should never happen. */
+}
+
+/* The list of line area records is no longer needed.
+ Free the data allocated. */
+static void
+free_area_data(struct a_line_area *arp)
+{
+ while(arp) {
+ struct a_line_area *next = arp->ala_next;
+ free(arp);
+ arp = next;
+ }
+}
+
+/*
+ On entry:
+ line_ptr must point to first
+ byte of a line group for one (original) .o
+
+ remaining_bytes is the size of the area pointed to
+ by line_ptr: may be larger than the
+ current original compilation unit .
+
+ length size is 4 for 32bit pointers, 8 for 64bit pointers
+ in the data pointed to.
+
+
+ On return:
+ return DW_DLV_OK if all ok. (ignore
+ *err_code in this case)
+
+ return DW_DLV_ERROR and set *err_code if an error.
+
+ If some line data was moved around, set *any_change to 1.
+ If error or no movement, set *any_change to 0;
+
+ Set *new_line_ptr to one-byte-past the end of the
+ current original compilation unit (not necessary
+ if returning DW_DLV_ERROR, but not harmful).
+
+
+ This copies the entire array to a malloc area, then
+ mallocs pieces of it (another malloc) for sorting a CU entries
+ and copying back. Then at end the whole new thing copied in.
+ The result is that on error, the input is not touched.
+
+ An alternative would be to just update a piece at a time
+ and on error stop updating but leave what was done, done.
+ This alternative would save some temporary malloc space.
+
+
+*/
+static int
+_dwarf_update_line_sec(Dwarf_Small * line_ptr,
+ unsigned long remaining_bytes,
+ int *any_change,
+ int length_size,
+ int *err_code, Dwarf_Small ** new_line_ptr)
+{
+
+
+ /*
+ This points to the last byte of the .debug_line portion for the
+ current cu. */
+ Dwarf_Small *line_ptr_end = 0;
+
+ /*
+ This points to the end of the statement program prologue for the
+ current cu, and serves to check that the prologue was correctly
+ decoded. */
+
+ Dwarf_Small *orig_line_ptr = 0;
+
+ /* These are the fields of the statement program header. */
+ struct Dwarf_Debug_s dbg_data;
+ Dwarf_Debug dbg = &dbg_data;
+
+ /* These are the state machine state variables. */
+ Dwarf_Addr address = 0;
+ Dwarf_Word line = 1;
+ Dwarf_Bool is_stmt = false;
+
+ /* Dwarf_Bool prologue_end; Dwarf_Bool epilogue_begin; */
+ Dwarf_Small isa = 0;
+
+
+ struct a_line_area *area_base = 0;
+ struct a_line_area *area_current = 0;
+ long area_count = 0;
+
+ Dwarf_Addr last_address = 0;
+ int need_to_sort = 0;
+
+ /*
+ This is the current opcode read from the statement program. */
+ Dwarf_Small opcode = 0;
+
+
+ /*
+ These variables are used to decode leb128 numbers. Leb128_num
+ holds the decoded number, and leb128_length is its length in
+ bytes. */
+ Dwarf_Word leb128_num = 0;
+ Dwarf_Sword advance_line = 0;
+
+ /*
+ This is the operand of the latest fixed_advance_pc extended
+ opcode. */
+ Dwarf_Half fixed_advance_pc = 0;
+
+ /* This is the length of an extended opcode instr. */
+ Dwarf_Word instr_length = 0;
+ Dwarf_Small ext_opcode = 0;
+ struct Line_Table_Prefix_s prefix;
+
+
+
+ memset(dbg, 0, sizeof(struct Dwarf_Debug_s));
+ dbg->de_copy_word = memcpy;
+ /*
+ Following is a straightforward decoding of the statement program
+ prologue information. */
+ *any_change = 0;
+
+
+ orig_line_ptr = line_ptr;
+ if (remaining_bytes < MINIMUM_POSSIBLE_PROLOG_LEN) {
+ /* We are at the end. Remaining should be zero bytes, padding.
+ This is really just 'end of CU buffer' not an error. The is
+ no 'entry' left so report there is none. We don't want to
+ READ_UNALIGNED the total_length below and then belatedly
+ discover that we read off the end already. */
+ return (DW_DLV_NO_ENTRY);
+ }
+
+ dwarf_init_line_table_prefix(&prefix);
+ {
+ Dwarf_Small *line_ptr_out = 0;
+ Dwarf_Error error;
+ int dres = dwarf_read_line_table_prefix(dbg,
+ line_ptr,
+ remaining_bytes,
+ &line_ptr_out,
+ &prefix,
+ NULL, NULL,&error,
+ NULL);
+
+ if (dres == DW_DLV_ERROR) {
+ dwarf_free_line_table_prefix(&prefix);
+ *err_code = dwarf_errno(error);
+ dwarf_dealloc(dbg, error, DW_DLA_ERROR);
+ free_area_data(area_base);
+ return dres;
+ }
+ if (dres == DW_DLV_NO_ENTRY) {
+ dwarf_free_line_table_prefix(&prefix);
+ return dres;
+ }
+ line_ptr_end = prefix.pf_line_ptr_end;
+
+ line_ptr = line_ptr_out;
+ }
+
+
+ /* Initialize the state machine. */
+ /* file = 1; */
+ /* column = 0; */
+ is_stmt = prefix.pf_default_is_stmt;
+ /* basic_block = false; */
+ /* end_sequence = false; */
+ /* prologue_end = false; */
+ /* epilogue_begin = false; */
+ isa = 0;
+
+
+ /* Start of statement program. */
+ while (line_ptr < line_ptr_end) {
+ int type;
+
+ Dwarf_Small *stmt_prog_entry_start = line_ptr;
+
+ opcode = *(Dwarf_Small *) line_ptr;
+ line_ptr++;
+ /* 'type' is the output */
+ WHAT_IS_OPCODE(type, opcode, prefix.pf_opcode_base,
+ prefix.pf_opcode_length_table, line_ptr,
+ prefix.pf_std_op_count);
+
+ if (type == LOP_DISCARD) {
+ int oc;
+ int opcnt = prefix.pf_opcode_length_table[opcode];
+
+ for (oc = 0; oc < opcnt; oc++) {
+ /*
+ ** Read and discard operands we don't
+ ** understand.
+ ** arbitrary choice of unsigned read.
+ ** signed read would work as well.
+ */
+ Dwarf_Unsigned utmp2;
+
+ DECODE_LEB128_UWORD(line_ptr, utmp2);
+ }
+
+ } else if (type == LOP_SPECIAL) {
+ opcode = opcode - prefix.pf_opcode_base;
+ address = address + prefix.pf_minimum_instruction_length *
+ (opcode / prefix.pf_line_range);
+ line =
+ line + prefix.pf_line_base +
+ opcode % prefix.pf_line_range;
+
+ /* basic_block = false; */
+
+
+ } else if (type == LOP_STANDARD) {
+
+
+ switch (opcode) {
+
+
+ case DW_LNS_copy:{
+
+ /* basic_block = false; */
+ break;
+ }
+
+ case DW_LNS_advance_pc:{
+ Dwarf_Unsigned utmp2;
+
+
+ DECODE_LEB128_UWORD(line_ptr, utmp2);
+ leb128_num = (Dwarf_Word) utmp2;
+ address =
+ address +
+ prefix.pf_minimum_instruction_length *
+ leb128_num;
+ break;
+ }
+
+ case DW_LNS_advance_line:{
+ Dwarf_Signed stmp;
+
+
+ DECODE_LEB128_SWORD(line_ptr, stmp);
+ advance_line = (Dwarf_Sword) stmp;
+ line = line + advance_line;
+ break;
+ }
+
+ case DW_LNS_set_file:{
+ Dwarf_Unsigned utmp2;
+
+
+ DECODE_LEB128_UWORD(line_ptr, utmp2);
+ /* file = (Dwarf_Word)utmp2; */
+ break;
+ }
+
+ case DW_LNS_set_column:{
+ Dwarf_Unsigned utmp2;
+
+
+ DECODE_LEB128_UWORD(line_ptr, utmp2);
+ /* column = (Dwarf_Word)utmp2; */
+ break;
+ }
+
+ case DW_LNS_negate_stmt:{
+
+ is_stmt = !is_stmt;
+ break;
+ }
+
+ case DW_LNS_set_basic_block:{
+
+ /* basic_block = true; */
+ break;
+ }
+
+ case DW_LNS_const_add_pc:{
+ opcode = MAX_LINE_OP_CODE - prefix.pf_opcode_base;
+ address =
+ address +
+ prefix.pf_minimum_instruction_length * (opcode /
+ prefix.
+ pf_line_range);
+
+ break;
+ }
+
+ case DW_LNS_fixed_advance_pc:{
+
+ READ_UNALIGNED(dbg, fixed_advance_pc, Dwarf_Half,
+ line_ptr, sizeof(Dwarf_Half));
+ line_ptr += sizeof(Dwarf_Half);
+ address = address + fixed_advance_pc;
+ break;
+ }
+ /* New in DWARF3 */
+ case DW_LNS_set_prologue_end:{
+
+ /* prologue_end = true; */
+ break;
+
+
+ }
+ /* New in DWARF3 */
+ case DW_LNS_set_epilogue_begin:{
+ /* epilogue_begin = true; */
+ break;
+ }
+
+ /* New in DWARF3 */
+ case DW_LNS_set_isa:{
+ Dwarf_Unsigned utmp2;
+
+ DECODE_LEB128_UWORD(line_ptr, utmp2);
+ isa = utmp2;
+ if (isa != utmp2) {
+ /* The value of the isa did not fit in our
+ local so we record it wrong. declare an
+ error. */
+ dwarf_free_line_table_prefix(&prefix);
+ *err_code = DW_DLE_LINE_NUM_OPERANDS_BAD;
+ free_area_data(area_base);
+ return (DW_DLV_ERROR);
+ }
+ break;
+ }
+
+ }
+ } else if (type == LOP_EXTENDED) {
+
+ Dwarf_Unsigned utmp3;
+
+ DECODE_LEB128_UWORD(line_ptr, utmp3);
+ instr_length = (Dwarf_Word) utmp3;
+ ext_opcode = *(Dwarf_Small *) line_ptr;
+ line_ptr++;
+ switch (ext_opcode) {
+
+ case DW_LNE_end_sequence:{
+ /* end_sequence = true; */
+
+ address = 0;
+ /* file = 1; */
+ line = 1;
+ /* column = 0; */
+ is_stmt = prefix.pf_default_is_stmt;
+ /* basic_block = false; */
+ /* end_sequence = false; */
+ /* prologue_end = false; */
+ /* epilogue_begin = false; */
+ break;
+ }
+
+ case DW_LNE_set_address:{
+ {
+ struct a_line_area *area;
+
+ READ_UNALIGNED(dbg, address, Dwarf_Addr,
+ line_ptr, length_size);
+ /* Here we need to remember the offset into the
+ buffer and check to see if address went
+ down. */
+ if (address < last_address) {
+ need_to_sort = 1;
+ }
+ last_address = address;
+
+ area = malloc(sizeof(struct a_line_area));
+ area->ala_address = address;
+ area->ala_offset = stmt_prog_entry_start -
+ orig_line_ptr;
+ area->ala_entry_num = area_count;
+ area->ala_next = 0;
+ area->ala_length = 0;
+ if (area_current) {
+ area_current->ala_next = area;
+ area_current->ala_length =
+ area->ala_offset -
+ area_current->ala_offset;
+ }
+ ++area_count;
+ area_current = area;
+ if (area_base == 0) {
+ area_base = area;
+ }
+
+ line_ptr += length_size;
+ }
+ break;
+ }
+
+ case DW_LNE_define_file:{
+ break;
+ }
+
+ default:{
+ Dwarf_Unsigned remaining_bytes = instr_length -1;
+ line_ptr += remaining_bytes;
+ break;
+ }
+ }
+
+ }
+ }
+
+
+ *new_line_ptr = line_ptr;
+ if (!need_to_sort) {
+ dwarf_free_line_table_prefix(&prefix);
+ free_area_data(area_base);
+ return (DW_DLV_OK);
+ }
+
+ /* So now we have something to sort. First, finish off the last
+ area record: */
+ area_current->ala_length = (line_ptr - orig_line_ptr)
+ -area_current->ala_offset;
+
+ /* Build and sort a simple array of sections. Forcing a stable sort
+ by comparing on sequence number. We will use the sorted list to
+ move sections of this part of the line table. Each 'section'
+ starting with a DW_LNE_set_address opcode, on the assumption
+ that such only get out of order where there was an ld-cord
+ function rearrangement and that it is meaningful to restart the
+ line info there. */
+ {
+ struct a_line_area *ala_array;
+ struct a_line_area *local;
+ long start_len;
+ Dwarf_Small *new_area;
+ long i;
+
+ ala_array = malloc(area_count * sizeof(struct a_line_area));
+ if (!ala_array) {
+ dwarf_free_line_table_prefix(&prefix);
+ *err_code = DW_DLE_ALLOC_FAIL;
+ free_area_data(area_base);
+ return DW_DLV_ERROR;
+ }
+
+ for (local = area_base, i = 0; local;
+ local = local->ala_next, ++i) {
+
+ ala_array[i] = *local;
+ }
+ free_area_data(area_base);
+ /* Zero the stale pointers so we don't use them accidentally. */
+ area_base = 0;
+ area_current = 0;
+
+ qsort(ala_array, area_count, sizeof(struct a_line_area), cmpr);
+
+ /* Now we must rearrange the pieces of the line table. */
+
+ start_len =
+ (prefix.pf_line_prologue_start +
+ prefix.pf_prologue_length) - orig_line_ptr;
+ new_area = malloc(remaining_bytes);
+ if (!new_area) {
+ free(ala_array);
+ *err_code = DW_DLE_ALLOC_FAIL;
+ dwarf_free_line_table_prefix(&prefix);
+ return DW_DLV_ERROR;
+ }
+ memcpy(new_area, orig_line_ptr, start_len);
+ line_ptr = new_area + start_len;
+ for (i = 0; i < area_count; ++i) {
+ memcpy(line_ptr, orig_line_ptr +
+ ala_array[i].ala_offset, ala_array[i].ala_length);
+ line_ptr += ala_array[i].ala_length;
+ }
+
+ memcpy(orig_line_ptr, new_area, remaining_bytes);
+
+ free(new_area);
+ free(ala_array);
+ ala_array = 0;
+ new_area = 0;
+ }
+
+ *any_change = 1;
+ dwarf_free_line_table_prefix(&prefix);
+ return (DW_DLV_OK);
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_string.c b/usr/src/lib/libdwarf/common/dwarf_string.c
new file mode 100644
index 0000000000..fafa5a097c
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_string.c
@@ -0,0 +1,79 @@
+/*
+
+ Copyright (C) 2000-2004 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2009-2010 David Anderson. 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
+
+*/
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+
+int
+dwarf_get_str(Dwarf_Debug dbg,
+ Dwarf_Off offset,
+ char **string,
+ Dwarf_Signed * returned_str_len, Dwarf_Error * error)
+{
+ int res = DW_DLV_ERROR;
+
+ if (dbg == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ if (offset == dbg->de_debug_str.dss_size) {
+ /* Normal (if we've iterated thru the set of strings using
+ dwarf_get_str and are at the end). */
+ return DW_DLV_NO_ENTRY;
+ }
+ if (offset > dbg->de_debug_str.dss_size) {
+ _dwarf_error(dbg, error, DW_DLE_DEBUG_STR_OFFSET_BAD);
+ return (DW_DLV_ERROR);
+ }
+
+ if (string == NULL) {
+ _dwarf_error(dbg, error, DW_DLE_STRING_PTR_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ res = _dwarf_load_section(dbg, &dbg->de_debug_str,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ *string = (char *) dbg->de_debug_str.dss_data + offset;
+
+ *returned_str_len = (strlen(*string));
+ return DW_DLV_OK;
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_stubs.c b/usr/src/lib/libdwarf/common/dwarf_stubs.c
new file mode 100644
index 0000000000..f2c1f7fd45
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_stubs.c
@@ -0,0 +1,50 @@
+/*
+
+ Copyright (C) 2000,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
+
+*/
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+
+
+
+ /*ARGSUSED*/ int
+dwarf_nextglob(Dwarf_Debug dbg,
+ Dwarf_Global glob,
+ Dwarf_Global * returned_nextglob, Dwarf_Error * error)
+{
+ return (DW_DLV_NO_ENTRY);
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_types.c b/usr/src/lib/libdwarf/common/dwarf_types.c
new file mode 100644
index 0000000000..d547805289
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_types.c
@@ -0,0 +1,129 @@
+/*
+ Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2009-2010 David Anderson. 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
+
+*/
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+#include "dwarf_types.h"
+#include "dwarf_global.h"
+
+int
+dwarf_get_types(Dwarf_Debug dbg,
+ Dwarf_Type ** types,
+ Dwarf_Signed * ret_type_count, Dwarf_Error * error)
+{
+ int res = _dwarf_load_section(dbg, &dbg->de_debug_typenames,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ return _dwarf_internal_get_pubnames_like_data(dbg,
+ dbg->de_debug_typenames.dss_data,
+ dbg->de_debug_typenames.dss_size,
+ (Dwarf_Global **) types, /* type punning, Dwarf_Type is
+ never a completed type */
+ ret_type_count,
+ error,
+ DW_DLA_TYPENAME_CONTEXT,
+ DW_DLA_TYPENAME,
+ DW_DLE_DEBUG_TYPENAMES_LENGTH_BAD,
+ DW_DLE_DEBUG_TYPENAMES_VERSION_ERROR);
+}
+
+/* Deallocating fully requires deallocating the list
+ and all entries. But some internal data is
+ not exposed, so we need a function with internal knowledge.
+*/
+
+void
+dwarf_types_dealloc(Dwarf_Debug dbg, Dwarf_Type * dwgl,
+ Dwarf_Signed count)
+{
+ _dwarf_internal_globals_dealloc(dbg, (Dwarf_Global *) dwgl,
+ count,
+ DW_DLA_TYPENAME_CONTEXT,
+ DW_DLA_TYPENAME, DW_DLA_LIST);
+ return;
+}
+
+
+int
+dwarf_typename(Dwarf_Type type_in, char **ret_name, Dwarf_Error * error)
+{
+ Dwarf_Global type = (Dwarf_Global) type_in;
+
+ if (type == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_TYPE_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ *ret_name = (char *) (type->gl_name);
+ return DW_DLV_OK;
+}
+
+
+int
+dwarf_type_die_offset(Dwarf_Type type_in,
+ Dwarf_Off * ret_offset, Dwarf_Error * error)
+{
+ Dwarf_Global type = (Dwarf_Global) type_in;
+
+ return dwarf_global_die_offset(type, ret_offset, error);
+}
+
+
+int
+dwarf_type_cu_offset(Dwarf_Type type_in,
+ Dwarf_Off * ret_offset, Dwarf_Error * error)
+{
+ Dwarf_Global type = (Dwarf_Global) type_in;
+
+ return dwarf_global_cu_offset(type, ret_offset, error);
+}
+
+
+int
+dwarf_type_name_offsets(Dwarf_Type type_in,
+ char **returned_name,
+ Dwarf_Off * die_offset,
+ Dwarf_Off * cu_die_offset, Dwarf_Error * error)
+{
+ Dwarf_Global type = (Dwarf_Global) type_in;
+ return dwarf_global_name_offsets(type,
+ returned_name,
+ die_offset, cu_die_offset, error);
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_types.h b/usr/src/lib/libdwarf/common/dwarf_types.h
new file mode 100644
index 0000000000..ebd31c6c79
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_types.h
@@ -0,0 +1,41 @@
+/*
+
+ Copyright (C) 2000,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
+
+*/
+
+
+
+
+typedef struct Dwarf_Type_Context_s *Dwarf_Type_Context;
+
+/* type never completed see dwarf_global.h */
diff --git a/usr/src/lib/libdwarf/common/dwarf_util.c b/usr/src/lib/libdwarf/common/dwarf_util.c
new file mode 100644
index 0000000000..01e0dd755d
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_util.c
@@ -0,0 +1,547 @@
+/*
+ Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2007-2010 David Anderson. 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
+
+*/
+/* The address of the Free Software Foundation is
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ SGI has moved from the Crittenden Lane address.
+*/
+
+
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+#include "dwarf_die_deliv.h"
+
+
+
+/*
+ Given a form, and a pointer to the bytes encoding
+ a value of that form, val_ptr, this function returns
+ the length, in bytes, of a value of that form.
+ When using this function, check for a return of 0
+ a recursive DW_FORM_INDIRECT value.
+*/
+Dwarf_Unsigned
+_dwarf_get_size_of_val(Dwarf_Debug dbg,
+ Dwarf_Unsigned form,
+ Dwarf_Half address_size,
+ Dwarf_Small * val_ptr, int v_length_size)
+{
+ Dwarf_Unsigned length = 0;
+ Dwarf_Word leb128_length = 0;
+ Dwarf_Unsigned form_indirect = 0;
+ Dwarf_Unsigned ret_value = 0;
+
+ switch (form) {
+
+ default: /* Handles form = 0. */
+ return (form);
+
+ case DW_FORM_addr:
+ if(address_size) {
+ return address_size;
+ }
+ /* This should never happen, address_size should be set. */
+ return (dbg->de_pointer_size);
+
+ /* DWARF2 was wrong on the size of the attribute for
+ DW_FORM_ref_addr. We assume compilers are using the
+ corrected DWARF3 text (for 32bit pointer target objects pointer and
+ offsets are the same size anyway). */
+ case DW_FORM_ref_addr:
+ return (v_length_size);
+
+ case DW_FORM_block1:
+ return (*(Dwarf_Small *) val_ptr + 1);
+
+ case DW_FORM_block2:
+ READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
+ val_ptr, sizeof(Dwarf_Half));
+ return (ret_value + sizeof(Dwarf_Half));
+
+ case DW_FORM_block4:
+ READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned,
+ val_ptr, sizeof(Dwarf_ufixed));
+ return (ret_value + sizeof(Dwarf_ufixed));
+
+
+ case DW_FORM_data1:
+ return (1);
+
+ case DW_FORM_data2:
+ return (2);
+
+ case DW_FORM_data4:
+ return (4);
+
+ case DW_FORM_data8:
+ return (8);
+
+ case DW_FORM_string:
+ return (strlen((char *) val_ptr) + 1);
+
+ case DW_FORM_block:
+ case DW_FORM_exprloc:
+ length = _dwarf_decode_u_leb128(val_ptr, &leb128_length);
+ return (length + leb128_length);
+
+ case DW_FORM_flag_present:
+ return (0);
+ case DW_FORM_flag:
+ return (1);
+
+ case DW_FORM_sec_offset:
+ /* If 32bit dwarf, is 4. Else is 64bit dwarf and is 8. */
+ return (v_length_size);
+
+ case DW_FORM_ref_udata:
+ length = _dwarf_decode_u_leb128(val_ptr, &leb128_length);
+ return (leb128_length);
+
+ case DW_FORM_indirect:
+ {
+ Dwarf_Word indir_len = 0;
+
+ form_indirect = _dwarf_decode_u_leb128(val_ptr, &indir_len);
+ if (form_indirect == DW_FORM_indirect) {
+ return (0); /* We are in big trouble: The true form
+ of DW_FORM_indirect is
+ DW_FORM_indirect? Nonsense. Should
+ never happen. */
+ }
+ return (indir_len + _dwarf_get_size_of_val(dbg,
+ form_indirect,
+ address_size,
+ val_ptr + indir_len,
+ v_length_size));
+ }
+
+ case DW_FORM_ref1:
+ return (1);
+
+ case DW_FORM_ref2:
+ return (2);
+
+ case DW_FORM_ref4:
+ return (4);
+
+ case DW_FORM_ref8:
+ return (8);
+
+ case DW_FORM_sdata:
+ _dwarf_decode_s_leb128(val_ptr, &leb128_length);
+ return (leb128_length);
+
+ case DW_FORM_strp:
+ return (v_length_size);
+
+ case DW_FORM_udata:
+ _dwarf_decode_u_leb128(val_ptr, &leb128_length);
+ return (leb128_length);
+ }
+}
+
+/* We allow an arbitrary number of HT_MULTIPLE entries
+ before resizing. It seems up to 20 or 30
+ would work nearly as well.
+ We could have a different resize multiple than 'resize now'
+ test multiple, but for now we don't do that.
+*/
+#define HT_MULTIPLE 8
+
+/* Copy the old entries, updating each to be in
+ a new list. Don't delete anything. Leave the
+ htin with stale data. */
+static void
+copy_abbrev_table_to_new_table(Dwarf_Hash_Table htin,
+ Dwarf_Hash_Table htout)
+{
+ Dwarf_Hash_Table_Entry entry_in = htin->tb_entries;
+ unsigned entry_in_count = htin->tb_table_entry_count;
+ Dwarf_Hash_Table_Entry entry_out = htout->tb_entries;
+ unsigned entry_out_count = htout->tb_table_entry_count;
+ unsigned k = 0;
+ for ( ; k < entry_in_count; ++k,++entry_in) {
+ Dwarf_Abbrev_List listent = entry_in->at_head;
+ Dwarf_Abbrev_List nextlistent = 0;
+
+ for ( ; listent ; listent = nextlistent) {
+ unsigned newtmp = listent->ab_code;
+ unsigned newhash = newtmp%entry_out_count;
+ Dwarf_Hash_Table_Entry e;
+ nextlistent = listent->ab_next;
+ e = entry_out+newhash;
+ /* Move_entry_to_new_hash. This reverses the
+ order of the entries, effectively, but
+ that does not seem significant. */
+ listent->ab_next = e->at_head;
+ e->at_head = listent;
+
+ htout->tb_total_abbrev_count++;
+ }
+ }
+}
+
+/*
+ This function returns a pointer to a Dwarf_Abbrev_List_s
+ struct for the abbrev with the given code. It puts the
+ struct on the appropriate hash table. It also adds all
+ the abbrev between the last abbrev added and this one to
+ the hash table. In other words, the .debug_abbrev section
+ is scanned sequentially from the top for an abbrev with
+ the given code. All intervening abbrevs are also put
+ into the hash table.
+
+ This function hashes the given code, and checks the chain
+ at that hash table entry to see if a Dwarf_Abbrev_List_s
+ with the given code exists. If yes, it returns a pointer
+ to that struct. Otherwise, it scans the .debug_abbrev
+ section from the last byte scanned for that CU till either
+ an abbrev with the given code is found, or an abbrev code
+ of 0 is read. It puts Dwarf_Abbrev_List_s entries for all
+ abbrev's read till that point into the hash table. The
+ hash table contains both a head pointer and a tail pointer
+ for each entry.
+
+ While the lists can move and entries can be moved between
+ lists on reallocation, any given Dwarf_Abbrev_list entry
+ never moves once allocated, so the pointer is safe to return.
+
+ Returns NULL on error.
+*/
+Dwarf_Abbrev_List
+_dwarf_get_abbrev_for_code(Dwarf_CU_Context cu_context, Dwarf_Unsigned code)
+{
+ Dwarf_Debug dbg = cu_context->cc_dbg;
+ Dwarf_Hash_Table hash_table_base = cu_context->cc_abbrev_hash_table;
+ Dwarf_Hash_Table_Entry entry_base = 0;
+ Dwarf_Hash_Table_Entry entry_cur = 0;
+ Dwarf_Word hash_num = 0;
+ Dwarf_Unsigned abbrev_code = 0;
+ Dwarf_Unsigned abbrev_tag = 0;
+ Dwarf_Unsigned attr_name = 0;
+ Dwarf_Unsigned attr_form = 0;
+
+ Dwarf_Abbrev_List hash_abbrev_entry = 0;
+
+ Dwarf_Abbrev_List inner_list_entry = 0;
+ Dwarf_Hash_Table_Entry inner_hash_entry = 0;
+
+ Dwarf_Byte_Ptr abbrev_ptr = 0;
+ unsigned hashable_val;
+
+ if ( !hash_table_base->tb_entries ) {
+ hash_table_base->tb_table_entry_count = HT_MULTIPLE;
+ hash_table_base->tb_total_abbrev_count= 0;
+ hash_table_base->tb_entries = _dwarf_get_alloc(dbg,
+ DW_DLA_HASH_TABLE_ENTRY,
+ hash_table_base->tb_table_entry_count);
+ if(! hash_table_base->tb_entries) {
+ return NULL;
+ }
+
+ } else if (hash_table_base->tb_total_abbrev_count >
+ ( hash_table_base->tb_table_entry_count * HT_MULTIPLE) ) {
+ struct Dwarf_Hash_Table_s newht;
+ /* Effectively multiplies by >= HT_MULTIPLE */
+ newht.tb_table_entry_count = hash_table_base->tb_total_abbrev_count;
+ newht.tb_total_abbrev_count = 0;
+ newht.tb_entries = _dwarf_get_alloc(dbg,
+ DW_DLA_HASH_TABLE_ENTRY,
+ newht.tb_table_entry_count);
+
+ if(! newht.tb_entries) {
+ return NULL;
+ }
+ /* Copy the existing entries to the new table,
+ rehashing each.
+ */
+ copy_abbrev_table_to_new_table(hash_table_base, &newht);
+ /* Dealloc only the entries hash table array, not the lists
+ of things pointed to by a hash table entry array. */
+ dwarf_dealloc(dbg, hash_table_base->tb_entries,DW_DLA_HASH_TABLE_ENTRY);
+ hash_table_base->tb_entries = 0;
+ /* Now overwrite the existing table descriptor with
+ the new, newly valid, contents. */
+ *hash_table_base = newht;
+ } /* Else is ok as is, add entry */
+
+
+ hashable_val = code;
+ hash_num = hashable_val %
+ hash_table_base->tb_table_entry_count;
+ entry_base = hash_table_base->tb_entries;
+ entry_cur = entry_base + hash_num;
+
+ /* Determine if the 'code' is the list of synonyms already. */
+ for (hash_abbrev_entry = entry_cur->at_head;
+ hash_abbrev_entry != NULL && hash_abbrev_entry->ab_code != code;
+ hash_abbrev_entry = hash_abbrev_entry->ab_next);
+ if (hash_abbrev_entry != NULL) {
+ /* This returns a pointer to an abbrev list entry, not
+ the list itself. */
+ return (hash_abbrev_entry);
+ }
+
+ abbrev_ptr = cu_context->cc_last_abbrev_ptr != NULL ?
+ cu_context->cc_last_abbrev_ptr :
+ dbg->de_debug_abbrev.dss_data + cu_context->cc_abbrev_offset;
+
+ /* End of abbrev's for this cu, since abbrev code is 0. */
+ if (*abbrev_ptr == 0) {
+ return (NULL);
+ }
+
+ do {
+ unsigned new_hashable_val;
+ DECODE_LEB128_UWORD(abbrev_ptr, abbrev_code);
+ DECODE_LEB128_UWORD(abbrev_ptr, abbrev_tag);
+
+ inner_list_entry = (Dwarf_Abbrev_List)
+ _dwarf_get_alloc(cu_context->cc_dbg, DW_DLA_ABBREV_LIST, 1);
+ if (inner_list_entry == NULL)
+ return (NULL);
+
+ new_hashable_val = abbrev_code;
+ hash_num = new_hashable_val %
+ hash_table_base->tb_table_entry_count;
+ inner_hash_entry = entry_base + hash_num;
+ /* Move_entry_to_new_hash */
+ inner_list_entry->ab_next = inner_hash_entry->at_head;
+ inner_hash_entry->at_head = inner_list_entry;
+
+ hash_table_base->tb_total_abbrev_count++;
+
+ inner_list_entry->ab_code = abbrev_code;
+ inner_list_entry->ab_tag = abbrev_tag;
+ inner_list_entry->ab_has_child = *(abbrev_ptr++);
+ inner_list_entry->ab_abbrev_ptr = abbrev_ptr;
+
+ /* Cycle thru the abbrev content, ignoring the content except
+ to find the end of the content. */
+ do {
+ DECODE_LEB128_UWORD(abbrev_ptr, attr_name);
+ DECODE_LEB128_UWORD(abbrev_ptr, attr_form);
+ } while (attr_name != 0 && attr_form != 0);
+
+ } while (*abbrev_ptr != 0 && abbrev_code != code);
+
+ cu_context->cc_last_abbrev_ptr = abbrev_ptr;
+ return (abbrev_code == code ? inner_list_entry : NULL);
+}
+
+
+/* return 1 if string ends before 'endptr' else
+** return 0 meaning string is not properly terminated.
+** Presumption is the 'endptr' pts to end of some dwarf section data.
+*/
+int
+_dwarf_string_valid(void *startptr, void *endptr)
+{
+
+ char *start = startptr;
+ char *end = endptr;
+
+ while (start < end) {
+ if (*start == 0) {
+ return 1; /* OK! */
+ }
+ ++start;
+ ++end;
+ }
+ return 0; /* FAIL! bad string! */
+}
+
+/*
+ A byte-swapping version of memcpy
+ for cross-endian use.
+ Only 2,4,8 should be lengths passed in.
+*/
+void *
+_dwarf_memcpy_swap_bytes(void *s1, const void *s2, size_t len)
+{
+ void *orig_s1 = s1;
+ unsigned char *targ = (unsigned char *) s1;
+ unsigned char *src = (unsigned char *) s2;
+
+ if (len == 4) {
+ targ[3] = src[0];
+ targ[2] = src[1];
+ targ[1] = src[2];
+ targ[0] = src[3];
+ } else if (len == 8) {
+ targ[7] = src[0];
+ targ[6] = src[1];
+ targ[5] = src[2];
+ targ[4] = src[3];
+ targ[3] = src[4];
+ targ[2] = src[5];
+ targ[1] = src[6];
+ targ[0] = src[7];
+ } else if (len == 2) {
+ targ[1] = src[0];
+ targ[0] = src[1];
+ }
+/* should NOT get below here: is not the intended use */
+ else if (len == 1) {
+ targ[0] = src[0];
+ } else {
+ memcpy(s1, s2, len);
+ }
+
+ return orig_s1;
+}
+
+
+/*
+ This calculation used to be sprinkled all over.
+ Now brought to one place.
+
+ We try to accurately compute the size of a cu header
+ given a known cu header location ( an offset in .debug_info).
+
+*/
+/* ARGSUSED */
+Dwarf_Unsigned
+_dwarf_length_of_cu_header(Dwarf_Debug dbg, Dwarf_Unsigned offset)
+{
+ int local_length_size = 0;
+ int local_extension_size = 0;
+ Dwarf_Unsigned length = 0;
+ Dwarf_Small *cuptr = dbg->de_debug_info.dss_data + offset;
+
+ READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned,
+ cuptr, local_length_size, local_extension_size);
+
+ return local_extension_size + /* initial extesion, if present
+ */
+ local_length_size + /* Size of cu length field. */
+ sizeof(Dwarf_Half) + /* Size of version stamp field. */
+ local_length_size + /* Size of abbrev offset field. */
+ sizeof(Dwarf_Small); /* Size of address size field. */
+
+}
+
+/*
+ Pretend we know nothing about the CU
+ and just roughly compute the result.
+*/
+Dwarf_Unsigned
+_dwarf_length_of_cu_header_simple(Dwarf_Debug dbg)
+{
+ return dbg->de_length_size + /* Size of cu length field. */
+ sizeof(Dwarf_Half) + /* Size of version stamp field. */
+ dbg->de_length_size + /* Size of abbrev offset field. */
+ sizeof(Dwarf_Small); /* Size of address size field. */
+}
+
+/* Now that we delay loading .debug_info, we need to do the
+ load in more places. So putting the load
+ code in one place now instead of replicating it in multiple
+ places.
+
+*/
+int
+_dwarf_load_debug_info(Dwarf_Debug dbg, Dwarf_Error * error)
+{
+ int res = DW_DLV_ERROR;
+
+ /* Testing de_debug_info.dss_data allows us to avoid testing
+ de_debug_abbrev.dss_data.
+ One test instead of 2. .debug_info is useless
+ without .debug_abbrev. */
+ if (dbg->de_debug_info.dss_data) {
+ return DW_DLV_OK;
+ }
+
+ res = _dwarf_load_section(dbg, &dbg->de_debug_abbrev,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ res = _dwarf_load_section(dbg, &dbg->de_debug_info, error);
+ return res;
+
+}
+void
+_dwarf_free_abbrev_hash_table_contents(Dwarf_Debug dbg,Dwarf_Hash_Table hash_table)
+{
+ /* A Hash Table is an array with tb_table_entry_count struct
+ Dwarf_Hash_Table_s entries in the array. */
+ int hashnum = 0;
+ for (; hashnum < hash_table->tb_table_entry_count; ++hashnum) {
+ struct Dwarf_Abbrev_List_s *abbrev = 0;
+ struct Dwarf_Abbrev_List_s *nextabbrev = 0;
+ struct Dwarf_Hash_Table_Entry_s *tb = &hash_table->tb_entries[hashnum];
+
+ abbrev = tb->at_head;
+ for (; abbrev; abbrev = nextabbrev) {
+ nextabbrev = abbrev->ab_next;
+ dwarf_dealloc(dbg, abbrev, DW_DLA_ABBREV_LIST);
+ }
+ }
+ /* Frees all the entries at once: an array. */
+ dwarf_dealloc(dbg,hash_table->tb_entries,DW_DLA_HASH_TABLE_ENTRY);
+}
+
+/*
+ If no die provided the size value returned might be wrong.
+ If different compilation units have different address sizes
+ this may not give the correct value in all contexts if the die
+ pointer is NULL.
+ If the Elf offset size != address_size
+ (for example if address_size = 4 but recorded in elf64 object)
+ this may not give the correct value in all contexts if the die
+ pointer is NULL.
+ If the die pointer is non-NULL (in which case it must point to
+ a valid DIE) this will return the correct size.
+*/
+int
+_dwarf_get_address_size(Dwarf_Debug dbg, Dwarf_Die die)
+{
+ Dwarf_CU_Context context = 0;
+ Dwarf_Half addrsize = 0;
+ if(!die) {
+ return dbg->de_pointer_size;
+ }
+ context = die->di_cu_context;
+ addrsize = context->cc_address_size;
+ return addrsize;
+}
+
+
+
diff --git a/usr/src/lib/libdwarf/common/dwarf_util.h b/usr/src/lib/libdwarf/common/dwarf_util.h
new file mode 100644
index 0000000000..4046bb2478
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_util.h
@@ -0,0 +1,311 @@
+#ifndef DWARF_UTIL_H
+#define DWARF_UTIL_H
+/*
+
+ Copyright (C) 2000,2003,2004 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2007-2010 David Anderson. 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
+
+*/
+/* The address of the Free Software Foundation is
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ SGI has moved from the Crittenden Lane address.
+*/
+
+
+
+
+/*
+ Decodes unsigned leb128 encoded numbers.
+ Make sure ptr is a pointer to a 1-byte type.
+ In 2003 and earlier this was a hand-inlined
+ version of _dwarf_decode_u_leb128() which did
+ not work correctly if Dwarf_Word was 64 bits.
+*/
+#define DECODE_LEB128_UWORD(ptr, value) \
+ do { \
+ Dwarf_Word uleblen; \
+ value = _dwarf_decode_u_leb128(ptr,&uleblen); \
+ ptr += uleblen; \
+ } while (0)
+
+/*
+ Decodes signed leb128 encoded numbers.
+ Make sure ptr is a pointer to a 1-byte type.
+ In 2003 and earlier this was a hand-inlined
+ version of _dwarf_decode_s_leb128() which did
+ not work correctly if Dwarf_Word was 64 bits.
+
+*/
+#define DECODE_LEB128_SWORD(ptr, value) \
+ do { \
+ Dwarf_Word sleblen; \
+ value = _dwarf_decode_s_leb128(ptr,&sleblen); \
+ ptr += sleblen; \
+ } while(0)
+
+
+/*
+ Skips leb128_encoded numbers that are guaranteed
+ to be no more than 4 bytes long. Same for both
+ signed and unsigned numbers.
+*/
+#define SKIP_LEB128_WORD(ptr) \
+ do{ if ((*(ptr++) & 0x80) != 0) { \
+ if ((*(ptr++) & 0x80) != 0) { \
+ if ((*(ptr++) & 0x80) != 0) { \
+ if ((*(ptr++) & 0x80) != 0) { \
+ } \
+ } \
+ } \
+ } } while (0)
+
+
+#define CHECK_DIE(die, error_ret_value) \
+do {if (die == NULL) { \
+ _dwarf_error(NULL, error, DW_DLE_DIE_NULL); \
+ return(error_ret_value); \
+ } \
+ if (die->di_cu_context == NULL) { \
+ _dwarf_error(NULL, error, DW_DLE_DIE_NO_CU_CONTEXT); \
+ return(error_ret_value); \
+ } \
+ if (die->di_cu_context->cc_dbg == NULL) { \
+ _dwarf_error(NULL, error, DW_DLE_DBG_NULL); \
+ return(error_ret_value); \
+ } \
+} while (0)
+
+
+/*
+ Reads 'source' for 'length' bytes from unaligned addr.
+
+ Avoids any constant-in-conditional warnings and
+ avoids a test in the generated code (for non-const cases,
+ which are in the majority.)
+ Uses a temp to avoid the test.
+ The decl here should avoid any problem of size in the temp.
+ This code is ENDIAN DEPENDENT
+ The memcpy args are the endian issue.
+*/
+typedef Dwarf_Unsigned BIGGEST_UINT;
+
+#ifdef WORDS_BIGENDIAN
+#define READ_UNALIGNED(dbg,dest,desttype, source, length) \
+ do { \
+ BIGGEST_UINT _ltmp = 0; \
+ dbg->de_copy_word( (((char *)(&_ltmp)) + sizeof(_ltmp) - length), \
+ source, length) ; \
+ dest = (desttype)_ltmp; \
+ } while (0)
+
+
+/*
+ This macro sign-extends a variable depending on the length.
+ It fills the bytes between the size of the destination and
+ the length with appropriate padding.
+ This code is ENDIAN DEPENDENT but dependent only
+ on host endianness, not object file endianness.
+ The memcpy args are the issue.
+*/
+#define SIGN_EXTEND(dest, length) \
+ do {if (*(Dwarf_Sbyte *)((char *)&dest + sizeof(dest) - length) < 0) {\
+ memcpy((char *)&dest, "\xff\xff\xff\xff\xff\xff\xff\xff", \
+ sizeof(dest) - length); \
+ } \
+ } while (0)
+#else /* LITTLE ENDIAN */
+
+#define READ_UNALIGNED(dbg,dest,desttype, source, length) \
+ do { \
+ BIGGEST_UINT _ltmp = 0; \
+ dbg->de_copy_word( (char *)(&_ltmp) , \
+ source, length) ; \
+ dest = (desttype)_ltmp; \
+ } while (0)
+
+
+/*
+ This macro sign-extends a variable depending on the length.
+ It fills the bytes between the size of the destination and
+ the length with appropriate padding.
+ This code is ENDIAN DEPENDENT but dependent only
+ on host endianness, not object file endianness.
+ The memcpy args are the issue.
+*/
+#define SIGN_EXTEND(dest, length) \
+ do {if (*(Dwarf_Sbyte *)((char *)&dest + (length-1)) < 0) {\
+ memcpy((char *)&dest+length, \
+ "\xff\xff\xff\xff\xff\xff\xff\xff", \
+ sizeof(dest) - length); \
+ } \
+ } while (0)
+
+#endif /* ! LITTLE_ENDIAN */
+
+
+
+/*
+ READ_AREA LENGTH reads the length (the older way
+ of pure 32 or 64 bit
+ or the new proposed dwarfv2.1 64bit-extension way)
+
+ It reads the bits from where rw_src_data_p points to
+ and updates the rw_src_data_p to point past what was just read.
+
+ It updates w_length_size (to the size of an offset, either 4 or 8)
+ and w_exten_size (set 0 unless this frame has the DWARF3,4 64bit
+ extension, in which case w_exten_size is set to 4).
+
+ r_dbg is just the current dbg pointer.
+ w_target is the output length field.
+ r_targtype is the output type. Always Dwarf_Unsigned so far.
+
+*/
+/* This one handles the v2.1 64bit extension
+ and 32bit (and MIPS fixed 64 bit via the
+ dwarf_init-set r_dbg->de_length_size)..
+ It does not recognize any but the one distingushed value
+ (the only one with defined meaning).
+ It assumes that no CU will have a length
+ 0xffffffxx (32bit length)
+ or
+ 0xffffffxx xxxxxxxx (64bit length)
+ which makes possible auto-detection of the extension.
+
+ This depends on knowing that only a non-zero length
+ is legitimate (AFAICT), and for IRIX non-standard -64
+ dwarf that the first 32 bits of the 64bit offset will be
+ zero (because the compiler could not handle a truly large
+ value as of Jan 2003 and because no app has that much debug
+ info anyway, at least not in the IRIX case).
+
+ At present not testing for '64bit elf' here as that
+ does not seem necessary (none of the 64bit length seems
+ appropriate unless it's ident[EI_CLASS] == ELFCLASS64).
+*/
+# define READ_AREA_LENGTH(r_dbg,w_target,r_targtype, \
+ rw_src_data_p,w_length_size,w_exten_size) \
+do { READ_UNALIGNED(r_dbg,w_target,r_targtype, \
+ rw_src_data_p, ORIGINAL_DWARF_OFFSET_SIZE); \
+ if(w_target == DISTINGUISHED_VALUE) { \
+ /* dwarf3 64bit extension */ \
+ w_length_size = DISTINGUISHED_VALUE_OFFSET_SIZE; \
+ rw_src_data_p += ORIGINAL_DWARF_OFFSET_SIZE; \
+ w_exten_size = ORIGINAL_DWARF_OFFSET_SIZE; \
+ READ_UNALIGNED(r_dbg,w_target,r_targtype, \
+ rw_src_data_p, DISTINGUISHED_VALUE_OFFSET_SIZE);\
+ rw_src_data_p += DISTINGUISHED_VALUE_OFFSET_SIZE; \
+ } else { \
+ if(w_target == 0 && r_dbg->de_big_endian_object) { \
+ /* IRIX 64 bit, big endian. This test */ \
+ /* is not a truly precise test, a precise test */ \
+ /* would check if the target was IRIX. */ \
+ READ_UNALIGNED(r_dbg,w_target,r_targtype, \
+ rw_src_data_p, DISTINGUISHED_VALUE_OFFSET_SIZE); \
+ w_length_size = DISTINGUISHED_VALUE_OFFSET_SIZE; \
+ rw_src_data_p += DISTINGUISHED_VALUE_OFFSET_SIZE; \
+ w_exten_size = 0; \
+ } else { \
+ /* standard 32 bit dwarf2/dwarf3 */ \
+ w_exten_size = 0; \
+ w_length_size = ORIGINAL_DWARF_OFFSET_SIZE; \
+ rw_src_data_p += w_length_size; \
+ } \
+ } } while(0)
+
+Dwarf_Unsigned
+_dwarf_decode_u_leb128(Dwarf_Small * leb128,
+ Dwarf_Word * leb128_length);
+
+Dwarf_Signed
+_dwarf_decode_s_leb128(Dwarf_Small * leb128,
+ Dwarf_Word * leb128_length);
+
+Dwarf_Unsigned
+_dwarf_get_size_of_val(Dwarf_Debug dbg,
+ Dwarf_Unsigned form,
+ Dwarf_Half address_size,
+ Dwarf_Small * val_ptr,
+ int v_length_size);
+
+struct Dwarf_Hash_Table_Entry_s;
+/* This single struct is the base for the hash table.
+ The intent is that once the total_abbrev_count across
+ all the entries is greater than 10*current_table_entry_count
+ one should build a new Dwarf_Hash_Table_Base_s, rehash
+ all the existing entries, and delete the old table and entries.
+ (10 is a heuristic, nothing magic about it, but once the
+ count gets to 30 or 40 times current_table_entry_count
+ things really slow down a lot. One (500MB) application had
+ 127000 abbreviations in one compilation unit)
+ The incoming 'code' is an abbrev number and those simply
+ increase linearly so the hashing is perfect always.
+*/
+struct Dwarf_Hash_Table_s {
+ unsigned long tb_table_entry_count;
+ unsigned long tb_total_abbrev_count;
+ /* Each table entry is a list of abbreviations. */
+ struct Dwarf_Hash_Table_Entry_s *tb_entries;
+};
+
+/*
+ This struct is used to build a hash table for the
+ abbreviation codes for a compile-unit.
+*/
+struct Dwarf_Hash_Table_Entry_s {
+ Dwarf_Abbrev_List at_head;
+};
+
+
+
+Dwarf_Abbrev_List
+_dwarf_get_abbrev_for_code(Dwarf_CU_Context cu_context,
+ Dwarf_Unsigned code);
+
+
+/* return 1 if string ends before 'endptr' else
+** return 0 meaning string is not properly terminated.
+** Presumption is the 'endptr' pts to end of some dwarf section data.
+*/
+int _dwarf_string_valid(void *startptr, void *endptr);
+
+Dwarf_Unsigned _dwarf_length_of_cu_header(Dwarf_Debug,
+ Dwarf_Unsigned offset);
+Dwarf_Unsigned _dwarf_length_of_cu_header_simple(Dwarf_Debug);
+
+int _dwarf_load_debug_info(Dwarf_Debug dbg, Dwarf_Error *error);
+void _dwarf_free_abbrev_hash_table_contents(Dwarf_Debug dbg,
+ struct Dwarf_Hash_Table_s* hash_table);
+int _dwarf_get_address_size(Dwarf_Debug dbg, Dwarf_Die die);
+
+#endif /* DWARF_UTIL_H */
diff --git a/usr/src/lib/libdwarf/common/dwarf_vars.c b/usr/src/lib/libdwarf/common/dwarf_vars.c
new file mode 100644
index 0000000000..24105289ba
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_vars.c
@@ -0,0 +1,133 @@
+/*
+
+ Copyright (C) 2000,2002,2004,2005 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2009-2010 David Anderson. 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
+
+*/
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+#include "dwarf_vars.h"
+#include "dwarf_global.h"
+
+int
+dwarf_get_vars(Dwarf_Debug dbg,
+ Dwarf_Var ** vars,
+ Dwarf_Signed * ret_var_count, Dwarf_Error * error)
+{
+ int res = _dwarf_load_section(dbg, &dbg->de_debug_varnames,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ return _dwarf_internal_get_pubnames_like_data(dbg,
+ dbg->de_debug_varnames.dss_data,
+ dbg->de_debug_varnames.dss_size,
+ (Dwarf_Global **) vars, /* Type punning for sections
+ with identical format. */
+ ret_var_count,
+ error,
+ DW_DLA_VAR_CONTEXT,
+ DW_DLA_VAR,
+ DW_DLE_DEBUG_VARNAMES_LENGTH_BAD,
+ DW_DLE_DEBUG_VARNAMES_VERSION_ERROR);
+}
+
+/* Deallocating fully requires deallocating the list
+ and all entries. But some internal data is
+ not exposed, so we need a function with internal knowledge.
+*/
+
+void
+dwarf_vars_dealloc(Dwarf_Debug dbg, Dwarf_Var * dwgl,
+ Dwarf_Signed count)
+{
+ _dwarf_internal_globals_dealloc(dbg, (Dwarf_Global *) dwgl,
+ count,
+ DW_DLA_VAR_CONTEXT,
+ DW_DLA_VAR, DW_DLA_LIST);
+ return;
+}
+
+
+int
+dwarf_varname(Dwarf_Var var_in, char **ret_varname, Dwarf_Error * error)
+{
+ Dwarf_Global var = (Dwarf_Global) var_in;
+
+ if (var == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_VAR_NULL);
+ return (DW_DLV_ERROR);
+ }
+
+ *ret_varname = (char *) (var->gl_name);
+ return DW_DLV_OK;
+}
+
+
+int
+dwarf_var_die_offset(Dwarf_Var var_in,
+ Dwarf_Off * returned_offset, Dwarf_Error * error)
+{
+ Dwarf_Global var = (Dwarf_Global) var_in;
+
+ return dwarf_global_die_offset(var, returned_offset, error);
+
+}
+
+
+int
+dwarf_var_cu_offset(Dwarf_Var var_in,
+ Dwarf_Off * returned_offset, Dwarf_Error * error)
+{
+ Dwarf_Global var = (Dwarf_Global) var_in;
+
+ return dwarf_global_cu_offset(var, returned_offset, error);
+}
+
+
+int
+dwarf_var_name_offsets(Dwarf_Var var_in,
+ char **returned_name,
+ Dwarf_Off * die_offset,
+ Dwarf_Off * cu_offset, Dwarf_Error * error)
+{
+ Dwarf_Global var = (Dwarf_Global) var_in;
+
+ return
+ dwarf_global_name_offsets(var,
+ returned_name, die_offset, cu_offset,
+ error);
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_vars.h b/usr/src/lib/libdwarf/common/dwarf_vars.h
new file mode 100644
index 0000000000..bd5f967e48
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_vars.h
@@ -0,0 +1,41 @@
+/*
+
+ Copyright (C) 2000,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
+
+*/
+
+
+
+
+typedef struct Dwarf_Var_Context_s *Dwarf_Var_Context;
+
+/* struct never completed: see dwarf_global.h */
diff --git a/usr/src/lib/libdwarf/common/dwarf_weaks.c b/usr/src/lib/libdwarf/common/dwarf_weaks.c
new file mode 100644
index 0000000000..425916e62e
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_weaks.c
@@ -0,0 +1,130 @@
+/*
+
+ Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2009-2010 David Anderson. 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
+
+*/
+
+
+
+#include "config.h"
+#include "dwarf_incl.h"
+#include <stdio.h>
+#include "dwarf_weaks.h"
+#include "dwarf_global.h"
+
+int
+dwarf_get_weaks(Dwarf_Debug dbg,
+ Dwarf_Weak ** weaks,
+ Dwarf_Signed * ret_weak_count, Dwarf_Error * error)
+{
+ int res = _dwarf_load_section(dbg, &dbg->de_debug_weaknames,error);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+
+ return _dwarf_internal_get_pubnames_like_data(dbg,
+ dbg->de_debug_weaknames.dss_data,
+ dbg->de_debug_weaknames.dss_size,
+ (Dwarf_Global **) weaks, /* Type punning for sections
+ with identical format. */
+ ret_weak_count,
+ error,
+ DW_DLA_WEAK_CONTEXT,
+ DW_DLA_WEAK,
+ DW_DLE_DEBUG_WEAKNAMES_LENGTH_BAD,
+ DW_DLE_DEBUG_WEAKNAMES_VERSION_ERROR);
+}
+
+/* Deallocating fully requires deallocating the list
+ and all entries. But some internal data is
+ not exposed, so we need a function with internal knowledge.
+*/
+
+void
+dwarf_weaks_dealloc(Dwarf_Debug dbg, Dwarf_Weak * dwgl,
+ Dwarf_Signed count)
+{
+ _dwarf_internal_globals_dealloc(dbg, (Dwarf_Global *) dwgl,
+ count,
+ DW_DLA_WEAK_CONTEXT,
+ DW_DLA_WEAK, DW_DLA_LIST);
+ return;
+}
+
+
+
+int
+dwarf_weakname(Dwarf_Weak weak_in, char **ret_name, Dwarf_Error * error)
+{
+ Dwarf_Global weak = (Dwarf_Global) weak_in;
+
+ if (weak == NULL) {
+ _dwarf_error(NULL, error, DW_DLE_WEAK_NULL);
+ return (DW_DLV_ERROR);
+ }
+ *ret_name = (char *) (weak->gl_name);
+ return DW_DLV_OK;
+}
+
+
+int
+dwarf_weak_die_offset(Dwarf_Weak weak_in,
+ Dwarf_Off * weak_off, Dwarf_Error * error)
+{
+ Dwarf_Global weak = (Dwarf_Global) weak_in;
+
+ return dwarf_global_die_offset(weak, weak_off, error);
+}
+
+
+int
+dwarf_weak_cu_offset(Dwarf_Weak weak_in,
+ Dwarf_Off * weak_off, Dwarf_Error * error)
+{
+ Dwarf_Global weak = (Dwarf_Global) weak_in;
+
+ return dwarf_global_cu_offset(weak, weak_off, error);
+}
+
+
+int
+dwarf_weak_name_offsets(Dwarf_Weak weak_in,
+ char **weak_name,
+ Dwarf_Off * die_offset,
+ Dwarf_Off * cu_offset, Dwarf_Error * error)
+{
+ Dwarf_Global weak = (Dwarf_Global) weak_in;
+
+ return dwarf_global_name_offsets(weak,
+ weak_name, die_offset, cu_offset, error);
+}
diff --git a/usr/src/lib/libdwarf/common/dwarf_weaks.h b/usr/src/lib/libdwarf/common/dwarf_weaks.h
new file mode 100644
index 0000000000..d38f5f118a
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/dwarf_weaks.h
@@ -0,0 +1,41 @@
+/*
+
+ Copyright (C) 2000,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
+
+*/
+
+
+
+
+typedef struct Dwarf_Weak_Context_s *Dwarf_Weak_Context;
+
+/* struct never completed: see dwarf_global.h */
diff --git a/usr/src/lib/libdwarf/common/libdwarf.h b/usr/src/lib/libdwarf/common/libdwarf.h
new file mode 100644
index 0000000000..78627a96a6
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/libdwarf.h
@@ -0,0 +1,2736 @@
+/*
+
+ Copyright (C) 2000-2010 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright 2007-2010 Sun Microsystems, Inc. All rights reserved.
+ Portions Copyright 2008-2010 David Anderson. All rights reserved.
+ Portions Copyright 2008-2010 Arxan Technologies, 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
+
+*/
+
+
+#ifndef _LIBDWARF_H
+#define _LIBDWARF_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ libdwarf.h
+ $Revision: #9 $ $Date: 2008/01/17 $
+
+ For libdwarf producers and consumers
+
+ The interface is defined as having 8-byte signed and unsigned
+ values so it can handle 64-or-32bit target on 64-or-32bit host.
+ Addr is the native size: it represents pointers on
+ the host machine (not the target!).
+
+ This contains declarations for types and all producer
+ and consumer functions.
+
+ Function declarations are written on a single line each here
+ so one can use grep to each declaration in its entirety.
+ The declarations are a little harder to read this way, but...
+
+*/
+
+struct Elf;
+typedef struct Elf* dwarf_elf_handle;
+
+/* To enable printing with printf regardless of the
+ actual underlying data type, we define the DW_PR_xxx macros. */
+#if (_MIPS_SZLONG == 64)
+/* Special case for MIPS, so -64 (LP64) build gets simple -long-.
+ Non-MIPS LP64 or ILP64 environments should probably ensure
+ _MIPS_SZLONG set to 64 everywhere this header is #included.
+*/
+typedef int Dwarf_Bool; /* boolean type */
+typedef unsigned long Dwarf_Off; /* 4 or 8 byte file offset */
+typedef unsigned long Dwarf_Unsigned; /* 4 or 8 byte unsigned value */
+typedef unsigned short Dwarf_Half; /* 2 byte unsigned value */
+typedef unsigned char Dwarf_Small; /* 1 byte unsigned value */
+typedef signed long Dwarf_Signed; /* 4 or 8 byte signed value */
+typedef unsigned long Dwarf_Addr; /* target memory address */
+#define DW_PR_DUx "lx"
+#define DW_PR_DSx "lx"
+#define DW_PR_DUu "lu"
+#define DW_PR_DSd "ld"
+
+#else /* 32-bit */
+/* This is for ILP32, allowing i/o of 64bit dwarf info.
+ Also should be fine for LP64 and ILP64 cases.
+*/
+typedef int Dwarf_Bool; /* boolean type */
+typedef unsigned long long Dwarf_Off; /* 8 byte file offset */
+typedef unsigned long long Dwarf_Unsigned; /* 8 byte unsigned value*/
+typedef unsigned short Dwarf_Half; /* 2 byte unsigned value */
+typedef unsigned char Dwarf_Small; /* 1 byte unsigned value */
+typedef signed long long Dwarf_Signed; /* 8 byte signed value */
+typedef unsigned long long Dwarf_Addr; /* target memory address */
+#define DW_PR_DUx "llx"
+#define DW_PR_DSx "llx"
+#define DW_PR_DUu "llu"
+#define DW_PR_DSd "lld"
+#endif
+#ifdef HAVE_NONSTANDARD_PRINTF_64_FORMAT
+/* Windows does not use std C formatting, so allow it. */
+#undef DW_PR_DUx
+#undef DW_PR_DSx
+#undef DW_PR_DUu
+#undef DW_PR_DSd
+#define DW_PR_DUx "I64x"
+#define DW_PR_DSx "I64x"
+#define DW_PR_DUu "I64u"
+#define DW_PR_DSd "I64d"
+#endif /* HAVE_NONSTANDARD_FORMAT */
+
+typedef void* Dwarf_Ptr; /* host machine pointer */
+
+/* Used for DW_FORM_ref_sig8. It is not a string, it
+ is 8 bytes of a signature one would use to find
+ a type unit. See dwarf_formsig8()
+*/
+typedef struct {
+ char signature[8];
+} Dwarf_Sig8;
+
+/* Contains info on an uninterpreted block of data
+*/
+typedef struct {
+ Dwarf_Unsigned bl_len; /* length of block */
+ Dwarf_Ptr bl_data; /* uninterpreted data */
+ Dwarf_Small bl_from_loclist; /*non-0 if loclist, else debug_info*/
+ Dwarf_Unsigned bl_section_offset; /* Section (not CU) offset
+ which 'data' comes from. */
+} Dwarf_Block;
+
+
+/* location record
+*/
+typedef struct {
+ Dwarf_Small lr_atom; /* location operation */
+ Dwarf_Unsigned lr_number; /* operand */
+ Dwarf_Unsigned lr_number2; /* for OP_BREGx */
+ Dwarf_Unsigned lr_offset; /* offset in locexpr for OP_BRA etc */
+} Dwarf_Loc;
+
+
+/* location description
+*/
+typedef struct {
+ Dwarf_Addr ld_lopc; /* beginning of active range */
+ Dwarf_Addr ld_hipc; /* end of active range */
+ Dwarf_Half ld_cents; /* count of location records */
+ Dwarf_Loc* ld_s; /* pointer to list of same */
+ Dwarf_Small ld_from_loclist;
+ /* non-0 if loclist, else debug_info*/
+
+ Dwarf_Unsigned ld_section_offset; /* Section (not CU) offset
+ where loc-expr begins*/
+} Dwarf_Locdesc;
+
+/* First appears in DWARF3.
+ The dwr_addr1/addr2 data is either an offset (DW_RANGES_ENTRY)
+ or an address (dwr_addr2 in DW_RANGES_ADDRESS_SELECTION) or
+ both are zero (DW_RANGES_END).
+*/
+enum Dwarf_Ranges_Entry_Type { DW_RANGES_ENTRY,
+ DW_RANGES_ADDRESS_SELECTION,
+ DW_RANGES_END };
+typedef struct {
+ Dwarf_Addr dwr_addr1;
+ Dwarf_Addr dwr_addr2;
+ enum Dwarf_Ranges_Entry_Type dwr_type;
+} Dwarf_Ranges;
+
+/* Frame description instructions expanded.
+*/
+typedef struct {
+ Dwarf_Small fp_base_op;
+ Dwarf_Small fp_extended_op;
+ Dwarf_Half fp_register;
+
+ /* Value may be signed, depends on op.
+ Any applicable data_alignment_factor has
+ not been applied, this is the raw offset. */
+ Dwarf_Unsigned fp_offset;
+ Dwarf_Off fp_instr_offset;
+} Dwarf_Frame_Op; /* DWARF2 */
+
+typedef struct {
+ Dwarf_Small fp_base_op;
+ Dwarf_Small fp_extended_op;
+ Dwarf_Half fp_register;
+
+ /* Value may be signed, depends on op.
+ Any applicable data_alignment_factor has
+ not been applied, this is the raw offset. */
+ Dwarf_Unsigned fp_offset_or_block_len;
+ Dwarf_Small *fp_expr_block;
+
+ Dwarf_Off fp_instr_offset;
+} Dwarf_Frame_Op3; /* DWARF3 and DWARF2 compatible */
+
+/* ***IMPORTANT NOTE, TARGET DEPENDENCY ****
+ DW_REG_TABLE_SIZE must be at least as large as
+ the number of registers
+ (DW_FRAME_LAST_REG_NUM) as defined in dwarf.h
+ Preferably identical to DW_FRAME_LAST_REG_NUM.
+ Ensure [0-DW_REG_TABLE_SIZE] does not overlap
+ DW_FRAME_UNDEFINED_VAL or DW_FRAME_SAME_VAL.
+ Also ensure DW_FRAME_REG_INITIAL_VALUE is set to what
+ is appropriate to your cpu.
+ For various CPUs DW_FRAME_UNDEFINED_VAL is correct
+ as the value for DW_FRAME_REG_INITIAL_VALUE.
+
+ For consumer apps, this can be set dynamically: see
+ dwarf_set_frame_rule_table_size();
+ */
+#ifndef DW_REG_TABLE_SIZE
+#define DW_REG_TABLE_SIZE 66
+#endif
+
+/* For MIPS, DW_FRAME_SAME_VAL is the correct default value
+ for a frame register value. For other CPUS another value
+ may be better, such as DW_FRAME_UNDEFINED_VAL.
+ See dwarf_set_frame_rule_table_size
+*/
+#ifndef DW_FRAME_REG_INITIAL_VALUE
+#define DW_FRAME_REG_INITIAL_VALUE DW_FRAME_SAME_VAL
+#endif
+
+/* Taken as meaning 'undefined value', this is not
+ a column or register number.
+ Only present at libdwarf runtime in the consumer
+ interfaces. Never on disk.
+ DW_FRAME_* Values present on disk are in dwarf.h
+ Ensure this is > DW_REG_TABLE_SIZE (the reg table
+ size is changeable at runtime with the *reg3() interfaces,
+ and this value must be greater than the reg table size).
+*/
+#define DW_FRAME_UNDEFINED_VAL 1034
+
+/* Taken as meaning 'same value' as caller had, not a column
+ or register number.
+ Only present at libdwarf runtime in the consumer
+ interfaces. Never on disk.
+ DW_FRAME_* Values present on disk are in dwarf.h
+ Ensure this is > DW_REG_TABLE_SIZE (the reg table
+ size is changeable at runtime with the *reg3() interfaces,
+ and this value must be greater than the reg table size).
+*/
+#define DW_FRAME_SAME_VAL 1035
+
+/* For DWARF3 consumer interfaces, make the CFA a column with no
+ real table number. This is what should have been done
+ for the DWARF2 interfaces. This actually works for
+ both DWARF2 and DWARF3, but see the libdwarf documentation
+ on Dwarf_Regtable3 and dwarf_get_fde_info_for_reg3()
+ and dwarf_get_fde_info_for_all_regs3()
+ Do NOT use this with the older dwarf_get_fde_info_for_reg()
+ or dwarf_get_fde_info_for_all_regs() consumer interfaces.
+ Must be higher than any register count for *any* ABI
+ (ensures maximum applicability with minimum effort).
+ Ensure this is > DW_REG_TABLE_SIZE (the reg table
+ size is changeable at runtime with the *reg3() interfaces,
+ and this value must be greater than the reg table size).
+ Only present at libdwarf runtime in the consumer
+ interfaces. Never on disk.
+*/
+#define DW_FRAME_CFA_COL3 1436
+
+/* The following are all needed to evaluate DWARF3 register rules.
+*/
+#define DW_EXPR_OFFSET 0 /* DWARF2 only sees this. */
+#define DW_EXPR_VAL_OFFSET 1
+#define DW_EXPR_EXPRESSION 2
+#define DW_EXPR_VAL_EXPRESSION 3
+
+typedef struct Dwarf_Regtable_Entry_s {
+ /* For each index i (naming a hardware register with dwarf number
+ i) the following is true and defines the value of that register:
+
+ If dw_regnum is Register DW_FRAME_UNDEFINED_VAL
+ it is not DWARF register number but
+ a place holder indicating the register has no defined value.
+ If dw_regnum is Register DW_FRAME_SAME_VAL
+ it is not DWARF register number but
+ a place holder indicating the register has the same
+ value in the previous frame.
+ DW_FRAME_UNDEFINED_VAL, DW_FRAME_SAME_VAL are
+ only present at libdwarf runtime. Never on disk.
+ DW_FRAME_* Values present on disk are in dwarf.h
+
+ Otherwise: the register number is a DWARF register number
+ (see ABI documents for how this translates to hardware/
+ software register numbers in the machine hardware)
+ and the following applies:
+
+ if dw_value_type == DW_EXPR_OFFSET (the only case for dwarf2):
+ If dw_offset_relevant is non-zero, then
+ the value is stored at at the address CFA+N where
+ N is a signed offset.
+ Rule: Offset(N)
+ If dw_offset_relevant is zero, then the value of the register
+ is the value of (DWARF) register number dw_regnum.
+ Rule: register(F)
+ Other values of dw_value_type are an error.
+ */
+ Dwarf_Small dw_offset_relevant;
+
+ /* For DWARF2, always 0 */
+ Dwarf_Small dw_value_type;
+
+ Dwarf_Half dw_regnum;
+
+ /* The data type here should the larger of Dwarf_Addr
+ and Dwarf_Unsigned and Dwarf_Signed. */
+ Dwarf_Addr dw_offset;
+} Dwarf_Regtable_Entry;
+
+typedef struct Dwarf_Regtable_s {
+ struct Dwarf_Regtable_Entry_s rules[DW_REG_TABLE_SIZE];
+} Dwarf_Regtable;
+
+/* opaque type. Functional interface shown later. */
+struct Dwarf_Reg_value3_s;
+typedef struct Dwarf_Reg_value3_s Dwarf_Reg_Value3;
+
+typedef struct Dwarf_Regtable_Entry3_s {
+ /* For each index i (naming a hardware register with dwarf number
+ i) the following is true and defines the value of that register:
+
+ If dw_regnum is Register DW_FRAME_UNDEFINED_VAL
+ it is not DWARF register number but
+ a place holder indicating the register has no defined value.
+ If dw_regnum is Register DW_FRAME_SAME_VAL
+ it is not DWARF register number but
+ a place holder indicating the register has the same
+ value in the previous frame.
+ DW_FRAME_UNDEFINED_VAL, DW_FRAME_SAME_VAL and
+ DW_FRAME_CFA_COL3 are only present at libdwarf runtime.
+ Never on disk.
+ DW_FRAME_* Values present on disk are in dwarf.h
+ Because DW_FRAME_SAME_VAL and DW_FRAME_UNDEFINED_VAL
+ and DW_FRAME_CFA_COL3 are defineable at runtime
+ consider the names symbolic in this comment, not absolute.
+
+ Otherwise: the register number is a DWARF register number
+ (see ABI documents for how this translates to hardware/
+ software register numbers in the machine hardware)
+ and the following applies:
+
+ In a cfa-defining entry (rt3_cfa_rule) the regnum is the
+ CFA 'register number'. Which is some 'normal' register,
+ not DW_FRAME_CFA_COL3, nor DW_FRAME_SAME_VAL, nor
+ DW_FRAME_UNDEFINED_VAL.
+
+ If dw_value_type == DW_EXPR_OFFSET (the only possible case for
+ dwarf2):
+ If dw_offset_relevant is non-zero, then
+ the value is stored at at the address
+ CFA+N where N is a signed offset.
+ dw_regnum is the cfa register rule which means
+ one ignores dw_regnum and uses the CFA appropriately.
+ So dw_offset_or_block_len is a signed value, really,
+ and must be printed/evaluated as such.
+ Rule: Offset(N)
+ If dw_offset_relevant is zero, then the value of the register
+ is the value of (DWARF) register number dw_regnum.
+ Rule: register(R)
+ If dw_value_type == DW_EXPR_VAL_OFFSET
+ the value of this register is CFA +N where N is a signed offset.
+ dw_regnum is the cfa register rule which means
+ one ignores dw_regnum and uses the CFA appropriately.
+ Rule: val_offset(N)
+ If dw_value_type == DW_EXPR_EXPRESSION
+ The value of the register is the value at the address
+ computed by evaluating the DWARF expression E.
+ Rule: expression(E)
+ The expression E byte stream is pointed to by dw_block_ptr.
+ The expression length in bytes is given by
+ dw_offset_or_block_len.
+ If dw_value_type == DW_EXPR_VAL_EXPRESSION
+ The value of the register is the value
+ computed by evaluating the DWARF expression E.
+ Rule: val_expression(E)
+ The expression E byte stream is pointed to by dw_block_ptr.
+ The expression length in bytes is given by
+ dw_offset_or_block_len.
+ Other values of dw_value_type are an error.
+ */
+ Dwarf_Small dw_offset_relevant;
+ Dwarf_Small dw_value_type;
+ Dwarf_Half dw_regnum;
+ Dwarf_Unsigned dw_offset_or_block_len;
+ Dwarf_Ptr dw_block_ptr;
+
+}Dwarf_Regtable_Entry3;
+
+/* For the DWARF3 version, moved the DW_FRAME_CFA_COL
+ out of the array and into its own struct.
+ Having it part of the array is not very easy to work
+ with from a portability point of view: changing
+ the number for every architecture is a pain (if one fails
+ to set it correctly a register rule gets clobbered when
+ setting CFA). With MIPS it just happened to be easy to use
+ DW_FRAME_CFA_COL (it was wrong conceptually but it was easy...).
+
+ rt3_rules and rt3_reg_table_size must be filled in before
+ calling libdwarf. Filled in with a pointer to an array
+ (pointer and array set up by the calling application)
+ of rt3_reg_table_size Dwarf_Regtable_Entry3_s structs.
+ libdwarf does not allocate or deallocate space for the
+ rules, you must do so. libdwarf will initialize the
+ contents rules array, you do not need to do so (though
+ if you choose to initialize the array somehow that is ok:
+ libdwarf will overwrite your initializations with its own).
+
+*/
+typedef struct Dwarf_Regtable3_s {
+ struct Dwarf_Regtable_Entry3_s rt3_cfa_rule;
+
+ Dwarf_Half rt3_reg_table_size;
+ struct Dwarf_Regtable_Entry3_s * rt3_rules;
+} Dwarf_Regtable3;
+
+
+/* Use for DW_EPXR_STANDARD., DW_EXPR_VAL_OFFSET.
+ Returns DW_DLV_OK if the value is available.
+ If DW_DLV_OK returns the regnum and offset thru the pointers
+ (which the consumer must use appropriately).
+*/
+int dwarf_frame_get_reg_register(struct Dwarf_Regtable_Entry3_s *reg_in,
+ Dwarf_Small *offset_relevant,
+ Dwarf_Half *regnum_out,
+ Dwarf_Signed *offset_out);
+
+/* Use for DW_EXPR_EXPRESSION, DW_EXPR_VAL_EXPRESSION.
+ Returns DW_DLV_OK if the value is available.
+ The caller must pass in the address of a valid
+ Dwarf_Block (the caller need not initialize it).
+*/
+int dwarf_frame_get_reg_expression(struct Dwarf_Regtable_Entry3_s *reg_in,
+ Dwarf_Block *block_out);
+
+
+/* For DW_DLC_SYMBOLIC_RELOCATIONS output to caller
+ v2, adding drd_length: some relocations are 4 and
+ some 8 bytes (pointers are 8, section offsets 4) in
+ some dwarf environments. (MIPS relocations are all one
+ size in any given ABI.) Changing drd_type to an unsigned char
+ to keep struct size down.
+*/
+enum Dwarf_Rel_Type {
+ dwarf_drt_none, /* Should not get to caller */
+ dwarf_drt_data_reloc, /* Simple normal relocation. */
+ dwarf_drt_segment_rel, /* Special reloc, exceptions. */
+ /* dwarf_drt_first_of_length_pair and drt_second
+ are for for the .word end - begin case. */
+ dwarf_drt_first_of_length_pair,
+ dwarf_drt_second_of_length_pair
+};
+
+typedef struct Dwarf_P_Marker_s * Dwarf_P_Marker;
+struct Dwarf_P_Marker_s {
+ Dwarf_Unsigned ma_marker;
+ Dwarf_Unsigned ma_offset;
+};
+
+typedef struct Dwarf_Relocation_Data_s * Dwarf_Relocation_Data;
+struct Dwarf_Relocation_Data_s {
+ unsigned char drd_type; /* Cast to/from Dwarf_Rel_Type
+ to keep size small in struct. */
+ unsigned char drd_length; /* Length in bytes of data being
+ relocated. 4 for 32bit data,
+ 8 for 64bit data. */
+ Dwarf_Unsigned drd_offset; /* Where the data to reloc is. */
+ Dwarf_Unsigned drd_symbol_index;
+};
+
+typedef struct Dwarf_P_String_Attr_s * Dwarf_P_String_Attr;
+struct Dwarf_P_String_Attr_s {
+ Dwarf_Unsigned sa_offset; /* Offset of string attribute data */
+ Dwarf_Unsigned sa_nbytes;
+};
+
+
+/* Opaque types for Consumer Library. */
+typedef struct Dwarf_Debug_s* Dwarf_Debug;
+typedef struct Dwarf_Die_s* Dwarf_Die;
+typedef struct Dwarf_Line_s* Dwarf_Line;
+typedef struct Dwarf_Global_s* Dwarf_Global;
+typedef struct Dwarf_Func_s* Dwarf_Func;
+typedef struct Dwarf_Type_s* Dwarf_Type;
+typedef struct Dwarf_Var_s* Dwarf_Var;
+typedef struct Dwarf_Weak_s* Dwarf_Weak;
+typedef struct Dwarf_Error_s* Dwarf_Error;
+typedef struct Dwarf_Attribute_s* Dwarf_Attribute;
+typedef struct Dwarf_Abbrev_s* Dwarf_Abbrev;
+typedef struct Dwarf_Fde_s* Dwarf_Fde;
+typedef struct Dwarf_Cie_s* Dwarf_Cie;
+typedef struct Dwarf_Arange_s* Dwarf_Arange;
+
+/* Opaque types for Producer Library. */
+typedef struct Dwarf_P_Debug_s* Dwarf_P_Debug;
+typedef struct Dwarf_P_Die_s* Dwarf_P_Die;
+typedef struct Dwarf_P_Attribute_s* Dwarf_P_Attribute;
+typedef struct Dwarf_P_Fde_s* Dwarf_P_Fde;
+typedef struct Dwarf_P_Expr_s* Dwarf_P_Expr;
+typedef Dwarf_Unsigned Dwarf_Tag;
+
+
+/* error handler function
+*/
+typedef void (*Dwarf_Handler)(Dwarf_Error /*error*/, Dwarf_Ptr /*errarg*/);
+
+
+/* Begin libdwarf Object File Interface declarations.
+
+As of February 2008 there are multiple dwarf_reader object access
+initialization methods available:
+The traditional dwarf_elf_init() and dwarf_init() and dwarf_finish()
+ which assume libelf and POSIX file access.
+An object-file and library agnostic dwarf_object_init() and dwarf_object_finish()
+ which allow the coder to provide object access routines
+ abstracting away the elf interface. So there is no dependence in the
+ reader code on the object format and no dependence on libelf.
+ See the code in dwarf_elf_access.c and dwarf_original_elf_init.c
+ to see an example of initializing the structures mentioned below.
+
+Projects using dwarf_elf_init() or dwarf_init() can ignore
+the Dwarf_Obj_Access* structures entirely as all these details
+are completed for you.
+
+*/
+
+typedef struct Dwarf_Obj_Access_Interface_s Dwarf_Obj_Access_Interface;
+typedef struct Dwarf_Obj_Access_Methods_s Dwarf_Obj_Access_Methods;
+typedef struct Dwarf_Obj_Access_Section_s Dwarf_Obj_Access_Section;
+
+
+/* Used in the get_section interface function
+ in Dwarf_Obj_Access_Section_s. Since libdwarf
+ depends on standard DWARF section names an object
+ format that has no such names (but has some
+ method of setting up 'sections equivalents')
+ must arrange to return standard DWARF section
+ names in the 'name' field. libdwarf does
+ not free the strings in 'name'. */
+struct Dwarf_Obj_Access_Section_s {
+ Dwarf_Addr addr;
+ Dwarf_Unsigned size;
+ const char* name;
+ /* Set link to zero if it is meaningless. If non-zero
+ it should be a link to a rela section or from symtab
+ to strtab. In Elf it is sh_link. */
+ Dwarf_Unsigned link;
+};
+
+/* Returned by the get_endianness function in
+ Dwarf_Obj_Access_Methods_s. */
+typedef enum {
+ DW_OBJECT_MSB,
+ DW_OBJECT_LSB
+} Dwarf_Endianness;
+
+/* The functions we need to access object data from libdwarf are declared here.
+
+ In these function pointer declarations
+ 'void *obj' is intended to be a pointer (the object field in
+ Dwarf_Obj_Access_Interface_s)
+ that hides the library-specific and object-specific data that makes
+ it possible to handle multiple object formats and multiple libraries.
+ It's not required that one handles multiple such in a single libdwarf
+ archive/shared-library (but not ruled out either).
+ See dwarf_elf_object_access_internals_t and dwarf_elf_access.c
+ for an example.
+
+*/
+struct Dwarf_Obj_Access_Methods_s {
+ /**
+ * get_section_info
+ *
+ * Get address, size, and name info about a section.
+ *
+ * Parameters
+ * section_index - Zero-based index.
+ * return_section - Pointer to a structure in which section info
+ * will be placed. Caller must provide a valid pointer to a
+ * structure area. The structure's contents will be overwritten
+ * by the call to get_section_info.
+ * error - A pointer to an integer in which an error code may be stored.
+ *
+ * Return
+ * DW_DLV_OK - Everything ok.
+ * DW_DLV_ERROR - Error occurred. Use 'error' to determine the
+ * libdwarf defined error.
+ * DW_DLV_NO_ENTRY - No such section.
+ */
+ int (*get_section_info)(void* obj, Dwarf_Half section_index,
+ Dwarf_Obj_Access_Section* return_section, int* error);
+ /**
+ * get_byte_order
+ *
+ * Get whether the object file represented by this interface is big-endian
+ * (DW_OBJECT_MSB) or little endian (DW_OBJECT_LSB).
+ *
+ * Parameters
+ * obj - Equivalent to 'this' in OO languages.
+ *
+ * Return
+ * Endianness of object. Cannot fail.
+ */
+ Dwarf_Endianness (*get_byte_order)(void* obj);
+ /**
+ * get_length_size
+ *
+ * Get the size of a length field in the underlying object file.
+ * libdwarf currently supports * 4 and 8 byte sizes, but may
+ * support larger in the future.
+ * Perhaps the return type should be an enumeration?
+ *
+ * Parameters
+ * obj - Equivalent to 'this' in OO languages.
+ *
+ * Return
+ * Size of length. Cannot fail.
+ */
+ Dwarf_Small (*get_length_size)(void* obj);
+ /**
+ * get_pointer_size
+ *
+ * Get the size of a pointer field in the underlying object file.
+ * libdwarf currently supports 4 and 8 byte sizes.
+ * Perhaps the return type should be an enumeration?
+
+ * Return
+ * Size of pointer. Cannot fail.
+ */
+ Dwarf_Small (*get_pointer_size)(void* obj);
+ /**
+ * get_section_count
+ *
+ * Get the number of sections in the object file.
+ *
+ * Parameters
+ *
+ * Return
+ * Number of sections
+ */
+ Dwarf_Unsigned (*get_section_count)(void* obj);
+ /**
+ * load_section
+ *
+ * Get a pointer to an array of bytes that represent the section.
+ *
+ * Parameters
+ * section_index - Zero-based index.
+ * return_data - The address of a pointer to which the section data block
+ * will be assigned.
+ * error - Pointer to an integer for returning libdwarf-defined
+ * error numbers.
+ *
+ * Return
+ * DW_DLV_OK - No error.
+ * DW_DLV_ERROR - Error. Use 'error' to indicate a libdwarf-defined
+ * error number.
+ * DW_DLV_NO_ENTRY - No such section.
+ */
+ int (*load_section)(void* obj, Dwarf_Half section_index,
+ Dwarf_Small** return_data, int* error);
+
+ /**
+ * relocate_a_section
+ * If relocations are not supported leave this pointer NULL.
+ *
+ * Get a pointer to an array of bytes that represent the section.
+ *
+ * Parameters
+ * section_index - Zero-based index of the section to be relocated.
+ * error - Pointer to an integer for returning libdwarf-defined
+ * error numbers.
+ *
+ * Return
+ * DW_DLV_OK - No error.
+ * DW_DLV_ERROR - Error. Use 'error' to indicate a libdwarf-defined
+ * error number.
+ * DW_DLV_NO_ENTRY - No such section.
+ */
+ int (*relocate_a_section)(void* obj, Dwarf_Half section_index,
+ Dwarf_Debug dbg,
+ int* error);
+
+};
+
+
+
+/* These structures are allocated and deallocated by your code
+ when you are using the libdwarf Object File Interface
+ [dwarf_object_init() and dwarf_object_finish()] directly.
+ dwarf_object_finish() does not free
+ struct Dwarf_Obj_Access_Interface_s or its content.
+ (libdwarf does record a pointer to this struct: you must
+ ensure that pointer remains valid for as long as
+ a libdwarf instance is open (meaning
+ after dwarf_init() and before dwarf_finish()).
+
+ If you are reading Elf objects and libelf use dwarf_init()
+ or dwarf_elf_init() which take care of these details.
+*/
+struct Dwarf_Obj_Access_Interface_s {
+ /* object is a void* as it hides the data the object access routines
+ need (which varies by library in use and object format).
+ */
+ void* object;
+ const Dwarf_Obj_Access_Methods * methods;
+};
+
+/* End libdwarf Object File Interface */
+
+/*
+ Dwarf_dealloc() alloc_type arguments.
+ Argument points to:
+*/
+#define DW_DLA_STRING 0x01 /* char* */
+#define DW_DLA_LOC 0x02 /* Dwarf_Loc */
+#define DW_DLA_LOCDESC 0x03 /* Dwarf_Locdesc */
+#define DW_DLA_ELLIST 0x04 /* Dwarf_Ellist (not used)*/
+#define DW_DLA_BOUNDS 0x05 /* Dwarf_Bounds (not used) */
+#define DW_DLA_BLOCK 0x06 /* Dwarf_Block */
+#define DW_DLA_DEBUG 0x07 /* Dwarf_Debug */
+#define DW_DLA_DIE 0x08 /* Dwarf_Die */
+#define DW_DLA_LINE 0x09 /* Dwarf_Line */
+#define DW_DLA_ATTR 0x0a /* Dwarf_Attribute */
+#define DW_DLA_TYPE 0x0b /* Dwarf_Type (not used) */
+#define DW_DLA_SUBSCR 0x0c /* Dwarf_Subscr (not used) */
+#define DW_DLA_GLOBAL 0x0d /* Dwarf_Global */
+#define DW_DLA_ERROR 0x0e /* Dwarf_Error */
+#define DW_DLA_LIST 0x0f /* a list */
+#define DW_DLA_LINEBUF 0x10 /* Dwarf_Line* (not used) */
+#define DW_DLA_ARANGE 0x11 /* Dwarf_Arange */
+#define DW_DLA_ABBREV 0x12 /* Dwarf_Abbrev */
+#define DW_DLA_FRAME_OP 0x13 /* Dwarf_Frame_Op */
+#define DW_DLA_CIE 0x14 /* Dwarf_Cie */
+#define DW_DLA_FDE 0x15 /* Dwarf_Fde */
+#define DW_DLA_LOC_BLOCK 0x16 /* Dwarf_Loc Block (not used) */
+#define DW_DLA_FRAME_BLOCK 0x17 /* Dwarf_Frame Block (not used) */
+#define DW_DLA_FUNC 0x18 /* Dwarf_Func */
+#define DW_DLA_TYPENAME 0x19 /* Dwarf_Type */
+#define DW_DLA_VAR 0x1a /* Dwarf_Var */
+#define DW_DLA_WEAK 0x1b /* Dwarf_Weak */
+#define DW_DLA_ADDR 0x1c /* Dwarf_Addr sized entries */
+#define DW_DLA_RANGES 0x1d /* Dwarf_Ranges */
+
+/* The augmenter string for CIE */
+#define DW_CIE_AUGMENTER_STRING_V0 "z"
+
+/* dwarf_init() access arguments
+*/
+#define DW_DLC_READ 0 /* read only access */
+#define DW_DLC_WRITE 1 /* write only access */
+#define DW_DLC_RDWR 2 /* read/write access NOT SUPPORTED*/
+
+/* pro_init() access flag modifiers
+ If HAVE_DWARF2_99_EXTENSION is defined at libdwarf build time
+ and DW_DLC_OFFSET_SIZE_64 is passed in pro_init() flags then the DWARF3
+ 64 bit offset extension is used to generate 64 bit offsets.
+*/
+#define DW_DLC_SIZE_64 0x40000000 /* 32-bit address-size target */
+#define DW_DLC_SIZE_32 0x20000000 /* 64-bit address-size target */
+#define DW_DLC_OFFSET_SIZE_64 0x10000000 /* 64-bit offset-size DWARF */
+
+/* dwarf_pro_init() access flag modifiers
+*/
+#define DW_DLC_ISA_MIPS 0x00000000 /* MIPS target */
+#define DW_DLC_ISA_IA64 0x01000000 /* IA64 target */
+#define DW_DLC_STREAM_RELOCATIONS 0x02000000 /* Old style binary relocs */
+
+ /* Usable with assembly output because it is up to the producer to
+ deal with locations in whatever manner the producer code wishes.
+ Possibly emitting text an assembler will recognize. */
+#define DW_DLC_SYMBOLIC_RELOCATIONS 0x04000000
+
+#define DW_DLC_TARGET_BIGENDIAN 0x08000000 /* Big endian target */
+#define DW_DLC_TARGET_LITTLEENDIAN 0x00100000 /* Little endian target */
+
+#if 0
+ /*
+ The libdwarf producer interfaces jumble these two semantics together in
+ confusing ways. We *should* have flags like these...
+ But changing the code means a lot of diffs. So for now,
+ we leave things as they are
+ */
+ #define DW_DLC_SUN_OFFSET32 0x00010000 /* use 32-bit sec offsets */
+ #define DW_DLC_SUN_OFFSET64 0x00020000 /* use 64-bit sec offsets */
+ #define DW_DLC_SUN_POINTER32 0x00040000 /* use 4 for address_size */
+ #define DW_DLC_SUN_POINTER64 0x00080000 /* use 8 for address_size */
+#endif
+
+/* dwarf_pcline() slide arguments
+*/
+#define DW_DLS_BACKWARD -1 /* slide backward to find line */
+#define DW_DLS_NOSLIDE 0 /* match exactly without sliding */
+#define DW_DLS_FORWARD 1 /* slide forward to find line */
+
+/* libdwarf error numbers
+*/
+#define DW_DLE_NE 0 /* no error */
+#define DW_DLE_VMM 1 /* dwarf format/library version mismatch */
+#define DW_DLE_MAP 2 /* memory map failure */
+#define DW_DLE_LEE 3 /* libelf error */
+#define DW_DLE_NDS 4 /* no debug section */
+#define DW_DLE_NLS 5 /* no line section */
+#define DW_DLE_ID 6 /* invalid descriptor for query */
+#define DW_DLE_IOF 7 /* I/O failure */
+#define DW_DLE_MAF 8 /* memory allocation failure */
+#define DW_DLE_IA 9 /* invalid argument */
+#define DW_DLE_MDE 10 /* mangled debugging entry */
+#define DW_DLE_MLE 11 /* mangled line number entry */
+#define DW_DLE_FNO 12 /* file not open */
+#define DW_DLE_FNR 13 /* file not a regular file */
+#define DW_DLE_FWA 14 /* file open with wrong access */
+#define DW_DLE_NOB 15 /* not an object file */
+#define DW_DLE_MOF 16 /* mangled object file header */
+#define DW_DLE_EOLL 17 /* end of location list entries */
+#define DW_DLE_NOLL 18 /* no location list section */
+#define DW_DLE_BADOFF 19 /* Invalid offset */
+#define DW_DLE_EOS 20 /* end of section */
+#define DW_DLE_ATRUNC 21 /* abbreviations section appears truncated*/
+#define DW_DLE_BADBITC 22 /* Address size passed to dwarf bad*/
+ /* It is not an allowed size (64 or 32) */
+ /* Error codes defined by the current Libdwarf Implementation. */
+#define DW_DLE_DBG_ALLOC 23
+#define DW_DLE_FSTAT_ERROR 24
+#define DW_DLE_FSTAT_MODE_ERROR 25
+#define DW_DLE_INIT_ACCESS_WRONG 26
+#define DW_DLE_ELF_BEGIN_ERROR 27
+#define DW_DLE_ELF_GETEHDR_ERROR 28
+#define DW_DLE_ELF_GETSHDR_ERROR 29
+#define DW_DLE_ELF_STRPTR_ERROR 30
+#define DW_DLE_DEBUG_INFO_DUPLICATE 31
+#define DW_DLE_DEBUG_INFO_NULL 32
+#define DW_DLE_DEBUG_ABBREV_DUPLICATE 33
+#define DW_DLE_DEBUG_ABBREV_NULL 34
+#define DW_DLE_DEBUG_ARANGES_DUPLICATE 35
+#define DW_DLE_DEBUG_ARANGES_NULL 36
+#define DW_DLE_DEBUG_LINE_DUPLICATE 37
+#define DW_DLE_DEBUG_LINE_NULL 38
+#define DW_DLE_DEBUG_LOC_DUPLICATE 39
+#define DW_DLE_DEBUG_LOC_NULL 40
+#define DW_DLE_DEBUG_MACINFO_DUPLICATE 41
+#define DW_DLE_DEBUG_MACINFO_NULL 42
+#define DW_DLE_DEBUG_PUBNAMES_DUPLICATE 43
+#define DW_DLE_DEBUG_PUBNAMES_NULL 44
+#define DW_DLE_DEBUG_STR_DUPLICATE 45
+#define DW_DLE_DEBUG_STR_NULL 46
+#define DW_DLE_CU_LENGTH_ERROR 47
+#define DW_DLE_VERSION_STAMP_ERROR 48
+#define DW_DLE_ABBREV_OFFSET_ERROR 49
+#define DW_DLE_ADDRESS_SIZE_ERROR 50
+#define DW_DLE_DEBUG_INFO_PTR_NULL 51
+#define DW_DLE_DIE_NULL 52
+#define DW_DLE_STRING_OFFSET_BAD 53
+#define DW_DLE_DEBUG_LINE_LENGTH_BAD 54
+#define DW_DLE_LINE_PROLOG_LENGTH_BAD 55
+#define DW_DLE_LINE_NUM_OPERANDS_BAD 56
+#define DW_DLE_LINE_SET_ADDR_ERROR 57 /* No longer used. */
+#define DW_DLE_LINE_EXT_OPCODE_BAD 58
+#define DW_DLE_DWARF_LINE_NULL 59
+#define DW_DLE_INCL_DIR_NUM_BAD 60
+#define DW_DLE_LINE_FILE_NUM_BAD 61
+#define DW_DLE_ALLOC_FAIL 62
+#define DW_DLE_NO_CALLBACK_FUNC 63
+#define DW_DLE_SECT_ALLOC 64
+#define DW_DLE_FILE_ENTRY_ALLOC 65
+#define DW_DLE_LINE_ALLOC 66
+#define DW_DLE_FPGM_ALLOC 67
+#define DW_DLE_INCDIR_ALLOC 68
+#define DW_DLE_STRING_ALLOC 69
+#define DW_DLE_CHUNK_ALLOC 70
+#define DW_DLE_BYTEOFF_ERR 71
+#define DW_DLE_CIE_ALLOC 72
+#define DW_DLE_FDE_ALLOC 73
+#define DW_DLE_REGNO_OVFL 74
+#define DW_DLE_CIE_OFFS_ALLOC 75
+#define DW_DLE_WRONG_ADDRESS 76
+#define DW_DLE_EXTRA_NEIGHBORS 77
+#define DW_DLE_WRONG_TAG 78
+#define DW_DLE_DIE_ALLOC 79
+#define DW_DLE_PARENT_EXISTS 80
+#define DW_DLE_DBG_NULL 81
+#define DW_DLE_DEBUGLINE_ERROR 82
+#define DW_DLE_DEBUGFRAME_ERROR 83
+#define DW_DLE_DEBUGINFO_ERROR 84
+#define DW_DLE_ATTR_ALLOC 85
+#define DW_DLE_ABBREV_ALLOC 86
+#define DW_DLE_OFFSET_UFLW 87
+#define DW_DLE_ELF_SECT_ERR 88
+#define DW_DLE_DEBUG_FRAME_LENGTH_BAD 89
+#define DW_DLE_FRAME_VERSION_BAD 90
+#define DW_DLE_CIE_RET_ADDR_REG_ERROR 91
+#define DW_DLE_FDE_NULL 92
+#define DW_DLE_FDE_DBG_NULL 93
+#define DW_DLE_CIE_NULL 94
+#define DW_DLE_CIE_DBG_NULL 95
+#define DW_DLE_FRAME_TABLE_COL_BAD 96
+#define DW_DLE_PC_NOT_IN_FDE_RANGE 97
+#define DW_DLE_CIE_INSTR_EXEC_ERROR 98
+#define DW_DLE_FRAME_INSTR_EXEC_ERROR 99
+#define DW_DLE_FDE_PTR_NULL 100
+#define DW_DLE_RET_OP_LIST_NULL 101
+#define DW_DLE_LINE_CONTEXT_NULL 102
+#define DW_DLE_DBG_NO_CU_CONTEXT 103
+#define DW_DLE_DIE_NO_CU_CONTEXT 104
+#define DW_DLE_FIRST_DIE_NOT_CU 105
+#define DW_DLE_NEXT_DIE_PTR_NULL 106
+#define DW_DLE_DEBUG_FRAME_DUPLICATE 107
+#define DW_DLE_DEBUG_FRAME_NULL 108
+#define DW_DLE_ABBREV_DECODE_ERROR 109
+#define DW_DLE_DWARF_ABBREV_NULL 110
+#define DW_DLE_ATTR_NULL 111
+#define DW_DLE_DIE_BAD 112
+#define DW_DLE_DIE_ABBREV_BAD 113
+#define DW_DLE_ATTR_FORM_BAD 114
+#define DW_DLE_ATTR_NO_CU_CONTEXT 115
+#define DW_DLE_ATTR_FORM_SIZE_BAD 116
+#define DW_DLE_ATTR_DBG_NULL 117
+#define DW_DLE_BAD_REF_FORM 118
+#define DW_DLE_ATTR_FORM_OFFSET_BAD 119
+#define DW_DLE_LINE_OFFSET_BAD 120
+#define DW_DLE_DEBUG_STR_OFFSET_BAD 121
+#define DW_DLE_STRING_PTR_NULL 122
+#define DW_DLE_PUBNAMES_VERSION_ERROR 123
+#define DW_DLE_PUBNAMES_LENGTH_BAD 124
+#define DW_DLE_GLOBAL_NULL 125
+#define DW_DLE_GLOBAL_CONTEXT_NULL 126
+#define DW_DLE_DIR_INDEX_BAD 127
+#define DW_DLE_LOC_EXPR_BAD 128
+#define DW_DLE_DIE_LOC_EXPR_BAD 129
+#define DW_DLE_ADDR_ALLOC 130
+#define DW_DLE_OFFSET_BAD 131
+#define DW_DLE_MAKE_CU_CONTEXT_FAIL 132
+#define DW_DLE_REL_ALLOC 133
+#define DW_DLE_ARANGE_OFFSET_BAD 134
+#define DW_DLE_SEGMENT_SIZE_BAD 135
+#define DW_DLE_ARANGE_LENGTH_BAD 136
+#define DW_DLE_ARANGE_DECODE_ERROR 137
+#define DW_DLE_ARANGES_NULL 138
+#define DW_DLE_ARANGE_NULL 139
+#define DW_DLE_NO_FILE_NAME 140
+#define DW_DLE_NO_COMP_DIR 141
+#define DW_DLE_CU_ADDRESS_SIZE_BAD 142
+#define DW_DLE_INPUT_ATTR_BAD 143
+#define DW_DLE_EXPR_NULL 144
+#define DW_DLE_BAD_EXPR_OPCODE 145
+#define DW_DLE_EXPR_LENGTH_BAD 146
+#define DW_DLE_MULTIPLE_RELOC_IN_EXPR 147
+#define DW_DLE_ELF_GETIDENT_ERROR 148
+#define DW_DLE_NO_AT_MIPS_FDE 149
+#define DW_DLE_NO_CIE_FOR_FDE 150
+#define DW_DLE_DIE_ABBREV_LIST_NULL 151
+#define DW_DLE_DEBUG_FUNCNAMES_DUPLICATE 152
+#define DW_DLE_DEBUG_FUNCNAMES_NULL 153
+#define DW_DLE_DEBUG_FUNCNAMES_VERSION_ERROR 154
+#define DW_DLE_DEBUG_FUNCNAMES_LENGTH_BAD 155
+#define DW_DLE_FUNC_NULL 156
+#define DW_DLE_FUNC_CONTEXT_NULL 157
+#define DW_DLE_DEBUG_TYPENAMES_DUPLICATE 158
+#define DW_DLE_DEBUG_TYPENAMES_NULL 159
+#define DW_DLE_DEBUG_TYPENAMES_VERSION_ERROR 160
+#define DW_DLE_DEBUG_TYPENAMES_LENGTH_BAD 161
+#define DW_DLE_TYPE_NULL 162
+#define DW_DLE_TYPE_CONTEXT_NULL 163
+#define DW_DLE_DEBUG_VARNAMES_DUPLICATE 164
+#define DW_DLE_DEBUG_VARNAMES_NULL 165
+#define DW_DLE_DEBUG_VARNAMES_VERSION_ERROR 166
+#define DW_DLE_DEBUG_VARNAMES_LENGTH_BAD 167
+#define DW_DLE_VAR_NULL 168
+#define DW_DLE_VAR_CONTEXT_NULL 169
+#define DW_DLE_DEBUG_WEAKNAMES_DUPLICATE 170
+#define DW_DLE_DEBUG_WEAKNAMES_NULL 171
+#define DW_DLE_DEBUG_WEAKNAMES_VERSION_ERROR 172
+#define DW_DLE_DEBUG_WEAKNAMES_LENGTH_BAD 173
+#define DW_DLE_WEAK_NULL 174
+#define DW_DLE_WEAK_CONTEXT_NULL 175
+#define DW_DLE_LOCDESC_COUNT_WRONG 176
+#define DW_DLE_MACINFO_STRING_NULL 177
+#define DW_DLE_MACINFO_STRING_EMPTY 178
+#define DW_DLE_MACINFO_INTERNAL_ERROR_SPACE 179
+#define DW_DLE_MACINFO_MALLOC_FAIL 180
+#define DW_DLE_DEBUGMACINFO_ERROR 181
+#define DW_DLE_DEBUG_MACRO_LENGTH_BAD 182
+#define DW_DLE_DEBUG_MACRO_MAX_BAD 183
+#define DW_DLE_DEBUG_MACRO_INTERNAL_ERR 184
+#define DW_DLE_DEBUG_MACRO_MALLOC_SPACE 185
+#define DW_DLE_DEBUG_MACRO_INCONSISTENT 186
+#define DW_DLE_DF_NO_CIE_AUGMENTATION 187
+#define DW_DLE_DF_REG_NUM_TOO_HIGH 188
+#define DW_DLE_DF_MAKE_INSTR_NO_INIT 189
+#define DW_DLE_DF_NEW_LOC_LESS_OLD_LOC 190
+#define DW_DLE_DF_POP_EMPTY_STACK 191
+#define DW_DLE_DF_ALLOC_FAIL 192
+#define DW_DLE_DF_FRAME_DECODING_ERROR 193
+#define DW_DLE_DEBUG_LOC_SECTION_SHORT 194
+#define DW_DLE_FRAME_AUGMENTATION_UNKNOWN 195
+#define DW_DLE_PUBTYPE_CONTEXT 196 /* Unused. */
+#define DW_DLE_DEBUG_PUBTYPES_LENGTH_BAD 197
+#define DW_DLE_DEBUG_PUBTYPES_VERSION_ERROR 198
+#define DW_DLE_DEBUG_PUBTYPES_DUPLICATE 199
+#define DW_DLE_FRAME_CIE_DECODE_ERROR 200
+#define DW_DLE_FRAME_REGISTER_UNREPRESENTABLE 201
+#define DW_DLE_FRAME_REGISTER_COUNT_MISMATCH 202
+#define DW_DLE_LINK_LOOP 203
+#define DW_DLE_STRP_OFFSET_BAD 204
+#define DW_DLE_DEBUG_RANGES_DUPLICATE 205
+#define DW_DLE_DEBUG_RANGES_OFFSET_BAD 206
+#define DW_DLE_DEBUG_RANGES_MISSING_END 207
+#define DW_DLE_DEBUG_RANGES_OUT_OF_MEM 208
+#define DW_DLE_DEBUG_SYMTAB_ERR 209
+#define DW_DLE_DEBUG_STRTAB_ERR 210
+#define DW_DLE_RELOC_MISMATCH_INDEX 211
+#define DW_DLE_RELOC_MISMATCH_RELOC_INDEX 212
+#define DW_DLE_RELOC_MISMATCH_STRTAB_INDEX 213
+#define DW_DLE_RELOC_SECTION_MISMATCH 214
+#define DW_DLE_RELOC_SECTION_MISSING_INDEX 215
+#define DW_DLE_RELOC_SECTION_LENGTH_ODD 216
+#define DW_DLE_RELOC_SECTION_PTR_NULL 217
+#define DW_DLE_RELOC_SECTION_MALLOC_FAIL 218
+#define DW_DLE_NO_ELF64_SUPPORT 219
+#define DW_DLE_MISSING_ELF64_SUPPORT 220
+#define DW_DLE_ORPHAN_FDE 221
+#define DW_DLE_DUPLICATE_INST_BLOCK 222
+#define DW_DLE_BAD_REF_SIG8_FORM 223
+#define DW_DLE_ATTR_EXPRLOC_FORM_BAD 224
+#define DW_DLE_FORM_SEC_OFFSET_LENGTH_BAD 225
+#define DW_DLE_NOT_REF_FORM 226
+#define DW_DLE_DEBUG_FRAME_LENGTH_NOT_MULTIPLE 227
+
+
+
+ /* DW_DLE_LAST MUST EQUAL LAST ERROR NUMBER */
+#define DW_DLE_LAST 227
+#define DW_DLE_LO_USER 0x10000
+
+ /* Taken as meaning 'undefined value', this is not
+ a column or register number.
+ Only present at libdwarf runtime. Never on disk.
+ DW_FRAME_* Values present on disk are in dwarf.h
+ */
+#define DW_FRAME_UNDEFINED_VAL 1034
+
+ /* Taken as meaning 'same value' as caller had, not a column
+ or register number
+ Only present at libdwarf runtime. Never on disk.
+ DW_FRAME_* Values present on disk are in dwarf.h
+ */
+#define DW_FRAME_SAME_VAL 1035
+
+
+
+/* error return values
+*/
+#define DW_DLV_BADADDR (~(Dwarf_Addr)0)
+ /* for functions returning target address */
+
+#define DW_DLV_NOCOUNT ((Dwarf_Signed)-1)
+ /* for functions returning count */
+
+#define DW_DLV_BADOFFSET (~(Dwarf_Off)0)
+ /* for functions returning offset */
+
+/* standard return values for functions */
+#define DW_DLV_NO_ENTRY -1
+#define DW_DLV_OK 0
+#define DW_DLV_ERROR 1
+
+/* Special values for offset_into_exception_table field of dwarf fde's. */
+/* The following value indicates that there is no Exception table offset
+ associated with a dwarf frame. */
+#define DW_DLX_NO_EH_OFFSET (-1LL)
+/* The following value indicates that the producer was unable to analyse the
+ source file to generate Exception tables for this function. */
+#define DW_DLX_EH_OFFSET_UNAVAILABLE (-2LL)
+
+
+/*===========================================================================*/
+/* Dwarf consumer interface initialization and termination operations */
+
+/* Initialization based on Unix open fd (using libelf internally). */
+int dwarf_init(int /*fd*/,
+ Dwarf_Unsigned /*access*/,
+ Dwarf_Handler /*errhand*/,
+ Dwarf_Ptr /*errarg*/,
+ Dwarf_Debug* /*dbg*/,
+ Dwarf_Error* /*error*/);
+
+/* Initialization based on libelf/sgi-fastlibelf open pointer. */
+int dwarf_elf_init(dwarf_elf_handle /*elf*/,
+ Dwarf_Unsigned /*access*/,
+ Dwarf_Handler /*errhand*/,
+ Dwarf_Ptr /*errarg*/,
+ Dwarf_Debug* /*dbg*/,
+ Dwarf_Error* /*error*/);
+
+/* Undocumented function for memory allocator. */
+void dwarf_print_memory_stats(Dwarf_Debug /*dbg*/);
+
+int dwarf_get_elf(Dwarf_Debug /*dbg*/,
+ dwarf_elf_handle* /*return_elfptr*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_finish(Dwarf_Debug /*dbg*/, Dwarf_Error* /*error*/);
+
+
+int dwarf_object_init(Dwarf_Obj_Access_Interface* /* obj */,
+ Dwarf_Handler /* errhand */,
+ Dwarf_Ptr /* errarg */,
+ Dwarf_Debug* /* dbg */,
+ Dwarf_Error* /* error */);
+
+int dwarf_object_finish(Dwarf_Debug /* dbg */,
+ Dwarf_Error* /* error */);
+
+/* die traversal operations */
+int dwarf_next_cu_header_b(Dwarf_Debug /*dbg*/,
+ Dwarf_Unsigned* /*cu_header_length*/,
+ Dwarf_Half* /*version_stamp*/,
+ Dwarf_Off* /*abbrev_offset*/,
+ Dwarf_Half* /*address_size*/,
+ Dwarf_Half* /*length_size*/,
+ Dwarf_Half* /*extension_size*/,
+ Dwarf_Unsigned* /*next_cu_header_offset*/,
+ Dwarf_Error* /*error*/);
+/* The following is now obsolete, though supported. November 2009. */
+int dwarf_next_cu_header(Dwarf_Debug /*dbg*/,
+ Dwarf_Unsigned* /*cu_header_length*/,
+ Dwarf_Half* /*version_stamp*/,
+ Dwarf_Off* /*abbrev_offset*/,
+ Dwarf_Half* /*address_size*/,
+ Dwarf_Unsigned* /*next_cu_header_offset*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_siblingof(Dwarf_Debug /*dbg*/,
+ Dwarf_Die /*die*/,
+ Dwarf_Die* /*return_siblingdie*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_child(Dwarf_Die /*die*/,
+ Dwarf_Die* /*return_childdie*/,
+ Dwarf_Error* /*error*/);
+
+/* Finding die given global (not CU-relative) offset */
+int dwarf_offdie(Dwarf_Debug /*dbg*/,
+ Dwarf_Off /*offset*/,
+ Dwarf_Die* /*return_die*/,
+ Dwarf_Error* /*error*/);
+
+/* Higher level functions (Unimplemented) */
+int dwarf_pcfile(Dwarf_Debug /*dbg*/,
+ Dwarf_Addr /*pc*/,
+ Dwarf_Die* /*return_die*/,
+ Dwarf_Error* /*error*/);
+
+/* Unimplemented */
+int dwarf_pcsubr(Dwarf_Debug /*dbg*/,
+ Dwarf_Addr /*pc*/,
+ Dwarf_Die* /*return_die*/,
+ Dwarf_Error* /*error*/);
+
+/* Unimplemented */
+int dwarf_pcscope(Dwarf_Debug /*dbg*/,
+ Dwarf_Addr /*pc*/,
+ Dwarf_Die* /*return_die*/,
+ Dwarf_Error* /*error*/);
+
+/* operations on DIEs */
+int dwarf_tag(Dwarf_Die /*die*/,
+ Dwarf_Half* /*return_tag*/,
+ Dwarf_Error* /*error*/);
+
+/* utility? */
+/* dwarf_dieoffset returns the global debug_info
+ section offset, not the CU relative offset. */
+int dwarf_dieoffset(Dwarf_Die /*die*/,
+ Dwarf_Off* /*return_offset*/,
+ Dwarf_Error* /*error*/);
+
+/* dwarf_CU_dieoffset_given_die returns
+ the global debug_info section offset of the CU die
+ that is the CU containing the given_die
+ (the passed in DIE can be any DIE).
+ This information makes it possible for a consumer to
+ find and print CU context information for any die.
+ See also dwarf_get_cu_die_offset_given_cu_header_offset(). */
+int dwarf_CU_dieoffset_given_die(Dwarf_Die /*given_die*/,
+ Dwarf_Off* /*return_offset*/,
+ Dwarf_Error* /*error*/);
+
+/* dwarf_die_CU_offset returns the CU relative offset
+ not the global debug_info section offset, given
+ any DIE in the CU. See also dwarf_CU_dieoffset_given_die().
+ */
+int dwarf_die_CU_offset(Dwarf_Die /*die*/,
+ Dwarf_Off* /*return_offset*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_die_CU_offset_range(Dwarf_Die /*die*/,
+ Dwarf_Off* /*return_CU_header_offset*/,
+ Dwarf_Off* /*return_CU_length_bytes*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_attr (Dwarf_Die /*die*/,
+ Dwarf_Half /*attr*/,
+ Dwarf_Attribute * /*returned_attr*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_diename(Dwarf_Die /*die*/,
+ char ** /*diename*/,
+ Dwarf_Error* /*error*/);
+
+/* Returns the abbrev code of the die. Cannot fail. */
+int dwarf_die_abbrev_code(Dwarf_Die /*die */);
+
+
+/* convenience functions, alternative to using dwarf_attrlist() */
+int dwarf_hasattr(Dwarf_Die /*die*/,
+ Dwarf_Half /*attr*/,
+ Dwarf_Bool * /*returned_bool*/,
+ Dwarf_Error* /*error*/);
+
+/* dwarf_loclist_n preferred over dwarf_loclist */
+int dwarf_loclist_n(Dwarf_Attribute /*attr*/,
+ Dwarf_Locdesc*** /*llbuf*/,
+ Dwarf_Signed * /*locCount*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_loclist(Dwarf_Attribute /*attr*/, /* inflexible! */
+ Dwarf_Locdesc** /*llbuf*/,
+ Dwarf_Signed * /*locCount*/,
+ Dwarf_Error* /*error*/);
+
+/* Extracts a dwarf expression from an expression byte stream.
+ Useful to get expressions from DW_CFA_def_cfa_expression
+ DW_CFA_expression DW_CFA_val_expression expression bytes.
+ 27 April 2009: dwarf_loclist_from_expr() interface with
+ no addr_size is obsolete but supported,
+ use dwarf_loclist_from_expr_a() instead.
+*/
+int dwarf_loclist_from_expr(Dwarf_Debug dbg,
+ Dwarf_Ptr expression_in,
+ Dwarf_Unsigned expression_length,
+ Dwarf_Locdesc ** llbuf,
+ Dwarf_Signed * listlen, Dwarf_Error * error);
+
+/* dwarf_loclist_from_expr_a() new 27 Apr 2009: added addr_size argument. */
+int dwarf_loclist_from_expr_a(Dwarf_Debug dbg,
+ Dwarf_Ptr expression_in,
+ Dwarf_Unsigned expression_length,
+ Dwarf_Half addr_size,
+ Dwarf_Locdesc ** llbuf,
+ Dwarf_Signed * listlen, Dwarf_Error * error);
+
+/* Unimplemented */
+int dwarf_stringlen(Dwarf_Die /*die*/,
+ Dwarf_Locdesc ** /*returned_locdesc*/,
+ Dwarf_Error* /*error*/);
+
+/* Unimplemented */
+int dwarf_subscrcnt(Dwarf_Die /*die*/,
+ Dwarf_Signed * /*returned_count*/,
+ Dwarf_Error* /*error*/);
+
+/* Unimplemented */
+int dwarf_nthsubscr(Dwarf_Die /*die*/,
+ Dwarf_Unsigned /*ssndx*/,
+ Dwarf_Die * /*returned_die*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_lowpc(Dwarf_Die /*die*/,
+ Dwarf_Addr * /*returned_addr*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_highpc(Dwarf_Die /*die*/,
+ Dwarf_Addr * /*returned_addr*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_bytesize(Dwarf_Die /*die*/,
+ Dwarf_Unsigned * /*returned_size*/,
+ Dwarf_Error* /*error*/);
+
+/* Unimplemented */
+int dwarf_isbitfield(Dwarf_Die /*die*/,
+ Dwarf_Bool * /*returned_bool*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_bitsize(Dwarf_Die /*die*/,
+ Dwarf_Unsigned * /*returned_size*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_bitoffset(Dwarf_Die /*die*/,
+ Dwarf_Unsigned * /*returned_offset*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_srclang(Dwarf_Die /*die*/,
+ Dwarf_Unsigned * /*returned_lang*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_arrayorder(Dwarf_Die /*die*/,
+ Dwarf_Unsigned * /*returned_order*/,
+ Dwarf_Error* /*error*/);
+
+/* end of convenience function list */
+
+/* this is the main interface to attributes of a DIE */
+int dwarf_attrlist(Dwarf_Die /*die*/,
+ Dwarf_Attribute** /*attrbuf*/,
+ Dwarf_Signed * /*attrcount*/,
+ Dwarf_Error* /*error*/);
+
+/* query operations for attributes */
+int dwarf_hasform(Dwarf_Attribute /*attr*/,
+ Dwarf_Half /*form*/,
+ Dwarf_Bool * /*returned_bool*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_whatform(Dwarf_Attribute /*attr*/,
+ Dwarf_Half * /*returned_form*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_whatform_direct(Dwarf_Attribute /*attr*/,
+ Dwarf_Half * /*returned_form*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_whatattr(Dwarf_Attribute /*attr*/,
+ Dwarf_Half * /*returned_attr_num*/,
+ Dwarf_Error* /*error*/);
+
+/*
+ The following are concerned with the Primary Interface: getting
+ the actual data values. One function per 'kind' of FORM.
+*/
+/* dwarf_formref returns, thru return_offset, a CU-relative offset
+ and does not allow DW_FORM_ref_addr*/
+int dwarf_formref(Dwarf_Attribute /*attr*/,
+ Dwarf_Off* /*return_offset*/,
+ Dwarf_Error* /*error*/);
+/* dwarf_global_formref returns, thru return_offset,
+ a debug_info-relative offset and does allow all reference forms*/
+int dwarf_global_formref(Dwarf_Attribute /*attr*/,
+ Dwarf_Off* /*return_offset*/,
+ Dwarf_Error* /*error*/);
+
+/* dwarf_formsig8 returns in the caller-provided 8 byte area
+ the 8 bytes of a DW_FORM_ref_sig8. Not a string. */
+int dwarf_formsig8(Dwarf_Attribute /*attr*/,
+ Dwarf_Sig8 * /*returned sig bytes*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_formaddr(Dwarf_Attribute /*attr*/,
+ Dwarf_Addr * /*returned_addr*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_formflag(Dwarf_Attribute /*attr*/,
+ Dwarf_Bool * /*returned_bool*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_formudata(Dwarf_Attribute /*attr*/,
+ Dwarf_Unsigned * /*returned_val*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_formsdata(Dwarf_Attribute /*attr*/,
+ Dwarf_Signed * /*returned_val*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_formblock(Dwarf_Attribute /*attr*/,
+ Dwarf_Block ** /*returned_block*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_formstring(Dwarf_Attribute /*attr*/,
+ char ** /*returned_string*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_formexprloc(Dwarf_Attribute /*attr*/,
+ Dwarf_Unsigned * /*return_exprlen*/,
+ Dwarf_Ptr * /*block_ptr*/,
+ Dwarf_Error * /*error*/);
+
+
+/* end attribute query operations. */
+
+/* line number operations */
+/* dwarf_srclines is the normal interface */
+int dwarf_srclines(Dwarf_Die /*die*/,
+ Dwarf_Line** /*linebuf*/,
+ Dwarf_Signed * /*linecount*/,
+ Dwarf_Error* /*error*/);
+
+/* dwarf_srclines_dealloc, created July 2005, is the new
+ method for deallocating what dwarf_srclines returns.
+ More complete free than using dwarf_dealloc directly. */
+void dwarf_srclines_dealloc(Dwarf_Debug /*dbg*/,
+ Dwarf_Line* /*linebuf*/,
+ Dwarf_Signed /*count */);
+
+
+int dwarf_srcfiles(Dwarf_Die /*die*/,
+ char*** /*srcfiles*/,
+ Dwarf_Signed * /*filecount*/,
+ Dwarf_Error* /*error*/);
+
+/* Unimplemented. */
+int dwarf_dieline(Dwarf_Die /*die*/,
+ Dwarf_Line * /*returned_line*/,
+ Dwarf_Error * /*error*/);
+
+int dwarf_linebeginstatement(Dwarf_Line /*line*/,
+ Dwarf_Bool * /*returned_bool*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_lineendsequence(Dwarf_Line /*line*/,
+ Dwarf_Bool * /*returned_bool*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_lineno(Dwarf_Line /*line*/,
+ Dwarf_Unsigned * /*returned_lineno*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_line_srcfileno(Dwarf_Line /*line*/,
+ Dwarf_Unsigned * /*ret_fileno*/,
+ Dwarf_Error * /*error*/);
+
+int dwarf_lineaddr(Dwarf_Line /*line*/,
+ Dwarf_Addr * /*returned_addr*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_lineoff(Dwarf_Line /*line*/,
+ Dwarf_Signed * /*returned_lineoffset*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_linesrc(Dwarf_Line /*line*/,
+ char ** /*returned_name*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_lineblock(Dwarf_Line /*line*/,
+ Dwarf_Bool * /*returned_bool*/,
+ Dwarf_Error* /*error*/);
+
+/* tertiary interface to line info */
+/* Unimplemented */
+int dwarf_pclines(Dwarf_Debug /*dbg*/,
+ Dwarf_Addr /*pc*/,
+ Dwarf_Line** /*linebuf*/,
+ Dwarf_Signed * /*linecount*/,
+ Dwarf_Signed /*slide*/,
+ Dwarf_Error* /*error*/);
+/* end line number operations */
+
+/* global name space operations (.debug_pubnames access) */
+int dwarf_get_globals(Dwarf_Debug /*dbg*/,
+ Dwarf_Global** /*globals*/,
+ Dwarf_Signed * /*number_of_globals*/,
+ Dwarf_Error* /*error*/);
+void dwarf_globals_dealloc(Dwarf_Debug /*dbg*/,
+ Dwarf_Global* /*globals*/,
+ Dwarf_Signed /*number_of_globals*/);
+
+int dwarf_globname(Dwarf_Global /*glob*/,
+ char ** /*returned_name*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_global_die_offset(Dwarf_Global /*global*/,
+ Dwarf_Off* /*return_offset*/,
+ Dwarf_Error * /*error*/);
+
+/* This returns the CU die global offset if one knows the
+ CU header global offset.
+ See also dwarf_CU_dieoffset_given_die(). */
+int dwarf_get_cu_die_offset_given_cu_header_offset(
+ Dwarf_Debug /*dbg*/,
+ Dwarf_Off /*in_cu_header_offset*/,
+ Dwarf_Off * /*out_cu_die_offset*/,
+ Dwarf_Error * /*err*/);
+#ifdef __sgi /* pragma is sgi MIPS only */
+#pragma optional dwarf_get_cu_die_offset_given_cu_header_offset
+#endif
+
+int dwarf_global_cu_offset(Dwarf_Global /*global*/,
+ Dwarf_Off* /*return_offset*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_global_name_offsets(Dwarf_Global /*global*/,
+ char ** /*returned_name*/,
+ Dwarf_Off* /*die_offset*/,
+ Dwarf_Off* /*cu_offset*/,
+ Dwarf_Error* /*error*/);
+
+/* Static function name operations. */
+int dwarf_get_funcs(Dwarf_Debug /*dbg*/,
+ Dwarf_Func** /*funcs*/,
+ Dwarf_Signed * /*number_of_funcs*/,
+ Dwarf_Error* /*error*/);
+void dwarf_funcs_dealloc(Dwarf_Debug /*dbg*/,
+ Dwarf_Func* /*funcs*/,
+ Dwarf_Signed /*number_of_funcs*/);
+
+int dwarf_funcname(Dwarf_Func /*func*/,
+ char ** /*returned_name*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_func_die_offset(Dwarf_Func /*func*/,
+ Dwarf_Off* /*return_offset*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_func_cu_offset(Dwarf_Func /*func*/,
+ Dwarf_Off* /*return_offset*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_func_name_offsets(Dwarf_Func /*func*/,
+ char ** /*returned_name*/,
+ Dwarf_Off* /*die_offset*/,
+ Dwarf_Off* /*cu_offset*/,
+ Dwarf_Error* /*error*/);
+
+/* User-defined type name operations, SGI IRIX .debug_typenames section.
+ Same content as DWARF3 .debug_pubtypes, but defined years before
+ .debug_pubtypes was defined. SGI IRIX only. */
+int dwarf_get_types(Dwarf_Debug /*dbg*/,
+ Dwarf_Type** /*types*/,
+ Dwarf_Signed * /*number_of_types*/,
+ Dwarf_Error* /*error*/);
+void dwarf_types_dealloc(Dwarf_Debug /*dbg*/,
+ Dwarf_Type* /*types*/,
+ Dwarf_Signed /*number_of_types*/);
+
+
+int dwarf_typename(Dwarf_Type /*type*/,
+ char ** /*returned_name*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_type_die_offset(Dwarf_Type /*type*/,
+ Dwarf_Off* /*return_offset*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_type_cu_offset(Dwarf_Type /*type*/,
+ Dwarf_Off* /*return_offset*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_type_name_offsets(Dwarf_Type /*type*/,
+ char ** /*returned_name*/,
+ Dwarf_Off* /*die_offset*/,
+ Dwarf_Off* /*cu_offset*/,
+ Dwarf_Error* /*error*/);
+
+/* User-defined type name operations, DWARF3 .debug_pubtypes section.
+*/
+int dwarf_get_pubtypes(Dwarf_Debug /*dbg*/,
+ Dwarf_Type** /*types*/,
+ Dwarf_Signed * /*number_of_types*/,
+ Dwarf_Error* /*error*/);
+void dwarf_pubtypes_dealloc(Dwarf_Debug /*dbg*/,
+ Dwarf_Type* /*pubtypes*/,
+ Dwarf_Signed /*number_of_pubtypes*/);
+
+
+int dwarf_pubtypename(Dwarf_Type /*type*/,
+ char ** /*returned_name*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_pubtype_die_offset(Dwarf_Type /*type*/,
+ Dwarf_Off* /*return_offset*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_pubtype_cu_offset(Dwarf_Type /*type*/,
+ Dwarf_Off* /*return_offset*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_pubtype_name_offsets(Dwarf_Type /*type*/,
+ char ** /*returned_name*/,
+ Dwarf_Off* /*die_offset*/,
+ Dwarf_Off* /*cu_offset*/,
+ Dwarf_Error* /*error*/);
+
+/* File-scope static variable name operations. */
+int dwarf_get_vars(Dwarf_Debug /*dbg*/,
+ Dwarf_Var** /*vars*/,
+ Dwarf_Signed * /*number_of_vars*/,
+ Dwarf_Error* /*error*/);
+void dwarf_vars_dealloc(Dwarf_Debug /*dbg*/,
+ Dwarf_Var* /*vars*/,
+ Dwarf_Signed /*number_of_vars*/);
+
+
+int dwarf_varname(Dwarf_Var /*var*/,
+ char ** /*returned_name*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_var_die_offset(Dwarf_Var /*var*/,
+ Dwarf_Off* /*return_offset*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_var_cu_offset(Dwarf_Var /*var*/,
+ Dwarf_Off* /*return_offset*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_var_name_offsets(Dwarf_Var /*var*/,
+ char ** /*returned_name*/,
+ Dwarf_Off* /*die_offset*/,
+ Dwarf_Off* /*cu_offset*/,
+ Dwarf_Error* /*error*/);
+
+/* weak name operations. */
+int dwarf_get_weaks(Dwarf_Debug /*dbg*/,
+ Dwarf_Weak** /*weaks*/,
+ Dwarf_Signed * /*number_of_weaks*/,
+ Dwarf_Error* /*error*/);
+void dwarf_weaks_dealloc(Dwarf_Debug /*dbg*/,
+ Dwarf_Weak* /*weaks*/,
+ Dwarf_Signed /*number_of_weaks*/);
+
+
+int dwarf_weakname(Dwarf_Weak /*weak*/,
+ char ** /*returned_name*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_weak_die_offset(Dwarf_Weak /*weak*/,
+ Dwarf_Off* /*return_offset*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_weak_cu_offset(Dwarf_Weak /*weak*/,
+ Dwarf_Off* /*return_offset*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_weak_name_offsets(Dwarf_Weak /*weak*/,
+ char ** /*returned_name*/,
+ Dwarf_Off* /*die_offset*/,
+ Dwarf_Off* /*cu_offset*/,
+ Dwarf_Error* /*error*/);
+
+/* location list section operation. (.debug_loc access) */
+int dwarf_get_loclist_entry(Dwarf_Debug /*dbg*/,
+ Dwarf_Unsigned /*offset*/,
+ Dwarf_Addr* /*hipc*/,
+ Dwarf_Addr* /*lopc*/,
+ Dwarf_Ptr* /*data*/,
+ Dwarf_Unsigned* /*entry_len*/,
+ Dwarf_Unsigned* /*next_entry*/,
+ Dwarf_Error* /*error*/);
+
+/* abbreviation section operations */
+int dwarf_get_abbrev(Dwarf_Debug /*dbg*/,
+ Dwarf_Unsigned /*offset*/,
+ Dwarf_Abbrev * /*returned_abbrev*/,
+ Dwarf_Unsigned* /*length*/,
+ Dwarf_Unsigned* /*attr_count*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_get_abbrev_tag(Dwarf_Abbrev /*abbrev*/,
+ Dwarf_Half* /*return_tag_number*/,
+ Dwarf_Error* /*error*/);
+int dwarf_get_abbrev_code(Dwarf_Abbrev /*abbrev*/,
+ Dwarf_Unsigned* /*return_code_number*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_get_abbrev_children_flag(Dwarf_Abbrev /*abbrev*/,
+ Dwarf_Signed* /*return_flag*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_get_abbrev_entry(Dwarf_Abbrev /*abbrev*/,
+ Dwarf_Signed /*index*/,
+ Dwarf_Half * /*returned_attr_num*/,
+ Dwarf_Signed* /*form*/,
+ Dwarf_Off* /*offset*/,
+ Dwarf_Error* /*error*/);
+
+/* consumer string section operation */
+int dwarf_get_str(Dwarf_Debug /*dbg*/,
+ Dwarf_Off /*offset*/,
+ char** /*string*/,
+ Dwarf_Signed * /*strlen_of_string*/,
+ Dwarf_Error* /*error*/);
+
+/* Consumer op on gnu .eh_frame info */
+int dwarf_get_fde_list_eh(
+ Dwarf_Debug /*dbg*/,
+ Dwarf_Cie** /*cie_data*/,
+ Dwarf_Signed* /*cie_element_count*/,
+ Dwarf_Fde** /*fde_data*/,
+ Dwarf_Signed* /*fde_element_count*/,
+ Dwarf_Error* /*error*/);
+
+
+/* consumer operations on frame info: .debug_frame */
+int dwarf_get_fde_list(Dwarf_Debug /*dbg*/,
+ Dwarf_Cie** /*cie_data*/,
+ Dwarf_Signed* /*cie_element_count*/,
+ Dwarf_Fde** /*fde_data*/,
+ Dwarf_Signed* /*fde_element_count*/,
+ Dwarf_Error* /*error*/);
+
+/* Release storage gotten by dwarf_get_fde_list_eh() or
+ dwarf_get_fde_list() */
+void dwarf_fde_cie_list_dealloc(Dwarf_Debug dbg,
+ Dwarf_Cie *cie_data,
+ Dwarf_Signed cie_element_count,
+ Dwarf_Fde *fde_data,
+ Dwarf_Signed fde_element_count);
+
+
+
+int dwarf_get_fde_range(Dwarf_Fde /*fde*/,
+ Dwarf_Addr* /*low_pc*/,
+ Dwarf_Unsigned* /*func_length*/,
+ Dwarf_Ptr* /*fde_bytes*/,
+ Dwarf_Unsigned* /*fde_byte_length*/,
+ Dwarf_Off* /*cie_offset*/,
+ Dwarf_Signed* /*cie_index*/,
+ Dwarf_Off* /*fde_offset*/,
+ Dwarf_Error* /*error*/);
+
+/* Useful for IRIX only: see dwarf_get_cie_augmentation_data()
+ dwarf_get_fde_augmentation_data() for GNU .eh_frame. */
+int dwarf_get_fde_exception_info(Dwarf_Fde /*fde*/,
+ Dwarf_Signed* /* offset_into_exception_tables */,
+ Dwarf_Error* /*error*/);
+
+
+int dwarf_get_cie_of_fde(Dwarf_Fde /*fde*/,
+ Dwarf_Cie * /*cie_returned*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_get_cie_info(Dwarf_Cie /*cie*/,
+ Dwarf_Unsigned * /*bytes_in_cie*/,
+ Dwarf_Small* /*version*/,
+ char ** /*augmenter*/,
+ Dwarf_Unsigned* /*code_alignment_factor*/,
+ Dwarf_Signed* /*data_alignment_factor*/,
+ Dwarf_Half* /*return_address_register_rule*/,
+ Dwarf_Ptr* /*initial_instructions*/,
+ Dwarf_Unsigned* /*initial_instructions_length*/,
+ Dwarf_Error* /*error*/);
+
+/* dwarf_get_cie_index new September 2009. */
+int dwarf_get_cie_index(
+ Dwarf_Cie /*cie*/,
+ Dwarf_Signed* /*index*/,
+ Dwarf_Error* /*error*/ );
+
+
+int dwarf_get_fde_instr_bytes(Dwarf_Fde /*fde*/,
+ Dwarf_Ptr * /*outinstrs*/, Dwarf_Unsigned * /*outlen*/,
+ Dwarf_Error * /*error*/);
+
+int dwarf_get_fde_info_for_all_regs(Dwarf_Fde /*fde*/,
+ Dwarf_Addr /*pc_requested*/,
+ Dwarf_Regtable* /*reg_table*/,
+ Dwarf_Addr* /*row_pc*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_get_fde_info_for_all_regs3(Dwarf_Fde /*fde*/,
+ Dwarf_Addr /*pc_requested*/,
+ Dwarf_Regtable3* /*reg_table*/,
+ Dwarf_Addr* /*row_pc*/,
+ Dwarf_Error* /*error*/);
+
+/* In this older interface DW_FRAME_CFA_COL is a meaningful
+ column (which does not work well with DWARF3 or
+ non-MIPS architectures). */
+int dwarf_get_fde_info_for_reg(Dwarf_Fde /*fde*/,
+ Dwarf_Half /*table_column*/,
+ Dwarf_Addr /*pc_requested*/,
+ Dwarf_Signed* /*offset_relevant*/,
+ Dwarf_Signed* /*register*/,
+ Dwarf_Signed* /*offset*/,
+ Dwarf_Addr* /*row_pc*/,
+ Dwarf_Error* /*error*/);
+
+/* See discussion of dw_value_type, libdwarf.h.
+ Use of DW_FRAME_CFA_COL is not meaningful in this interface.
+ See dwarf_get_fde_info_for_cfa_reg3().
+*/
+/* dwarf_get_fde_info_for_reg3 is useful on a single column, but
+ it is inefficient to iterate across all table_columns using this
+ function. Instead call dwarf_get_fde_info_for_all_regs3() and index
+ into the table it fills in. */
+int dwarf_get_fde_info_for_reg3(Dwarf_Fde /*fde*/,
+ Dwarf_Half /*table_column*/,
+ Dwarf_Addr /*pc_requested*/,
+ Dwarf_Small * /*value_type*/,
+ Dwarf_Signed * /*offset_relevant*/,
+ Dwarf_Signed* /*register*/,
+ Dwarf_Signed* /*offset_or_block_len*/,
+ Dwarf_Ptr * /*block_ptr */,
+ Dwarf_Addr* /*row_pc_out*/,
+ Dwarf_Error* /*error*/);
+
+/* Use this to get the cfa. */
+int dwarf_get_fde_info_for_cfa_reg3(Dwarf_Fde /*fde*/,
+ Dwarf_Addr /*pc_requested*/,
+ Dwarf_Small * /*value_type*/,
+ Dwarf_Signed * /*offset_relevant*/,
+ Dwarf_Signed* /*register*/,
+ Dwarf_Signed* /*offset_or_block_len*/,
+ Dwarf_Ptr * /*block_ptr */,
+ Dwarf_Addr* /*row_pc_out*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_get_fde_for_die(Dwarf_Debug /*dbg*/,
+ Dwarf_Die /*subr_die */,
+ Dwarf_Fde * /*returned_fde*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_get_fde_n(Dwarf_Fde* /*fde_data*/,
+ Dwarf_Unsigned /*fde_index*/,
+ Dwarf_Fde * /*returned_fde*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_get_fde_at_pc(Dwarf_Fde* /*fde_data*/,
+ Dwarf_Addr /*pc_of_interest*/,
+ Dwarf_Fde * /*returned_fde*/,
+ Dwarf_Addr* /*lopc*/,
+ Dwarf_Addr* /*hipc*/,
+ Dwarf_Error* /*error*/);
+
+/* GNU .eh_frame augmentation information, raw form, see
+ Linux Standard Base Core Specification version 3.0 . */
+int dwarf_get_cie_augmentation_data(Dwarf_Cie /* cie*/,
+ Dwarf_Small ** /* augdata */,
+ Dwarf_Unsigned * /* augdata_len */,
+ Dwarf_Error* /*error*/);
+/* GNU .eh_frame augmentation information, raw form, see
+ Linux Standard Base Core Specification version 3.0 . */
+int dwarf_get_fde_augmentation_data(Dwarf_Fde /* fde*/,
+ Dwarf_Small ** /* augdata */,
+ Dwarf_Unsigned * /* augdata_len */,
+ Dwarf_Error* /*error*/);
+
+int dwarf_expand_frame_instructions(Dwarf_Cie /*cie*/,
+ Dwarf_Ptr /*instruction*/,
+ Dwarf_Unsigned /*i_length*/,
+ Dwarf_Frame_Op** /*returned_op_list*/,
+ Dwarf_Signed* /*op_count*/,
+ Dwarf_Error* /*error*/);
+
+/* Operations on .debug_aranges. */
+int dwarf_get_aranges(Dwarf_Debug /*dbg*/,
+ Dwarf_Arange** /*aranges*/,
+ Dwarf_Signed * /*arange_count*/,
+ Dwarf_Error* /*error*/);
+
+
+
+int dwarf_get_arange(
+ Dwarf_Arange* /*aranges*/,
+ Dwarf_Unsigned /*arange_count*/,
+ Dwarf_Addr /*address*/,
+ Dwarf_Arange * /*returned_arange*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_get_cu_die_offset(
+ Dwarf_Arange /*arange*/,
+ Dwarf_Off* /*return_offset*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_get_arange_cu_header_offset(
+ Dwarf_Arange /*arange*/,
+ Dwarf_Off* /*return_cu_header_offset*/,
+ Dwarf_Error* /*error*/);
+#ifdef __sgi /* pragma is sgi MIPS only */
+#pragma optional dwarf_get_arange_cu_header_offset
+#endif
+
+/* DWARF2,3 interface. No longer really adequate (it was never
+ right for segmented address spaces, please switch
+ to using dwarf_get_arange_info_b instead.
+ There is no effective difference between these
+ functions if the address space
+ of the target is not segmented. */
+int dwarf_get_arange_info(
+ Dwarf_Arange /*arange*/,
+ Dwarf_Addr* /*start*/,
+ Dwarf_Unsigned* /*length*/,
+ Dwarf_Off* /*cu_die_offset*/,
+ Dwarf_Error* /*error*/ );
+
+/* New for DWARF4, entries may have segment information.
+ *segment is only meaningful if *segment_entry_size is non-zero. */
+int dwarf_get_arange_info_b(
+ Dwarf_Arange /*arange*/,
+ Dwarf_Unsigned* /*segment*/,
+ Dwarf_Unsigned* /*segment_entry_size*/,
+ Dwarf_Addr * /*start*/,
+ Dwarf_Unsigned* /*length*/,
+ Dwarf_Off * /*cu_die_offset*/,
+ Dwarf_Error * /*error*/ );
+
+
+/* consumer .debug_macinfo information interface.
+*/
+struct Dwarf_Macro_Details_s {
+ Dwarf_Off dmd_offset; /* offset, in the section,
+ of this macro info */
+ Dwarf_Small dmd_type; /* the type, DW_MACINFO_define etc*/
+ Dwarf_Signed dmd_lineno; /* the source line number where
+ applicable and vend_def # if
+ vendor_extension op
+ */
+
+ Dwarf_Signed dmd_fileindex;/* the source file index:
+ applies to define undef start_file
+ */
+ char * dmd_macro; /* macro name (with value for defineop)
+ string from vendor ext
+ */
+};
+
+/* dwarf_print_lines is for use by dwarfdump: it prints
+ line info to stdout.
+ The _dwarf name is obsolete. Use dwarf_ instead.
+ Added extra argnument 2/2009 for better checking.
+*/
+int _dwarf_print_lines(Dwarf_Die /*cu_die*/,Dwarf_Error * /*error*/);
+int dwarf_print_lines(Dwarf_Die /*cu_die*/,Dwarf_Error * /*error*/,
+ int * /*error_count_out */);
+
+/* dwarf_check_lineheader lets dwarfdump get detailed messages
+ about some compiler errors we detect.
+ We return the count of detected errors throught the
+ pointer.
+*/
+void dwarf_check_lineheader(Dwarf_Die /*cu_die*/,int *errcount_out);
+
+/* dwarf_ld_sort_lines helps SGI IRIX ld
+ rearrange lines in .debug_line in a .o created with a text
+ section per function.
+ -OPT:procedure_reorder=ON
+ where ld-cord (cord(1)ing by ld,
+ not by cord(1)) may have changed the function order.
+ The _dwarf name is obsolete. Use dwarf_ instead.
+*/
+int _dwarf_ld_sort_lines(
+ void * /*orig_buffer*/,
+ unsigned long /* buffer_len*/,
+ int /*is_64_bit*/,
+ int * /*any_change*/,
+ int * /*err_code*/);
+int dwarf_ld_sort_lines(
+ void * /*orig_buffer*/,
+ unsigned long /*buffer_len*/,
+ int /*is_64_bit*/,
+ int * /*any_change*/,
+ int * /*err_code*/);
+
+/* Used by dwarfdump -v to print fde offsets from debugging
+ info.
+ The _dwarf name is obsolete. Use dwarf_ instead.
+*/
+int _dwarf_fde_section_offset(Dwarf_Debug dbg,
+ Dwarf_Fde /*in_fde*/,
+ Dwarf_Off * /*fde_off*/,
+ Dwarf_Off * /*cie_off*/,
+ Dwarf_Error * /*err*/);
+int dwarf_fde_section_offset(Dwarf_Debug dbg,
+ Dwarf_Fde /*in_fde*/,
+ Dwarf_Off * /*fde_off*/,
+ Dwarf_Off * /*cie_off*/,
+ Dwarf_Error * /*err*/);
+
+/* Used by dwarfdump -v to print cie offsets from debugging
+ info.
+ The _dwarf name is obsolete. Use dwarf_ instead.
+*/
+int dwarf_cie_section_offset(Dwarf_Debug /*dbg*/,
+ Dwarf_Cie /*in_cie*/,
+ Dwarf_Off * /*cie_off */,
+ Dwarf_Error * /*err*/);
+int _dwarf_cie_section_offset(Dwarf_Debug /*dbg*/,
+ Dwarf_Cie /*in_cie*/,
+ Dwarf_Off * /*cie_off*/,
+ Dwarf_Error * /*err*/);
+
+typedef struct Dwarf_Macro_Details_s Dwarf_Macro_Details;
+
+int dwarf_get_macro(Dwarf_Debug /*dbg*/,
+ char * /*requested_macro_name*/,
+ Dwarf_Addr /*pc_of_request*/,
+ char ** /*returned_macro_value*/,
+ Dwarf_Error * /*error*/);
+
+int dwarf_get_all_defined_macros(Dwarf_Debug /*dbg*/,
+ Dwarf_Addr /*pc_of_request*/,
+ Dwarf_Signed * /*returned_count*/,
+ char *** /*returned_pointers_to_macros*/,
+ Dwarf_Error * /*error*/);
+
+char *dwarf_find_macro_value_start(char * /*macro_string*/);
+
+int dwarf_get_macro_details(Dwarf_Debug /*dbg*/,
+ Dwarf_Off /*macro_offset*/,
+ Dwarf_Unsigned /*maximum_count*/,
+ Dwarf_Signed * /*entry_count*/,
+ Dwarf_Macro_Details ** /*details*/,
+ Dwarf_Error * /*err*/);
+
+
+int dwarf_get_address_size(Dwarf_Debug /*dbg*/,
+ Dwarf_Half * /*addr_size*/,
+ Dwarf_Error * /*error*/);
+int dwarf_get_die_address_size(Dwarf_Die /*die*/,
+ Dwarf_Half * /*addr_size*/,
+ Dwarf_Error * /*error*/);
+
+/* The dwarf specification separates FORMs into
+different classes. To do the seperation properly
+requires 4 pieces of data as of DWARF4 (thus the
+function arguments listed here).
+The DWARF4 specification class definition suffices to
+describe all DWARF versions.
+See section 7.5.4, Attribute Encodings.
+A return of DW_FORM_CLASS_UNKNOWN means we could not properly figure
+out what form-class it is.
+
+ DW_FORM_CLASS_FRAMEPTR is MIPS/IRIX only, and refers
+ to the DW_AT_MIPS_fde attribute (a reference to the
+ .debug_frame section).
+*/
+enum Dwarf_Form_Class {
+ DW_FORM_CLASS_UNKNOWN, DW_FORM_CLASS_ADDRESS,
+ DW_FORM_CLASS_BLOCK, DW_FORM_CLASS_CONSTANT,
+ DW_FORM_CLASS_EXPRLOC, DW_FORM_CLASS_FLAG,
+ DW_FORM_CLASS_LINEPTR, DW_FORM_CLASS_LOCLISTPTR,
+ DW_FORM_CLASS_MACPTR, DW_FORM_CLASS_RANGELISTPTR,
+ DW_FORM_CLASS_REFERENCE, DW_FORM_CLASS_STRING,
+ DW_FORM_CLASS_FRAMEPTR
+};
+
+enum Dwarf_Form_Class dwarf_get_form_class(
+ Dwarf_Half /* dwversion */,
+ Dwarf_Half /* attrnum */,
+ Dwarf_Half /*offset_size */,
+ Dwarf_Half /*form*/);
+
+/* utility operations */
+Dwarf_Unsigned dwarf_errno(Dwarf_Error /*error*/);
+
+char* dwarf_errmsg(Dwarf_Error /*error*/);
+
+/* stringcheck zero is default and means do all
+** string length validity checks.
+** Call with parameter value 1 to turn off many such checks (and
+** increase performance).
+** Call with zero for safest running.
+** Actual value saved and returned is only 8 bits! Upper bits
+** ignored by libdwarf (and zero on return).
+** Returns previous value.
+*/
+int dwarf_set_stringcheck(int /*stringcheck*/);
+
+/* 'apply' defaults to 1 and means do all
+ * 'rela' relocations on reading in a dwarf object section with
+ * such relocations.
+ * Call with parameter value 0 to turn off application of
+ * such relocations.
+ * Since the static linker leaves 'bogus' data in object sections
+ * with a 'rela' relocation section such data cannot be read
+ * sensibly without processing the relocations. Such relocations
+ * do not exist in executables and shared objects (.so), the
+ * relocations only exist in plain .o relocatable object files.
+ * Actual value saved and returned is only 8 bits! Upper bits
+ * ignored by libdwarf (and zero on return).
+ * Returns previous value.
+ * */
+int dwarf_set_reloc_application(int /*apply*/);
+
+
+/* Unimplemented */
+Dwarf_Handler dwarf_seterrhand(Dwarf_Debug /*dbg*/, Dwarf_Handler /*errhand*/);
+
+/* Unimplemented */
+Dwarf_Ptr dwarf_seterrarg(Dwarf_Debug /*dbg*/, Dwarf_Ptr /*errarg*/);
+
+void dwarf_dealloc(Dwarf_Debug /*dbg*/, void* /*space*/,
+ Dwarf_Unsigned /*type*/);
+
+/* DWARF Producer Interface */
+
+typedef int (*Dwarf_Callback_Func)(
+ char* /*name*/,
+ int /*size*/,
+ Dwarf_Unsigned /*type*/,
+ Dwarf_Unsigned /*flags*/,
+ Dwarf_Unsigned /*link*/,
+ Dwarf_Unsigned /*info*/,
+ int* /*sect name index*/,
+ int* /*error*/);
+
+Dwarf_P_Debug dwarf_producer_init(
+ Dwarf_Unsigned /*creation_flags*/,
+ Dwarf_Callback_Func /*func*/,
+ Dwarf_Handler /*errhand*/,
+ Dwarf_Ptr /*errarg*/,
+ Dwarf_Error* /*error*/);
+
+typedef int (*Dwarf_Callback_Func_b)(
+ char* /*name*/,
+ int /*size*/,
+ Dwarf_Unsigned /*type*/,
+ Dwarf_Unsigned /*flags*/,
+ Dwarf_Unsigned /*link*/,
+ Dwarf_Unsigned /*info*/,
+ Dwarf_Unsigned* /*sect_name_index*/,
+ int* /*error*/);
+
+
+Dwarf_P_Debug dwarf_producer_init_b(
+ Dwarf_Unsigned /*flags*/,
+ Dwarf_Callback_Func_b /*func*/,
+ Dwarf_Handler /*errhand*/,
+ Dwarf_Ptr /*errarg*/,
+ Dwarf_Error * /*error*/);
+
+
+Dwarf_Signed dwarf_transform_to_disk_form(Dwarf_P_Debug /*dbg*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Ptr dwarf_get_section_bytes(Dwarf_P_Debug /*dbg*/,
+ Dwarf_Signed /*dwarf_section*/,
+ Dwarf_Signed* /*elf_section_index*/,
+ Dwarf_Unsigned* /*length*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_get_relocation_info_count(
+ Dwarf_P_Debug /*dbg*/,
+ Dwarf_Unsigned * /*count_of_relocation_sections*/,
+ int * /*drd_buffer_version*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_get_relocation_info(
+ Dwarf_P_Debug /*dbg*/,
+ Dwarf_Signed * /*elf_section_index*/,
+ Dwarf_Signed * /*elf_section_index_link*/,
+ Dwarf_Unsigned * /*relocation_buffer_count*/,
+ Dwarf_Relocation_Data * /*reldata_buffer*/,
+ Dwarf_Error* /*error*/);
+
+/* v1: no drd_length field, enum explicit */
+/* v2: has the drd_length field, enum value in uchar member */
+#define DWARF_DRD_BUFFER_VERSION 2
+
+/* Markers are not written to DWARF2/3/4, they are user
+ defined and may be used for any purpose.
+*/
+Dwarf_Signed dwarf_get_die_markers(
+ Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Marker * /*marker_list*/,
+ Dwarf_Unsigned * /*marker_count*/,
+ Dwarf_Error * /*error*/);
+
+int dwarf_get_string_attributes_count(Dwarf_P_Debug,
+ Dwarf_Unsigned *,
+ int *,
+ Dwarf_Error *);
+
+int dwarf_get_string_attributes_info(Dwarf_P_Debug,
+ Dwarf_Signed *,
+ Dwarf_Unsigned *,
+ Dwarf_P_String_Attr *,
+ Dwarf_Error *);
+
+void dwarf_reset_section_bytes(Dwarf_P_Debug /*dbg*/);
+
+Dwarf_Unsigned dwarf_producer_finish(Dwarf_P_Debug /*dbg*/,
+ Dwarf_Error* /*error*/);
+
+/* Producer attribute addition functions. */
+Dwarf_P_Attribute dwarf_add_AT_targ_address(Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Die /*ownerdie*/,
+ Dwarf_Half /*attr*/,
+ Dwarf_Unsigned /*pc_value*/,
+ Dwarf_Signed /*sym_index*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_P_Attribute dwarf_add_AT_block(Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Die /*ownerdie*/,
+ Dwarf_Half /*attr*/,
+ Dwarf_Small* /*block_data*/,
+ Dwarf_Unsigned /*block_len*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_P_Attribute dwarf_add_AT_targ_address_b(Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Die /*ownerdie*/,
+ Dwarf_Half /*attr*/,
+ Dwarf_Unsigned /*pc_value*/,
+ Dwarf_Unsigned /*sym_index*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_P_Attribute dwarf_add_AT_ref_address(Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Die /*ownerdie*/,
+ Dwarf_Half /*attr*/,
+ Dwarf_Unsigned /*pc_value*/,
+ Dwarf_Unsigned /*sym_index*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_P_Attribute dwarf_add_AT_unsigned_const(Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Die /*ownerdie*/,
+ Dwarf_Half /*attr*/,
+ Dwarf_Unsigned /*value*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_P_Attribute dwarf_add_AT_signed_const(Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Die /*ownerdie*/,
+ Dwarf_Half /*attr*/,
+ Dwarf_Signed /*value*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_P_Attribute dwarf_add_AT_reference(Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Die /*ownerdie*/,
+ Dwarf_Half /*attr*/,
+ Dwarf_P_Die /*otherdie*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_P_Attribute dwarf_add_AT_dataref(
+ Dwarf_P_Debug /* dbg*/,
+ Dwarf_P_Die /*ownerdie*/,
+ Dwarf_Half /*attr*/,
+ Dwarf_Unsigned /*pcvalue*/,
+ Dwarf_Unsigned /*sym_index*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_P_Attribute dwarf_add_AT_const_value_string(Dwarf_P_Die /*ownerdie*/,
+ char* /*string_value*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_P_Attribute dwarf_add_AT_location_expr(Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Die /*ownerdie*/,
+ Dwarf_Half /*attr*/,
+ Dwarf_P_Expr /*loc_expr*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_P_Attribute dwarf_add_AT_string(Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Die /*ownerdie*/,
+ Dwarf_Half /*attr*/,
+ char* /*string*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_P_Attribute dwarf_add_AT_flag(Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Die /*ownerdie*/,
+ Dwarf_Half /*attr*/,
+ Dwarf_Small /*flag*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_P_Attribute dwarf_add_AT_producer(Dwarf_P_Die /*ownerdie*/,
+ char* /*producer_string*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_P_Attribute dwarf_add_AT_const_value_signedint(Dwarf_P_Die /*ownerdie*/,
+ Dwarf_Signed /*signed_value*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_P_Attribute dwarf_add_AT_const_value_unsignedint(
+ Dwarf_P_Die /*ownerdie*/,
+ Dwarf_Unsigned /*unsigned_value*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_P_Attribute dwarf_add_AT_comp_dir(Dwarf_P_Die /*ownerdie*/,
+ char* /*current_working_directory*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_P_Attribute dwarf_add_AT_name(Dwarf_P_Die /*die*/,
+ char* /*name*/,
+ Dwarf_Error* /*error*/);
+
+/* Producer line creation functions (.debug_line) */
+Dwarf_Unsigned dwarf_add_directory_decl(Dwarf_P_Debug /*dbg*/,
+ char* /*name*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Unsigned dwarf_add_file_decl(Dwarf_P_Debug /*dbg*/,
+ char* /*name*/,
+ Dwarf_Unsigned /*dir_index*/,
+ Dwarf_Unsigned /*time_last_modified*/,
+ Dwarf_Unsigned /*length*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Unsigned dwarf_add_line_entry(Dwarf_P_Debug /*dbg*/,
+ Dwarf_Unsigned /*file_index*/,
+ Dwarf_Addr /*code_address*/,
+ Dwarf_Unsigned /*lineno*/,
+ Dwarf_Signed /*column_number*/,
+ Dwarf_Bool /*is_source_stmt_begin*/,
+ Dwarf_Bool /*is_basic_block_begin*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Unsigned dwarf_lne_set_address(Dwarf_P_Debug /*dbg*/,
+ Dwarf_Unsigned /*offset*/,
+ Dwarf_Unsigned /*symbol_index*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Unsigned dwarf_lne_end_sequence(Dwarf_P_Debug /*dbg*/,
+ Dwarf_Addr /*end_address*/,
+ Dwarf_Error* /*error*/);
+
+/* Producer .debug_frame functions */
+Dwarf_Unsigned dwarf_add_frame_cie(Dwarf_P_Debug /*dbg*/,
+ char* /*augmenter*/,
+ Dwarf_Small /*code_alignent_factor*/,
+ Dwarf_Small /*data_alignment_factor*/,
+ Dwarf_Small /*return_address_reg*/,
+ Dwarf_Ptr /*initialization_bytes*/,
+ Dwarf_Unsigned /*init_byte_len*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Unsigned dwarf_add_frame_fde(
+ Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Fde /*fde*/,
+ Dwarf_P_Die /*corresponding subprogram die*/,
+ Dwarf_Unsigned /*cie_to_use*/,
+ Dwarf_Unsigned /*virt_addr_of_described_code*/,
+ Dwarf_Unsigned /*length_of_code*/,
+ Dwarf_Unsigned /*symbol_index*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Unsigned dwarf_add_frame_fde_b(
+ Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Fde /*fde*/,
+ Dwarf_P_Die /*die*/,
+ Dwarf_Unsigned /*cie*/,
+ Dwarf_Addr /*virt_addr*/,
+ Dwarf_Unsigned /*code_len*/,
+ Dwarf_Unsigned /*sym_idx*/,
+ Dwarf_Unsigned /*sym_idx_of_end*/,
+ Dwarf_Addr /*offset_from_end_sym*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Unsigned dwarf_add_frame_info_b(
+ Dwarf_P_Debug dbg /*dbg*/,
+ Dwarf_P_Fde /*fde*/,
+ Dwarf_P_Die /*die*/,
+ Dwarf_Unsigned /*cie*/,
+ Dwarf_Addr /*virt_addr*/,
+ Dwarf_Unsigned /*code_len*/,
+ Dwarf_Unsigned /*symidx*/,
+ Dwarf_Unsigned /*end_symbol */,
+ Dwarf_Addr /*offset_from_end_symbol */,
+ Dwarf_Signed /*offset_into_exception_tables*/,
+ Dwarf_Unsigned /*exception_table_symbol*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Unsigned dwarf_add_frame_info(
+ Dwarf_P_Debug dbg /*dbg*/,
+ Dwarf_P_Fde /*fde*/,
+ Dwarf_P_Die /*die*/,
+ Dwarf_Unsigned /*cie*/,
+ Dwarf_Addr /*virt_addr*/,
+ Dwarf_Unsigned /*code_len*/,
+ Dwarf_Unsigned /*symidx*/,
+ Dwarf_Signed /*offset_into_exception_tables*/,
+ Dwarf_Unsigned /*exception_table_symbol*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_P_Fde dwarf_add_fde_inst(
+ Dwarf_P_Fde /*fde*/,
+ Dwarf_Small /*op*/,
+ Dwarf_Unsigned /*val1*/,
+ Dwarf_Unsigned /*val2*/,
+ Dwarf_Error* /*error*/);
+
+/* New September 17, 2009 */
+int dwarf_insert_fde_inst_bytes(
+ Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Fde /*fde*/,
+ Dwarf_Unsigned /*len*/,
+ Dwarf_Ptr /*ibytes*/,
+ Dwarf_Error* /*error*/);
+
+
+Dwarf_P_Fde dwarf_new_fde(Dwarf_P_Debug /*dbg*/, Dwarf_Error* /*error*/);
+
+Dwarf_P_Fde dwarf_fde_cfa_offset(
+ Dwarf_P_Fde /*fde*/,
+ Dwarf_Unsigned /*register_number*/,
+ Dwarf_Signed /*offset*/,
+ Dwarf_Error* /*error*/);
+
+/* die creation & addition routines */
+Dwarf_P_Die dwarf_new_die(
+ Dwarf_P_Debug /*dbg*/,
+ Dwarf_Tag /*tag*/,
+ Dwarf_P_Die /*parent*/,
+ Dwarf_P_Die /*child*/,
+ Dwarf_P_Die /*left */,
+ Dwarf_P_Die /*right*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Unsigned dwarf_add_die_to_debug(
+ Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Die /*die*/,
+ Dwarf_Error* /*error*/);
+
+/* Markers are not written to DWARF2/3/4, they are user
+ defined and may be used for any purpose.
+*/
+Dwarf_Unsigned dwarf_add_die_marker(
+ Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Die /*die*/,
+ Dwarf_Unsigned /*marker*/,
+ Dwarf_Error * /*error*/);
+
+Dwarf_Unsigned dwarf_get_die_marker(
+ Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Die /*die*/,
+ Dwarf_Unsigned * /*marker*/,
+ Dwarf_Error * /*error*/);
+
+Dwarf_P_Die dwarf_die_link(
+ Dwarf_P_Die /*die*/,
+ Dwarf_P_Die /*parent*/,
+ Dwarf_P_Die /*child*/,
+ Dwarf_P_Die /*left*/,
+ Dwarf_P_Die /*right*/,
+ Dwarf_Error* /*error*/);
+
+void dwarf_dealloc_compressed_block(
+ Dwarf_P_Debug,
+ void *
+);
+
+/* Call this passing in return value from dwarf_uncompress_integer_block()
+ * to free the space the decompression allocated. */
+void dwarf_dealloc_uncompressed_block(
+ Dwarf_Debug,
+ void *
+);
+
+void * dwarf_compress_integer_block(
+ Dwarf_P_Debug, /* dbg */
+ Dwarf_Bool, /* signed==true (or unsigned) */
+ Dwarf_Small, /* size of integer units: 8, 16, 32, 64 */
+ void*, /* data */
+ Dwarf_Unsigned, /* number of elements */
+ Dwarf_Unsigned*, /* number of bytes in output block */
+ Dwarf_Error* /* error */
+);
+
+/* Decode an array of signed leb integers (so of course the
+ * array is not composed of fixed length values, but is instead
+ * a sequence of sleb values).
+ * Returns a DW_DLV_BADADDR on error.
+ * Otherwise returns a pointer to an array of 32bit integers.
+ * The signed argument must be non-zero (the decode
+ * assumes sleb integers in the input data) at this time.
+ * Size of integer units must be 32 (32 bits each) at this time.
+ * Number of bytes in block is a byte count (not array count).
+ * Returns number of units in output block (ie, number of elements
+ * of the array that the return value points to) thru the argument.
+ */
+void * dwarf_uncompress_integer_block(
+ Dwarf_Debug, /* dbg */
+ Dwarf_Bool, /* signed==true (or unsigned) */
+ Dwarf_Small, /* size of integer units: 8, 16, 32, 64 */
+ void*, /* input data */
+ Dwarf_Unsigned, /* number of bytes in input */
+ Dwarf_Unsigned*, /* number of units in output block */
+ Dwarf_Error* /* error */
+);
+
+/* Operations to create location expressions. */
+Dwarf_P_Expr dwarf_new_expr(Dwarf_P_Debug /*dbg*/, Dwarf_Error* /*error*/);
+
+void dwarf_expr_reset(
+ Dwarf_P_Expr /*expr*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Unsigned dwarf_add_expr_gen(
+ Dwarf_P_Expr /*expr*/,
+ Dwarf_Small /*opcode*/,
+ Dwarf_Unsigned /*val1*/,
+ Dwarf_Unsigned /*val2*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Unsigned dwarf_add_expr_addr(
+ Dwarf_P_Expr /*expr*/,
+ Dwarf_Unsigned /*addr*/,
+ Dwarf_Signed /*sym_index*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Unsigned dwarf_add_expr_addr_b(
+ Dwarf_P_Expr /*expr*/,
+ Dwarf_Unsigned /*addr*/,
+ Dwarf_Unsigned /*sym_index*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Unsigned dwarf_expr_current_offset(
+ Dwarf_P_Expr /*expr*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Addr dwarf_expr_into_block(
+ Dwarf_P_Expr /*expr*/,
+ Dwarf_Unsigned* /*length*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Unsigned dwarf_add_arange(Dwarf_P_Debug /*dbg*/,
+ Dwarf_Addr /*begin_address*/,
+ Dwarf_Unsigned /*length*/,
+ Dwarf_Signed /*symbol_index*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Unsigned dwarf_add_arange_b(
+ Dwarf_P_Debug /*dbg*/,
+ Dwarf_Addr /*begin_address*/,
+ Dwarf_Unsigned /*length*/,
+ Dwarf_Unsigned /*symbol_index*/,
+ Dwarf_Unsigned /*end_symbol_index*/,
+ Dwarf_Addr /*offset_from_end_symbol*/,
+ Dwarf_Error * /*error*/);
+
+Dwarf_Unsigned dwarf_add_pubname(
+ Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Die /*die*/,
+ char* /*pubname_name*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Unsigned dwarf_add_funcname(
+ Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Die /*die*/,
+ char* /*func_name*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Unsigned dwarf_add_typename(
+ Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Die /*die*/,
+ char* /*type_name*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Unsigned dwarf_add_varname(
+ Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Die /*die*/,
+ char* /*var_name*/,
+ Dwarf_Error* /*error*/);
+
+Dwarf_Unsigned dwarf_add_weakname(
+ Dwarf_P_Debug /*dbg*/,
+ Dwarf_P_Die /*die*/,
+ char* /*weak_name*/,
+ Dwarf_Error* /*error*/);
+
+/* .debug_macinfo producer functions
+ Functions must be called in right order: the section is output
+ In the order these are presented.
+*/
+int dwarf_def_macro(Dwarf_P_Debug /*dbg*/,
+ Dwarf_Unsigned /*line*/,
+ char * /*macname, with (arglist), no space before (*/,
+ char * /*macvalue*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_undef_macro(Dwarf_P_Debug /*dbg*/,
+ Dwarf_Unsigned /*line*/,
+ char * /*macname, no arglist, of course*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_start_macro_file(Dwarf_P_Debug /*dbg*/,
+ Dwarf_Unsigned /*fileindex*/,
+ Dwarf_Unsigned /*linenumber*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_end_macro_file(Dwarf_P_Debug /*dbg*/,
+ Dwarf_Error* /*error*/);
+
+int dwarf_vendor_ext(Dwarf_P_Debug /*dbg*/,
+ Dwarf_Unsigned /*constant*/,
+ char * /*string*/,
+ Dwarf_Error* /*error*/);
+
+/* end macinfo producer functions */
+
+int dwarf_attr_offset(Dwarf_Die /*die*/,
+ Dwarf_Attribute /*attr of above die*/,
+ Dwarf_Off * /*returns offset thru this ptr */,
+ Dwarf_Error * /*error*/);
+
+/* This is a hack so clients can verify offsets.
+ Added April 2005 so that debugger can detect broken offsets
+ (which happened in an IRIX executable larger than 2GB
+ with MIPSpro 7.3.1.3 toolchain.).
+*/
+int
+dwarf_get_section_max_offsets(Dwarf_Debug /*dbg*/,
+ Dwarf_Unsigned * /*debug_info_size*/,
+ Dwarf_Unsigned * /*debug_abbrev_size*/,
+ Dwarf_Unsigned * /*debug_line_size*/,
+ Dwarf_Unsigned * /*debug_loc_size*/,
+ Dwarf_Unsigned * /*debug_aranges_size*/,
+ Dwarf_Unsigned * /*debug_macinfo_size*/,
+ Dwarf_Unsigned * /*debug_pubnames_size*/,
+ Dwarf_Unsigned * /*debug_str_size*/,
+ Dwarf_Unsigned * /*debug_frame_size*/,
+ Dwarf_Unsigned * /*debug_ranges_size*/,
+ Dwarf_Unsigned * /*debug_pubtypes_size*/);
+
+/* Multiple releases spelled 'initial' as 'inital' .
+ The 'inital' spelling should not be used. */
+Dwarf_Half dwarf_set_frame_rule_inital_value(Dwarf_Debug /*dbg*/,
+ Dwarf_Half /*value*/);
+/* Additional interface with correct 'initial' spelling. */
+/* It is likely you will want to call the following 5 functions
+ before accessing any frame information. All are useful
+ to tailor handling of pseudo-registers needed to turn
+ frame operation references into simpler forms and to
+ reflect ABI specific data. Of course altering libdwarf.h
+ and dwarf.h allow the same capabilities, but such header changes
+ do not let one change these values at runtime. */
+Dwarf_Half dwarf_set_frame_rule_initial_value(Dwarf_Debug /*dbg*/,
+ Dwarf_Half /*value*/);
+Dwarf_Half dwarf_set_frame_rule_table_size(Dwarf_Debug /*dbg*/,
+ Dwarf_Half /*value*/);
+Dwarf_Half dwarf_set_frame_cfa_value(Dwarf_Debug /*dbg*/,
+ Dwarf_Half /*value*/);
+Dwarf_Half dwarf_set_frame_same_value(Dwarf_Debug /*dbg*/,
+ Dwarf_Half /*value*/);
+Dwarf_Half dwarf_set_frame_undefined_value(Dwarf_Debug /*dbg*/,
+ Dwarf_Half /*value*/);
+
+/* As of April 27, 2009, this version with no diepointer is
+ obsolete though supported. Use dwarf_get_ranges_a() instead. */
+int dwarf_get_ranges(Dwarf_Debug /*dbg*/,
+ Dwarf_Off /*rangesoffset*/,
+ Dwarf_Ranges ** /*rangesbuf*/,
+ Dwarf_Signed * /*listlen*/,
+ Dwarf_Unsigned * /*bytecount*/,
+ Dwarf_Error * /*error*/);
+
+/* This adds the address_size argument. New April 27, 2009 */
+int dwarf_get_ranges_a(Dwarf_Debug /*dbg*/,
+ Dwarf_Off /*rangesoffset*/,
+ Dwarf_Die /* diepointer */,
+ Dwarf_Ranges ** /*rangesbuf*/,
+ Dwarf_Signed * /*listlen*/,
+ Dwarf_Unsigned * /*bytecount*/,
+ Dwarf_Error * /*error*/);
+
+void dwarf_ranges_dealloc(Dwarf_Debug /*dbg*/,
+ Dwarf_Ranges * /*rangesbuf*/,
+ Dwarf_Signed /*rangecount*/);
+
+/* The harmless error list is a circular buffer of
+ errors we note but which do not stop us from processing
+ the object. Created so dwarfdump or other tools
+ can report such inconsequential errors without causing
+ anything to stop early. */
+#define DW_HARMLESS_ERROR_CIRCULAR_LIST_DEFAULT_SIZE 4
+#define DW_HARMLESS_ERROR_MSG_STRING_SIZE 200
+/* User code supplies size of array of pointers errmsg_ptrs_array
+ in count and the array of pointers (the pointers themselves
+ need not be initialized).
+ The pointers returned in the array of pointers
+ are invalidated by ANY call to libdwarf.
+ Use them before making another libdwarf call!
+ The array of string pointers passed in always has
+ a final null pointer, so if there are N pointers the
+ and M actual strings, then MIN(M,N-1) pointers are
+ set to point to error strings. The array of pointers
+ to strings always terminates with a NULL pointer.
+ If 'count' is passed in zero then errmsg_ptrs_array
+ is not touched.
+
+ The function returns DW_DLV_NO_ENTRY if no harmless errors
+ were noted so far. Returns DW_DLV_OK if there are errors.
+ Never returns DW_DLV_ERROR.
+
+ Each call empties the error list (discarding all current entries).
+ If newerr_count is non-NULL the count of harmless errors
+ since the last call is returned through the pointer
+ (some may have been discarded or not returned, it is a circular
+ list...).
+ If DW_DLV_NO_ENTRY is returned none of the arguments
+ here are touched or used.
+ */
+int dwarf_get_harmless_error_list(Dwarf_Debug /*dbg*/,
+ unsigned /*count*/,
+ const char ** /*errmsg_ptrs_array*/,
+ unsigned * /*newerr_count*/);
+
+/* Insertion is only for testing the harmless error code, it is not
+ necessarily useful otherwise. */
+void dwarf_insert_harmless_error(Dwarf_Debug /*dbg*/,
+ char * /*newerror*/);
+
+/* The size of the circular list of strings may be set
+ and reset as needed. If it is shortened excess
+ messages are simply dropped. It returns the previous
+ size. If zero passed in the size is unchanged
+ and it simply returns the current size */
+unsigned dwarf_set_harmless_error_list_size(Dwarf_Debug /*dbg*/,
+ unsigned /*maxcount*/);
+/* The harmless error strings (if any) are freed when the dbg
+ is dwarf_finish()ed. */
+
+/* When the val_in is known these dwarf_get_TAG_name (etc)
+ functions return the string corresponding to the val_in passed in
+ through the pointer s_out and the value returned is DW_DLV_OK.
+ The strings are in static storage
+ and must not be freed.
+ If DW_DLV_NO_ENTRY is returned the val_in is not known and
+ *s_out is not set. DW_DLV_ERROR is never returned.*/
+
+extern int dwarf_get_TAG_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_children_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_FORM_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_AT_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_OP_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_ATE_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_DS_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_END_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_ATCF_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_ACCESS_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_VIS_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_VIRTUALITY_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_LANG_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_ID_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_CC_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_INL_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_ORD_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_DSC_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_LNS_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_LNE_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_MACINFO_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_CFA_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_EH_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_FRAME_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_CHILDREN_name(unsigned int /*val_in*/, const char ** /*s_out */);
+extern int dwarf_get_ADDR_name(unsigned int /*val_in*/, const char ** /*s_out */);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _LIBDWARF_H */
+
+
diff --git a/usr/src/lib/libdwarf/common/libdwarfdefs.h b/usr/src/lib/libdwarf/common/libdwarfdefs.h
new file mode 100644
index 0000000000..a564655b23
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/libdwarfdefs.h
@@ -0,0 +1,91 @@
+/*
+
+ Copyright (C) 2000,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
+
+*/
+
+
+/* libdwarfdefs.h
+*/
+
+#ifndef LIBDWARFDEFS_H
+#define LIBDWARFDEFS_H
+
+/* We want __uint32_t and __uint64_t and __int32_t __int64_t
+ properly defined but not duplicated, since duplicate typedefs
+ are not legal C.
+*/
+/*
+ HAVE___UINT32_T
+ HAVE___UINT64_T will be set by configure if
+ our 4 types are predefined in compiler
+*/
+
+
+#if (!defined(HAVE___UINT32_T)) && defined(HAVE___UINT32_T_IN_SGIDEFS_H)
+#include <sgidefs.h> /* sgidefs.h defines them */
+#define HAVE___UINT32_T 1
+#endif
+
+#if (!defined(HAVE___UINT64_T)) && defined(HAVE___UINT64_T_IN_SGIDEFS_H)
+#include <sgidefs.h> /* sgidefs.h defines them */
+#define HAVE___UINT64_T 1
+#endif
+
+
+#if (!defined(HAVE___UINT32_T)) && \
+ defined(HAVE_SYS_TYPES_H) && \
+ defined(HAVE___UINT32_T_IN_SYS_TYPES_H)
+# include <sys/types.h>
+#define HAVE___UINT32_T 1
+#endif
+
+#if (!defined(HAVE___UINT64_T)) && \
+ defined(HAVE_SYS_TYPES_H) && \
+ defined(HAVE___UINT64_T_IN_SYS_TYPES_H)
+# include <sys/types.h>
+#define HAVE___UINT64_T 1
+#endif
+
+#ifndef HAVE___UINT32_T
+typedef int __int32_t;
+typedef unsigned __uint32_t;
+#define HAVE___UINT32_T 1
+#endif
+
+#ifndef HAVE___UINT64_T
+typedef long long __int64_t;
+typedef unsigned long long __uint64_t;
+#define HAVE___UINT64_T 1
+#endif
+
+#endif /* LIBDWARFDEFS_H */
diff --git a/usr/src/lib/libdwarf/common/malloc_check.c b/usr/src/lib/libdwarf/common/malloc_check.c
new file mode 100644
index 0000000000..1c6e7738e4
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/malloc_check.c
@@ -0,0 +1,339 @@
+/*
+
+ Copyright (C) 2005 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
+
+*/
+
+
+
+/* malloc_check.c For checking dealloc completeness.
+
+ This code is as simple as possible and works ok for
+ reasonable size allocation counts.
+
+ It treats allocation as global, and so will not
+ work very well if an application opens more than one
+ Dwarf_Debug.
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h> /* for exit() and various malloc
+ prototypes */
+#include "config.h"
+#include "dwarf_incl.h"
+#include "malloc_check.h"
+#ifdef WANT_LIBBDWARF_MALLOC_CHECK
+
+/* To turn off printing every entry, just change the define
+ to set PRINT_MALLOC_DETAILS 0.
+*/
+#define PRINT_MALLOC_DETAILS 0
+
+#define MC_TYPE_UNKNOWN 0
+#define MC_TYPE_ALLOC 1
+#define MC_TYPE_DEALLOC 2
+
+struct mc_data_s {
+ struct mc_data_s *mc_prev;
+ unsigned long mc_address; /* Assumes this is large enough to hold
+ a pointer! */
+
+ long mc_alloc_number; /* Assigned in order by when record
+ created. */
+ unsigned char mc_alloc_code; /* Allocation code, libdwarf. */
+ unsigned char mc_type;
+ unsigned char mc_dealloc_noted; /* Used on an ALLOC node. */
+ unsigned char mc_dealloc_noted_count; /* Used on an ALLOC
+ node. */
+};
+
+/*
+
+
+*/
+#define HASH_TABLE_SIZE 10501
+static struct mc_data_s *mc_data_hash[HASH_TABLE_SIZE];
+static long mc_data_list_size = 0;
+
+static char *alloc_type_name[MAX_DW_DLA + 1] = {
+ "",
+ "DW_DLA_STRING",
+ "DW_DLA_LOC",
+ "DW_DLA_LOCDESC",
+ "DW_DLA_ELLIST",
+ "DW_DLA_BOUNDS",
+ "DW_DLA_BLOCK",
+ "DW_DLA_DEBUG",
+ "DW_DLA_DIE",
+ "DW_DLA_LINE",
+ "DW_DLA_ATTR",
+ "DW_DLA_TYPE",
+ "DW_DLA_SUBSCR",
+ "DW_DLA_GLOBAL",
+ "DW_DLA_ERROR",
+ "DW_DLA_LIST",
+ "DW_DLA_LINEBUF",
+ "DW_DLA_ARANGE",
+ "DW_DLA_ABBREV",
+ "DW_DLA_FRAME_OP",
+ "DW_DLA_CIE",
+ "DW_DLA_FDE",
+ "DW_DLA_LOC_BLOCK",
+ "DW_DLA_FRAME_BLOCK",
+ "DW_DLA_FUNC",
+ "DW_DLA_TYPENAME",
+ "DW_DLA_VAR",
+ "DW_DLA_WEAK",
+ "DW_DLA_ADDR",
+ "DW_DLA_ABBREV_LIST",
+ "DW_DLA_CHAIN",
+ "DW_DLA_CU_CONTEXT",
+ "DW_DLA_FRAME",
+ "DW_DLA_GLOBAL_CONTEXT",
+ "DW_DLA_FILE_ENTRY",
+ "DW_DLA_LINE_CONTEXT",
+ "DW_DLA_LOC_CHAIN",
+ "DW_DLA_HASH_TABLE",
+ "DW_DLA_FUNC_CONTEXT",
+ "DW_DLA_TYPENAME_CONTEXT",
+ "DW_DLA_VAR_CONTEXT",
+ "DW_DLA_WEAK_CONTEXT",
+ "DW_DLA_PUBTYPES_CONTEXT"
+ /* Don't forget to expand this list if the list of codes
+ expands. */
+};
+
+static unsigned
+hash_address(unsigned long addr)
+{
+ unsigned long a = addr >> 2;
+
+ return a % HASH_TABLE_SIZE;
+}
+
+#if PRINT_MALLOC_DETAILS
+static void
+print_alloc_dealloc_detail(unsigned long addr,
+ int code, char *whichisit)
+{
+ fprintf(stderr,
+ "%s addr 0x%lx code %d (%s) entry %ld\n",
+ whichisit, addr, code, alloc_type_name[code],
+ mc_data_list_size);
+}
+#else
+#define print_alloc_dealloc_detail(a,b,c) /* nothing */
+#endif
+
+/* Create a zeroed struct or die. */
+static void *
+newone(void)
+{
+ struct mc_data_s *newd = malloc(sizeof(struct mc_data_s));
+
+ if (newd == 0) {
+ fprintf(stderr, "out of memory , # %ld\n", mc_data_list_size);
+ exit(1);
+ }
+ memset(newd, 0, sizeof(struct mc_data_s));
+ return newd;
+}
+
+/* Notify checker that get_alloc has allocated user data. */
+void
+dwarf_malloc_check_alloc_data(void *addr_in, unsigned char code)
+{
+ struct mc_data_s *newd = newone();
+ unsigned long addr = (unsigned long) addr_in;
+ struct mc_data_s **base = &mc_data_hash[hash_address(addr)];
+
+ print_alloc_dealloc_detail(addr, code, "alloc ");
+ newd->mc_address = addr;
+ newd->mc_alloc_code = code;
+ newd->mc_type = MC_TYPE_ALLOC;
+ newd->mc_alloc_number = mc_data_list_size;
+ newd->mc_prev = *base;
+ *base = newd;
+ newd->mc_alloc_number = mc_data_list_size;
+ mc_data_list_size += 1;
+}
+
+static void
+print_entry(char *msg, struct mc_data_s *data)
+{
+ fprintf(stderr,
+ "%s: 0x%08lx code %2d (%s) type %s dealloc noted %u ct %u\n",
+ msg,
+ (long) data->mc_address,
+ data->mc_alloc_code,
+ alloc_type_name[data->mc_alloc_code],
+ (data->mc_type == MC_TYPE_ALLOC) ? "alloc " :
+ (data->mc_type == MC_TYPE_DEALLOC) ? "dealloc" : "unknown",
+ (unsigned) data->mc_dealloc_noted,
+ (unsigned) data->mc_dealloc_noted_count);
+}
+
+/* newd is a 'dealloc'.
+*/
+static long
+balanced_by_alloc_p(struct mc_data_s *newd,
+ long *addr_match_num,
+ struct mc_data_s **addr_match,
+ struct mc_data_s *base)
+{
+ struct mc_data_s *cur = base;
+
+ for (; cur; cur = cur->mc_prev) {
+ if (cur->mc_address == newd->mc_address) {
+ if (cur->mc_type == MC_TYPE_ALLOC) {
+ if (cur->mc_alloc_code == newd->mc_alloc_code) {
+ *addr_match = cur;
+ *addr_match_num = cur->mc_alloc_number;
+ return cur->mc_alloc_number;
+ } else {
+ /* code mismatch */
+ *addr_match = cur;
+ *addr_match_num = cur->mc_alloc_number;
+ return -1;
+ }
+ } else {
+ /* Unbalanced new/del */
+ *addr_match = cur;
+ *addr_match_num = cur->mc_alloc_number;
+ return -1;
+ }
+ }
+ }
+ return -1;
+}
+
+/* A dealloc is to take place. Ensure it balances an alloc.
+*/
+void
+dwarf_malloc_check_dealloc_data(void *addr_in, unsigned char code)
+{
+ struct mc_data_s *newd = newone();
+ long prev;
+ long addr_match_num = -1;
+ struct mc_data_s *addr_match = 0;
+ unsigned long addr = (unsigned long) addr_in;
+ struct mc_data_s **base = &mc_data_hash[hash_address(addr)];
+
+
+ print_alloc_dealloc_detail(addr, code, "dealloc ");
+ newd->mc_address = (unsigned long) addr;
+ newd->mc_alloc_code = code;
+ newd->mc_type = MC_TYPE_DEALLOC;
+ newd->mc_prev = *base;
+ prev =
+ balanced_by_alloc_p(newd, &addr_match_num, &addr_match, *base);
+ if (prev < 0) {
+ fprintf(stderr,
+ "Unbalanced dealloc at index %ld\n", mc_data_list_size);
+ print_entry("new", newd);
+ fprintf(stderr, "addr-match_num? %ld\n", addr_match_num);
+ if (addr_match) {
+ print_entry("prev entry", addr_match);
+ if (addr_match->mc_dealloc_noted > 1) {
+ fprintf(stderr, "Above is Duplicate dealloc!\n");
+ }
+ }
+ abort();
+ exit(3);
+ }
+ addr_match->mc_dealloc_noted = 1;
+ addr_match->mc_dealloc_noted_count += 1;
+ if (addr_match->mc_dealloc_noted_count > 1) {
+ fprintf(stderr, "Double dealloc entry %ld\n", addr_match_num);
+ print_entry("new dealloc entry", newd);
+ print_entry("bad alloc entry", addr_match);
+ }
+ *base = newd;
+ mc_data_list_size += 1;
+}
+
+/* Final check for leaks.
+*/
+void
+dwarf_malloc_check_complete(char *msg)
+{
+ long i = 0;
+ long total = mc_data_list_size;
+ long hash_slots_used = 0;
+ long max_chain_length = 0;
+
+ fprintf(stderr, "Run complete, %s. %ld entries\n", msg, total);
+ for (; i < HASH_TABLE_SIZE; ++i) {
+ struct mc_data_s *cur = mc_data_hash[i];
+ long cur_chain_length = 0;
+
+ if (cur == 0)
+ continue;
+ ++hash_slots_used;
+ for (; cur; cur = cur->mc_prev) {
+ ++cur_chain_length;
+ if (cur->mc_type == MC_TYPE_ALLOC) {
+ if (cur->mc_dealloc_noted) {
+ if (cur->mc_dealloc_noted > 1) {
+ fprintf(stderr,
+ " Duplicate dealloc! entry %ld\n",
+ cur->mc_alloc_number);
+ print_entry("duplicate dealloc", cur);
+
+ }
+ continue;
+ } else {
+ fprintf(stderr, "malloc no dealloc, entry %ld\n",
+ cur->mc_alloc_number);
+ print_entry("dangle", cur);
+ }
+ } else {
+ /* mc_type is MC_TYPE_DEALLOC, already checked */
+
+ }
+ }
+ if (cur_chain_length > max_chain_length) {
+ max_chain_length = cur_chain_length;
+ }
+ }
+ fprintf(stderr, "mc hash table slots=%ld, "
+ "used=%ld, maxchain=%ld\n",
+ (long) HASH_TABLE_SIZE, hash_slots_used, max_chain_length);
+ return;
+}
+
+#else
+
+extern void *libdwarf_an_unused_function_so_not_empty_c_file();
+
+#endif /* WANT_LIBBDWARF_MALLOC_CHECK */
diff --git a/usr/src/lib/libdwarf/common/malloc_check.h b/usr/src/lib/libdwarf/common/malloc_check.h
new file mode 100644
index 0000000000..ba1ad3da71
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/malloc_check.h
@@ -0,0 +1,62 @@
+/*
+
+ Copyright (C) 2005 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
+
+*/
+
+
+/* malloc_check.h */
+
+/* A simple libdwarf-aware malloc checker.
+ define WANT_LIBBDWARF_MALLOC_CHECK and rebuild libdwarf
+ do make a checking-for-alloc-mistakes libdwarf.
+ NOT recommended for production use.
+
+ When defined, also add malloc_check.c to the list of
+ files in Makefile.
+*/
+
+#undef WANT_LIBBDWARF_MALLOC_CHECK
+/*#define WANT_LIBBDWARF_MALLOC_CHECK 1 */
+
+#ifdef WANT_LIBBDWARF_MALLOC_CHECK
+
+void dwarf_malloc_check_alloc_data(void * addr,unsigned char code);
+void dwarf_malloc_check_dealloc_data(void * addr,unsigned char code);
+void dwarf_malloc_check_complete(char *wheremsg); /* called at exit of app */
+
+#else /* !WANT_LIBBDWARF_MALLOC_CHECK */
+
+#define dwarf_malloc_check_alloc_data(a,b) /* nothing */
+#define dwarf_malloc_check_dealloc_data(a,b) /* nothing */
+#define dwarf_malloc_check_complete(a) /* nothing */
+
+#endif /* WANT_LIBBDWARF_MALLOC_CHECK */
diff --git a/usr/src/lib/libdwarf/common/mapfile-vers b/usr/src/lib/libdwarf/common/mapfile-vers
new file mode 100644
index 0000000000..c1a652a591
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/mapfile-vers
@@ -0,0 +1,302 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2011, Richard Lowe.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+SYMBOL_VERSION ILLUMOSprivate_1.1 {
+ global:
+ dwarf_add_arange;
+ dwarf_add_arange_b;
+ dwarf_add_AT_block;
+ dwarf_add_AT_comp_dir;
+ dwarf_add_AT_const_value_signedint;
+ dwarf_add_AT_const_value_string;
+ dwarf_add_AT_const_value_unsignedint;
+ dwarf_add_AT_dataref;
+ dwarf_add_AT_flag;
+ dwarf_add_AT_location_expr;
+ dwarf_add_AT_name;
+ dwarf_add_AT_producer;
+ dwarf_add_AT_ref_address;
+ dwarf_add_AT_reference;
+ dwarf_add_AT_signed_const;
+ dwarf_add_AT_string;
+ dwarf_add_AT_targ_address;
+ dwarf_add_AT_targ_address_b;
+ dwarf_add_AT_unsigned_const;
+ dwarf_add_die_marker;
+ dwarf_add_die_to_debug;
+ dwarf_add_directory_decl;
+ dwarf_add_expr_addr;
+ dwarf_add_expr_addr_b;
+ dwarf_add_expr_gen;
+ dwarf_add_fde_inst;
+ dwarf_add_file_decl;
+ dwarf_add_frame_cie;
+ dwarf_add_frame_fde;
+ dwarf_add_frame_fde_b;
+ dwarf_add_frame_info;
+ dwarf_add_frame_info_b;
+ dwarf_add_funcname;
+ dwarf_add_line_entry;
+ dwarf_add_pubname;
+ dwarf_add_typename;
+ dwarf_add_varname;
+ dwarf_add_weakname;
+ dwarf_arrayorder;
+ dwarf_attr;
+ dwarf_attr_offset;
+ dwarf_attrlist;
+ dwarf_bitoffset;
+ dwarf_bitsize;
+ dwarf_bytesize;
+ dwarf_check_lineheader;
+ dwarf_child;
+ dwarf_cie_section_offset;
+ dwarf_compress_integer_block;
+ dwarf_create_cie_from_after_start;
+ dwarf_create_fde_from_after_start;
+ dwarf_CU_dieoffset_given_die;
+ dwarf_dealloc;
+ dwarf_dealloc_compressed_block;
+ dwarf_dealloc_uncompressed_block;
+ dwarf_def_macro;
+ dwarf_die_abbrev_code;
+ dwarf_die_CU_offset;
+ dwarf_die_CU_offset_range;
+ dwarf_die_link;
+ dwarf_diename;
+ dwarf_dieoffset;
+ dwarf_elf_init;
+ dwarf_elf_object_access_finish;
+ dwarf_elf_object_access_init;
+ dwarf_end_macro_file;
+ dwarf_errmsg;
+ dwarf_errno;
+ dwarf_expand_frame_instructions;
+ dwarf_expr_current_offset;
+ dwarf_expr_into_block;
+ dwarf_expr_reset;
+ dwarf_fde_cfa_offset;
+ dwarf_fde_cie_list_dealloc;
+ dwarf_fde_section_offset;
+ dwarf_find_macro_value_start;
+ dwarf_finish;
+ dwarf_formaddr;
+ dwarf_formblock;
+ dwarf_formexprloc;
+ dwarf_formflag;
+ dwarf_formref;
+ dwarf_formsdata;
+ dwarf_formsig8;
+ dwarf_formstring;
+ dwarf_formudata;
+ dwarf_free_line_table_prefix;
+ dwarf_func_cu_offset;
+ dwarf_func_die_offset;
+ dwarf_func_name_offsets;
+ dwarf_funcname;
+ dwarf_funcs_dealloc;
+ dwarf_get_abbrev;
+ dwarf_get_abbrev_children_flag;
+ dwarf_get_abbrev_code;
+ dwarf_get_abbrev_entry;
+ dwarf_get_abbrev_tag;
+ dwarf_get_ACCESS_name;
+ dwarf_get_ADDR_name;
+ dwarf_get_address_size;
+ dwarf_get_arange;
+ dwarf_get_arange_cu_header_offset;
+ dwarf_get_arange_info;
+ dwarf_get_arange_info_b;
+ dwarf_get_aranges;
+ dwarf_get_AT_name;
+ dwarf_get_ATCF_name;
+ dwarf_get_ATE_name;
+ dwarf_get_CC_name;
+ dwarf_get_CFA_name;
+ dwarf_get_children_name;
+ dwarf_get_CHILDREN_name;
+ dwarf_get_cie_augmentation_data;
+ dwarf_get_cie_index;
+ dwarf_get_cie_info;
+ dwarf_get_cie_of_fde;
+ dwarf_get_cu_die_offset;
+ dwarf_get_cu_die_offset_given_cu_header_offset;
+ dwarf_get_die_address_size;
+ dwarf_get_die_marker;
+ dwarf_get_die_markers;
+ dwarf_get_DS_name;
+ dwarf_get_DSC_name;
+ dwarf_get_EH_name;
+ dwarf_get_elf;
+ dwarf_get_END_name;
+ dwarf_get_fde_at_pc;
+ dwarf_get_fde_augmentation_data;
+ dwarf_get_fde_exception_info;
+ dwarf_get_fde_for_die;
+ dwarf_get_fde_info_for_all_regs;
+ dwarf_get_fde_info_for_all_regs3;
+ dwarf_get_fde_info_for_cfa_reg3;
+ dwarf_get_fde_info_for_reg;
+ dwarf_get_fde_info_for_reg3;
+ dwarf_get_fde_instr_bytes;
+ dwarf_get_fde_list;
+ dwarf_get_fde_list_eh;
+ dwarf_get_fde_n;
+ dwarf_get_fde_range;
+ dwarf_get_form_class;
+ dwarf_get_FORM_name;
+ dwarf_get_FRAME_name;
+ dwarf_get_funcs;
+ dwarf_get_globals;
+ dwarf_get_harmless_error_list;
+ dwarf_get_ID_name;
+ dwarf_get_INL_name;
+ dwarf_get_ISA_name;
+ dwarf_get_LANG_name;
+ dwarf_get_LNE_name;
+ dwarf_get_LNS_name;
+ dwarf_get_loclist_entry;
+ dwarf_get_MACINFO_name;
+ dwarf_get_macro_details;
+ dwarf_get_OP_name;
+ dwarf_get_ORD_name;
+ dwarf_get_pubtypes;
+ dwarf_get_ranges;
+ dwarf_get_ranges_a;
+ dwarf_get_relocation_info;
+ dwarf_get_relocation_info_count;
+ dwarf_get_section_bytes;
+ dwarf_get_section_max_offsets;
+ dwarf_get_str;
+ dwarf_get_string_attributes_count;
+ dwarf_get_string_attributes_info;
+ dwarf_get_TAG_name;
+ dwarf_get_types;
+ dwarf_get_vars;
+ dwarf_get_VIRTUALITY_name;
+ dwarf_get_VIS_name;
+ dwarf_get_weaks;
+ dwarf_global_cu_offset;
+ dwarf_global_die_offset;
+ dwarf_global_formref;
+ dwarf_global_name_offsets;
+ dwarf_globals_dealloc;
+ dwarf_globname;
+ dwarf_harmless_cleanout;
+ dwarf_harmless_init;
+ dwarf_hasattr;
+ dwarf_hasform;
+ dwarf_highpc;
+ dwarf_init;
+ dwarf_init_line_table_prefix;
+ dwarf_insert_fde_inst_bytes;
+ dwarf_insert_harmless_error;
+ dwarf_ld_sort_lines;
+ dwarf_line_srcfileno;
+ dwarf_lineaddr;
+ dwarf_linebeginstatement;
+ dwarf_lineblock;
+ dwarf_lineendsequence;
+ dwarf_lineno;
+ dwarf_lineoff;
+ dwarf_linesrc;
+ dwarf_lne_end_sequence;
+ dwarf_lne_set_address;
+ dwarf_loclist;
+ dwarf_loclist_from_expr;
+ dwarf_loclist_from_expr_a;
+ dwarf_loclist_n;
+ dwarf_lowpc;
+ dwarf_new_die;
+ dwarf_new_expr;
+ dwarf_new_fde;
+ dwarf_next_cu_header;
+ dwarf_next_cu_header_b;
+ dwarf_nextglob;
+ dwarf_object_finish;
+ dwarf_object_init;
+ dwarf_offdie;
+ dwarf_p_dealloc;
+ dwarf_print_lines;
+ dwarf_print_memory_stats;
+ dwarf_producer_finish;
+ dwarf_producer_init;
+ dwarf_producer_init_b;
+ dwarf_pubtype_cu_offset;
+ dwarf_pubtype_name_offsets;
+ dwarf_pubtype_type_die_offset;
+ dwarf_pubtypename;
+ dwarf_pubtypes_dealloc;
+ dwarf_ranges_dealloc;
+ dwarf_read_cie_fde_prefix;
+ dwarf_read_line_table_prefix;
+ dwarf_reset_section_bytes;
+ dwarf_set_frame_cfa_value;
+ dwarf_set_frame_rule_inital_value;
+ dwarf_set_frame_rule_initial_value;
+ dwarf_set_frame_rule_table_size;
+ dwarf_set_frame_same_value;
+ dwarf_set_frame_undefined_value;
+ dwarf_set_harmless_error_list_size;
+ dwarf_set_reloc_application;
+ dwarf_set_stringcheck;
+ dwarf_siblingof;
+ dwarf_srcfiles;
+ dwarf_srclang;
+ dwarf_srclines;
+ dwarf_srclines_dealloc;
+ dwarf_start_macro_file;
+ dwarf_tag;
+ dwarf_transform_to_disk_form;
+ dwarf_type_cu_offset;
+ dwarf_type_die_offset;
+ dwarf_type_name_offsets;
+ dwarf_typename;
+ dwarf_types_dealloc;
+ dwarf_uncompress_integer_block;
+ dwarf_undef_macro;
+ dwarf_var_cu_offset;
+ dwarf_var_die_offset;
+ dwarf_var_name_offsets;
+ dwarf_varname;
+ dwarf_vars_dealloc;
+ dwarf_vendor_ext;
+ dwarf_weak_cu_offset;
+ dwarf_weak_die_offset;
+ dwarf_weak_name_offsets;
+ dwarf_weakname;
+ dwarf_weaks_dealloc;
+ dwarf_whatattr;
+ dwarf_whatform;
+ dwarf_whatform_direct;
+ local:
+ *;
+};
diff --git a/usr/src/lib/libdwarf/common/pro_alloc.c b/usr/src/lib/libdwarf/common/pro_alloc.c
new file mode 100644
index 0000000000..1ca7806239
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_alloc.c
@@ -0,0 +1,188 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright 2002-2010 Sun Microsystems, 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
+
+*/
+
+
+
+#include "config.h"
+#include "pro_incl.h"
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif /* HAVE_STDLIB_H */
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif /* HAVE_STRING_H */
+#include <malloc.h>
+
+/*
+ When each block is allocated, there is a two-word structure
+ allocated at the beginning so the block can go on a list.
+ The address returned is the address *after* the two pointers
+ at the start. But this allows us to be given a pointer to
+ a generic block, and go backwards to find the list-node. Then
+ we can remove this block from it's list without the need to search
+ through a linked list in order to remove the node. It also allows
+ us to 'delete' a memory block without needing the dbg structure.
+ We still need the dbg structure on allocation so that we know which
+ linked list to add the block to.
+
+ Only the allocation of the dbg structure itself cannot use _dwarf_p_get_alloc.
+ That structure should be set up by hand, and the two list pointers
+ should be initialized to point at the node itself. That initializes
+ the doubly linked list.
+*/
+
+#define LIST_TO_BLOCK(lst) ((void*) (((char *)lst) + sizeof(memory_list_t)))
+#define BLOCK_TO_LIST(blk) ((memory_list_t*) (((char*)blk) - sizeof(memory_list_t)))
+
+
+/*
+ dbg should be NULL only when allocating dbg itself. In that
+ case we initialize it to an empty circular doubly-linked list.
+*/
+
+Dwarf_Ptr
+_dwarf_p_get_alloc(Dwarf_P_Debug dbg, Dwarf_Unsigned size)
+{
+ void *sp;
+ memory_list_t *lp = NULL;
+ memory_list_t *dbglp = NULL;
+ memory_list_t *nextblock = NULL;
+
+ /* alloc control struct and data block together for performance reasons */
+ lp = (memory_list_t *) malloc(size + sizeof(memory_list_t));
+ if (lp == NULL) {
+ /* should throw an error */
+ return NULL;
+ }
+
+ /* point to 'size' bytes just beyond lp struct */
+ sp = LIST_TO_BLOCK(lp);
+ memset(sp, 0, size);
+
+ if (dbg == NULL) {
+ lp->next = lp->prev = lp;
+ } else {
+ /* I always have to draw a picture to understand this part. */
+
+ dbglp = BLOCK_TO_LIST(dbg);
+ nextblock = dbglp->next;
+
+ /* Insert between dbglp and nextblock */
+ dbglp->next = lp;
+ lp->prev = dbglp;
+ lp->next = nextblock;
+ nextblock->prev = lp;
+ }
+
+ return sp;
+}
+
+/*
+ This routine is only here in case a caller of an older version of the
+ library is calling this for some reason.
+ We will clean up any stray blocks when the session is closed.
+ No need to remove this block. In theory the user might be
+ depending on the fact that we used to just 'free' this.
+ In theory they might also be
+ passing a block that they got from libdwarf. So we don't know if we
+ should try to remove this block from our global list. Safest just to
+ do nothing at this point.
+
+ !!!
+ This function is deprecated! Don't call it inside libdwarf or outside of it.
+ !!!
+*/
+
+void
+dwarf_p_dealloc(Dwarf_Small * ptr)
+{
+ return;
+}
+
+/*
+ The dbg structure is not needed here anymore.
+*/
+
+void
+_dwarf_p_dealloc(Dwarf_P_Debug dbg, Dwarf_Small * ptr) /* ARGSUSED */
+{
+ memory_list_t *lp;
+ lp = BLOCK_TO_LIST(ptr);
+
+ /*
+ Remove from a doubly linked, circular list.
+ Read carefully, use a white board if necessary.
+ If this is an empty list, the following statements are no-ops, and
+ will write to the same memory location they read from.
+ This should only happen when we deallocate the dbg structure itself.
+ */
+
+ lp->prev->next = lp->next;
+ lp->next->prev = lp->prev;
+
+ free((void*)lp);
+}
+
+
+/*
+ This routine deallocates all the nodes on the dbg list,
+ and then deallocates the dbg structure itself.
+*/
+
+void
+_dwarf_p_dealloc_all(Dwarf_P_Debug dbg)
+{
+ memory_list_t *dbglp;
+
+ if (dbg == NULL) {
+ /* should throw an error */
+ return;
+ }
+
+ dbglp = BLOCK_TO_LIST(dbg);
+ while (dbglp->next != dbglp) {
+ _dwarf_p_dealloc(dbg, LIST_TO_BLOCK(dbglp->next));
+ }
+ if (dbglp->next != dbglp ||
+ dbglp->prev != dbglp) {
+
+ /* should throw error */
+ /* For some reason we couldn't free all the blocks? */
+ return;
+ }
+ _dwarf_p_dealloc(NULL, (void*)dbg);
+}
+
diff --git a/usr/src/lib/libdwarf/common/pro_alloc.h b/usr/src/lib/libdwarf/common/pro_alloc.h
new file mode 100644
index 0000000000..b4da65325f
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_alloc.h
@@ -0,0 +1,42 @@
+/*
+
+ Copyright (C) 2000,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
+
+*/
+
+
+
+Dwarf_Ptr _dwarf_p_get_alloc(Dwarf_P_Debug, Dwarf_Unsigned);
+
+void _dwarf_p_dealloc(Dwarf_P_Debug dbg, Dwarf_Small * ptr);
+
+void _dwarf_p_dealloc_all(Dwarf_P_Debug dbg);
diff --git a/usr/src/lib/libdwarf/common/pro_arange.c b/usr/src/lib/libdwarf/common/pro_arange.c
new file mode 100644
index 0000000000..4e5c37795c
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_arange.c
@@ -0,0 +1,337 @@
+/*
+
+ Copyright (C) 2000,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
+
+*/
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_ELFACCESS_H
+#include <elfaccess.h>
+#endif
+#include "pro_incl.h"
+#include "pro_arange.h"
+#include "pro_section.h"
+#include "pro_reloc.h"
+
+
+
+/*
+ This function adds another address range
+ to the list of address ranges for the
+ given Dwarf_P_Debug. It returns 0 on error,
+ and 1 otherwise.
+*/
+Dwarf_Unsigned
+dwarf_add_arange(Dwarf_P_Debug dbg,
+ Dwarf_Addr begin_address,
+ Dwarf_Unsigned length,
+ Dwarf_Signed symbol_index, Dwarf_Error * error)
+{
+ return dwarf_add_arange_b(dbg, begin_address, length, symbol_index,
+ /* end_symbol_index */ 0,
+ /* offset_from_end_sym */ 0,
+ error);
+}
+
+/*
+ This function adds another address range
+ to the list of address ranges for the
+ given Dwarf_P_Debug. It returns 0 on error,
+ and 1 otherwise.
+*/
+Dwarf_Unsigned
+dwarf_add_arange_b(Dwarf_P_Debug dbg,
+ Dwarf_Addr begin_address,
+ Dwarf_Unsigned length,
+ Dwarf_Unsigned symbol_index,
+ Dwarf_Unsigned end_symbol_index,
+ Dwarf_Addr offset_from_end_sym, Dwarf_Error * error)
+{
+ Dwarf_P_Arange arange;
+
+ if (dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return (0);
+ }
+
+ arange = (Dwarf_P_Arange)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Arange_s));
+ if (arange == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (0);
+ }
+
+ arange->ag_begin_address = begin_address;
+ arange->ag_length = length;
+ arange->ag_symbol_index = symbol_index;
+ arange->ag_end_symbol_index = end_symbol_index;
+ arange->ag_end_symbol_offset = offset_from_end_sym;
+
+ if (dbg->de_arange == NULL)
+ dbg->de_arange = dbg->de_last_arange = arange;
+ else {
+ dbg->de_last_arange->ag_next = arange;
+ dbg->de_last_arange = arange;
+ }
+ dbg->de_arange_count++;
+
+ return (1);
+}
+
+
+int
+_dwarf_transform_arange_to_disk(Dwarf_P_Debug dbg, Dwarf_Error * error)
+{
+ /* Total num of bytes in .debug_aranges section. */
+ Dwarf_Unsigned arange_num_bytes;
+
+ /*
+ Adjustment to align the start of the actual address ranges on a
+ boundary aligned with twice the address size. */
+ Dwarf_Small remainder;
+
+ /* Total number of bytes excluding the length field. */
+ Dwarf_Unsigned adjusted_length;
+
+ /* Points to first byte of .debug_aranges buffer. */
+ Dwarf_Small *arange;
+
+ /* Fills in the .debug_aranges buffer. */
+ Dwarf_Small *arange_ptr;
+
+ /* Scans the list of address ranges provided by user. */
+ Dwarf_P_Arange given_arange;
+
+ /* Used to fill in 0. */
+ const Dwarf_Signed big_zero = 0;
+
+ int extension_word_size = dbg->de_64bit_extension ? 4 : 0;
+ int uword_size = dbg->de_offset_size;
+ int upointer_size = dbg->de_pointer_size;
+ int res;
+
+
+ /* ***** BEGIN CODE ***** */
+
+ /* Size of the .debug_aranges section header. */
+ arange_num_bytes = extension_word_size + uword_size + /* Size
+ of
+ length
+ field.
+ */
+ sizeof(Dwarf_Half) + /* Size of version field. */
+ uword_size + /* Size of .debug_info offset. */
+ sizeof(Dwarf_Small) + /* Size of address size field. */
+ sizeof(Dwarf_Small); /* Size of segment size field. */
+
+ /*
+ Adjust the size so that the set of aranges begins on a boundary
+ that aligned with twice the address size. This is a Libdwarf
+ requirement. */
+ remainder = arange_num_bytes % (2 * upointer_size);
+ if (remainder != 0)
+ arange_num_bytes += (2 * upointer_size) - remainder;
+
+
+ /* Add the bytes for the actual address ranges. */
+ arange_num_bytes += upointer_size * 2 * (dbg->de_arange_count + 1);
+
+ GET_CHUNK(dbg, dbg->de_elf_sects[DEBUG_ARANGES],
+ arange, (unsigned long) arange_num_bytes, error);
+ arange_ptr = arange;
+ if (arange == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (0);
+ }
+ if (extension_word_size) {
+ Dwarf_Word x = DISTINGUISHED_VALUE;
+
+ WRITE_UNALIGNED(dbg, (void *) arange_ptr,
+ (const void *) &x,
+ sizeof(x), extension_word_size);
+ arange_ptr += extension_word_size;
+ }
+
+ /* Write the total length of .debug_aranges section. */
+ adjusted_length = arange_num_bytes - uword_size
+ - extension_word_size;
+ {
+ Dwarf_Unsigned du = adjusted_length;
+
+ WRITE_UNALIGNED(dbg, (void *) arange_ptr,
+ (const void *) &du, sizeof(du), uword_size);
+ arange_ptr += uword_size;
+ }
+
+ /* Write the version as 2 bytes. */
+ {
+ Dwarf_Half verstamp = CURRENT_VERSION_STAMP;
+
+ WRITE_UNALIGNED(dbg, (void *) arange_ptr,
+ (const void *) &verstamp,
+ sizeof(verstamp), sizeof(Dwarf_Half));
+ arange_ptr += sizeof(Dwarf_Half);
+ }
+
+
+ /* Write the .debug_info offset. This is always 0. */
+ WRITE_UNALIGNED(dbg, (void *) arange_ptr,
+ (const void *) &big_zero,
+ sizeof(big_zero), uword_size);
+ arange_ptr += uword_size;
+
+ {
+ unsigned long count = dbg->de_arange_count + 1;
+ int res;
+
+ if (dbg->de_reloc_pair) {
+ count = (3 * dbg->de_arange_count) + 1;
+ }
+ /* the following is a small optimization: not needed for
+ correctness */
+ res = _dwarf_pro_pre_alloc_n_reloc_slots(dbg,
+ DEBUG_ARANGES, count);
+ if (res != DW_DLV_OK) {
+ {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (0);
+ }
+ }
+ }
+
+ /* reloc for .debug_info */
+ res = dbg->de_reloc_name(dbg,
+ DEBUG_ARANGES,
+ extension_word_size +
+ uword_size + sizeof(Dwarf_Half),
+ dbg->de_sect_name_idx[DEBUG_INFO],
+ dwarf_drt_data_reloc, uword_size);
+
+ /* Write the size of addresses. */
+ *arange_ptr = dbg->de_pointer_size;
+ arange_ptr++;
+
+ /*
+ Write the size of segment addresses. This is zero for MIPS
+ architectures. */
+ *arange_ptr = 0;
+ arange_ptr++;
+
+ /*
+ Skip over the padding to align the start of the actual address
+ ranges to twice the address size. */
+ if (remainder != 0)
+ arange_ptr += (2 * upointer_size) - remainder;
+
+
+
+
+
+ /* The arange address, length are pointer-size fields of the target
+ machine. */
+ for (given_arange = dbg->de_arange; given_arange != NULL;
+ given_arange = given_arange->ag_next) {
+
+ /* Write relocation record for beginning of address range. */
+ res = dbg->de_reloc_name(dbg, DEBUG_ARANGES, arange_ptr - arange, /* r_offset
+ */
+ (long) given_arange->ag_symbol_index,
+ dwarf_drt_data_reloc, upointer_size);
+ if (res != DW_DLV_OK) {
+ {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (0);
+ }
+ }
+
+ /* Copy beginning address of range. */
+ WRITE_UNALIGNED(dbg, (void *) arange_ptr,
+ (const void *) &given_arange->ag_begin_address,
+ sizeof(given_arange->ag_begin_address),
+ upointer_size);
+ arange_ptr += upointer_size;
+
+ if (dbg->de_reloc_pair &&
+ given_arange->ag_end_symbol_index != 0 &&
+ given_arange->ag_length == 0) {
+ /* symbolic reloc, need reloc for length What if we really
+ know the length? If so, should use the other part of
+ 'if'. */
+ Dwarf_Unsigned val;
+
+ res = dbg->de_reloc_pair(dbg, DEBUG_ARANGES, arange_ptr - arange, /* r_offset
+ */
+ given_arange->ag_symbol_index,
+ given_arange->ag_end_symbol_index,
+ dwarf_drt_first_of_length_pair,
+ upointer_size);
+ if (res != DW_DLV_OK) {
+ {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (0);
+ }
+ }
+
+ /* arrange pre-calc so assem text can do .word end - begin
+ + val (gets val from stream) */
+ val = given_arange->ag_end_symbol_offset -
+ given_arange->ag_begin_address;
+ WRITE_UNALIGNED(dbg, (void *) arange_ptr,
+ (const void *) &val,
+ sizeof(val), upointer_size);
+ arange_ptr += upointer_size;
+
+ } else {
+ /* plain old length to copy, no relocation at all */
+ WRITE_UNALIGNED(dbg, (void *) arange_ptr,
+ (const void *) &given_arange->ag_length,
+ sizeof(given_arange->ag_length),
+ upointer_size);
+ arange_ptr += upointer_size;
+ }
+ }
+
+ WRITE_UNALIGNED(dbg, (void *) arange_ptr,
+ (const void *) &big_zero,
+ sizeof(big_zero), upointer_size);
+
+ arange_ptr += upointer_size;
+ WRITE_UNALIGNED(dbg, (void *) arange_ptr,
+ (const void *) &big_zero,
+ sizeof(big_zero), upointer_size);
+ return (int) dbg->de_n_debug_sect;
+}
diff --git a/usr/src/lib/libdwarf/common/pro_arange.h b/usr/src/lib/libdwarf/common/pro_arange.h
new file mode 100644
index 0000000000..f0e7e84dff
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_arange.h
@@ -0,0 +1,62 @@
+/*
+
+ Copyright (C) 2000,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
+
+*/
+
+
+/*
+ If ag_end_symbol_index is zero,
+ ag_length must be known and non-zero.
+
+
+ Deals with length being known costant or fr
+ assembler output, not known.
+
+*/
+
+struct Dwarf_P_Arange_s {
+ Dwarf_Addr ag_begin_address; /* known address or for
+ symbolic assem output,
+ offset of symbol */
+ Dwarf_Addr ag_length; /* zero or address or offset */
+ Dwarf_Unsigned ag_symbol_index;
+
+ Dwarf_P_Arange ag_next;
+
+ Dwarf_Unsigned ag_end_symbol_index; /* zero or index/id of end
+ symbol */
+ Dwarf_Addr ag_end_symbol_offset; /* known address or for
+ symbolic assem output,
+ offset of end symbol */
+
+};
diff --git a/usr/src/lib/libdwarf/common/pro_die.c b/usr/src/lib/libdwarf/common/pro_die.c
new file mode 100644
index 0000000000..948b641146
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_die.c
@@ -0,0 +1,442 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright 2002-2010 Sun Microsystems, 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
+
+*/
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#include <stdio.h>
+#include <string.h>
+#include "pro_incl.h"
+#include "pro_die.h"
+
+#ifndef R_MIPS_NONE
+#define R_MIPS_NONE 0
+#endif
+
+/* adds an attribute to a die */
+void _dwarf_pro_add_at_to_die(Dwarf_P_Die die, Dwarf_P_Attribute attr);
+
+/*----------------------------------------------------------------------------
+ This function creates a new die.
+ tag: tag of the new die to be created
+ parent,child,left,right: specify neighbors of the new die. Only
+ one of these may be non-null
+-----------------------------------------------------------------------------*/
+Dwarf_P_Die
+dwarf_new_die(Dwarf_P_Debug dbg,
+ Dwarf_Tag tag,
+ Dwarf_P_Die parent,
+ Dwarf_P_Die child,
+ Dwarf_P_Die left, Dwarf_P_Die right, Dwarf_Error * error)
+{
+ Dwarf_P_Die ret_die = 0;
+
+ Dwarf_P_Die new_die = (Dwarf_P_Die)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Die_s));
+ if (new_die == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_DIE_ALLOC,
+ (Dwarf_P_Die) DW_DLV_BADADDR);
+ }
+ new_die->di_parent = NULL;
+ new_die->di_left = NULL;
+ new_die->di_right = NULL;
+ new_die->di_child = NULL;
+ new_die->di_last_child = NULL;
+ new_die->di_tag = tag;
+ new_die->di_dbg = dbg;
+ new_die->di_marker = 0;
+ ret_die =
+ dwarf_die_link(new_die, parent, child, left, right, error);
+ return ret_die;
+}
+
+/*----------------------------------------------------------------------------
+ This function links up a die to specified neighbors
+ parent,child,left,right: specify neighbors of the new die. Only
+ one of these may be non-null
+-----------------------------------------------------------------------------*/
+Dwarf_P_Die
+dwarf_die_link(Dwarf_P_Die new_die,
+ Dwarf_P_Die parent,
+ Dwarf_P_Die child,
+ Dwarf_P_Die left, Dwarf_P_Die right, Dwarf_Error * error)
+{
+ /* Count the # of non null neighbors. */
+ int n_nulls = 0;
+
+ if (parent != NULL) {
+ n_nulls++;
+ if (new_die->di_parent != NULL) {
+ DWARF_P_DBG_ERROR(NULL, DW_DLE_LINK_LOOP,
+ (Dwarf_P_Die) DW_DLV_BADADDR);
+ }
+ new_die->di_parent = parent;
+ if (parent->di_child) {
+
+ /* di_last_child identifies the last sibling, the
+ die we want to attach new_die to. */
+ /* ASSERT: if di_child is set so is di_last_child. */
+ Dwarf_P_Die former_lastchild = parent->di_last_child;
+ parent->di_last_child = new_die;
+ /* Attach to the new die to end of the sibling list. */
+ former_lastchild->di_right = new_die;
+ new_die->di_left = former_lastchild;
+ } else {
+ parent->di_child = new_die;
+ parent->di_last_child = new_die;
+ }
+ }
+ if (child != NULL) {
+ n_nulls++;
+ new_die->di_child = child;
+ new_die->di_last_child = child;
+ if (child->di_parent) {
+ DWARF_P_DBG_ERROR(NULL, DW_DLE_PARENT_EXISTS,
+ (Dwarf_P_Die) DW_DLV_BADADDR);
+ } else {
+ child->di_parent = new_die;
+ }
+ }
+ if (left != NULL) {
+ n_nulls++;
+ new_die->di_left = left;
+ if (left->di_right) {
+ /* There's already a right sibling of left,
+ insert the new die in the list. */
+ new_die->di_right = left->di_right;
+ left->di_right->di_left = new_die;
+ }
+ left->di_right = new_die;
+ if (new_die->di_parent) {
+ DWARF_P_DBG_ERROR(NULL, DW_DLE_PARENT_EXISTS,
+ (Dwarf_P_Die) DW_DLV_BADADDR);
+ } else {
+ new_die->di_parent = left->di_parent;
+ }
+ }
+ if (right != NULL) {
+ n_nulls++;
+ new_die->di_right = right;
+ if (right->di_left) {
+ /* There is already a left sibling of the right die,
+ insert the new die in the list. */
+ new_die->di_left = right->di_left;
+ right->di_left->di_right = new_die;
+ }
+ right->di_left = new_die;
+ if (new_die->di_parent) {
+ DWARF_P_DBG_ERROR(NULL, DW_DLE_PARENT_EXISTS,
+ (Dwarf_P_Die) DW_DLV_BADADDR);
+ } else {
+ new_die->di_parent = right->di_parent;
+ }
+ }
+ if (n_nulls > 1) {
+ /* Multiple neighbors! error! */
+ DWARF_P_DBG_ERROR(NULL, DW_DLE_EXTRA_NEIGHBORS,
+ (Dwarf_P_Die) DW_DLV_BADADDR);
+ }
+ return new_die;
+
+}
+
+Dwarf_Unsigned
+dwarf_add_die_marker(Dwarf_P_Debug dbg,
+ Dwarf_P_Die die,
+ Dwarf_Unsigned marker,
+ Dwarf_Error * error)
+{
+ if (die == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_DIE_NULL, DW_DLV_NOCOUNT);
+ }
+ die->di_marker = marker;
+ return 0;
+}
+
+
+Dwarf_Unsigned
+dwarf_get_die_marker(Dwarf_P_Debug dbg,
+ Dwarf_P_Die die,
+ Dwarf_Unsigned * marker,
+ Dwarf_Error * error)
+{
+ if (die == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_DIE_NULL, DW_DLV_NOCOUNT);
+ }
+ *marker = die->di_marker;
+ return 0;
+}
+
+
+/*----------------------------------------------------------------------------
+ This function adds a die to dbg struct. It should be called using
+ the root of all the dies.
+-----------------------------------------------------------------------------*/
+Dwarf_Unsigned
+dwarf_add_die_to_debug(Dwarf_P_Debug dbg,
+ Dwarf_P_Die first_die, Dwarf_Error * error)
+{
+ if (first_die == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_DIE_NULL, DW_DLV_NOCOUNT);
+ }
+ if (first_die->di_tag != DW_TAG_compile_unit) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_WRONG_TAG, DW_DLV_NOCOUNT);
+ }
+ dbg->de_dies = first_die;
+ return 0;
+}
+
+int
+_dwarf_pro_add_AT_stmt_list(Dwarf_P_Debug dbg,
+ Dwarf_P_Die first_die, Dwarf_Error * error)
+{
+ Dwarf_P_Attribute new_attr;
+ int uwordb_size = dbg->de_offset_size;
+
+ /* Add AT_stmt_list attribute */
+ new_attr = (Dwarf_P_Attribute)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Attribute_s));
+ if (new_attr == NULL) {
+ DWARF_P_DBG_ERROR(NULL, DW_DLE_ATTR_ALLOC, DW_DLV_NOCOUNT);
+ }
+
+ new_attr->ar_attribute = DW_AT_stmt_list;
+ new_attr->ar_attribute_form = dbg->de_ar_data_attribute_form;
+ new_attr->ar_rel_type = dbg->de_offset_reloc;
+
+ new_attr->ar_nbytes = uwordb_size;
+ new_attr->ar_next = NULL;
+ new_attr->ar_reloc_len = uwordb_size;
+ new_attr->ar_data = (char *)
+ _dwarf_p_get_alloc(dbg, uwordb_size);
+ if (new_attr->ar_data == NULL) {
+ DWARF_P_DBG_ERROR(NULL, DW_DLE_ADDR_ALLOC, DW_DLV_NOCOUNT);
+ }
+ {
+ Dwarf_Unsigned du = 0;
+
+ WRITE_UNALIGNED(dbg, (void *) new_attr->ar_data,
+ (const void *) &du, sizeof(du), uwordb_size);
+ }
+
+ _dwarf_pro_add_at_to_die(first_die, new_attr);
+ return 0;
+}
+
+/*-----------------------------------------------------------------------------
+ Add AT_name attribute to die
+------------------------------------------------------------------------------*/
+Dwarf_P_Attribute
+dwarf_add_AT_name(Dwarf_P_Die die, char *name, Dwarf_Error * error)
+{
+ Dwarf_P_Attribute new_attr;
+
+ if (die == NULL) {
+ DWARF_P_DBG_ERROR(NULL, DW_DLE_DIE_NULL,
+ (Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ new_attr = (Dwarf_P_Attribute)
+ _dwarf_p_get_alloc(die->di_dbg,sizeof(struct Dwarf_P_Attribute_s));
+ if (new_attr == NULL) {
+ DWARF_P_DBG_ERROR(NULL, DW_DLE_ATTR_ALLOC,
+ (Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ /* fill in the information */
+ new_attr->ar_attribute = DW_AT_name;
+ /* assume that form is string, no debug_str yet */
+ new_attr->ar_attribute_form = DW_FORM_string;
+ new_attr->ar_nbytes = strlen(name) + 1;
+ new_attr->ar_next = NULL;
+ new_attr->ar_reloc_len = 0;
+ new_attr->ar_data = (char *)
+ _dwarf_p_get_alloc(die->di_dbg, strlen(name)+1);
+ if (new_attr->ar_data == NULL) {
+ DWARF_P_DBG_ERROR(NULL, DW_DLE_STRING_ALLOC,
+ (Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ strcpy(new_attr->ar_data, name);
+
+ new_attr->ar_rel_type = R_MIPS_NONE;
+
+ /* add attribute to the die */
+ _dwarf_pro_add_at_to_die(die, new_attr);
+ return new_attr;
+}
+
+
+/*-----------------------------------------------------------------------------
+ Add AT_comp_dir attribute to die
+------------------------------------------------------------------------------*/
+Dwarf_P_Attribute
+dwarf_add_AT_comp_dir(Dwarf_P_Die ownerdie,
+ char *current_working_directory,
+ Dwarf_Error * error)
+{
+ Dwarf_P_Attribute new_attr;
+
+ if (ownerdie == NULL) {
+ DWARF_P_DBG_ERROR(NULL, DW_DLE_DIE_NULL,
+ (Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ new_attr = (Dwarf_P_Attribute)
+ _dwarf_p_get_alloc(ownerdie->di_dbg,
+ sizeof(struct Dwarf_P_Attribute_s));
+ if (new_attr == NULL) {
+ DWARF_P_DBG_ERROR(NULL, DW_DLE_ATTR_ALLOC,
+ (Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ /* fill in the information */
+ new_attr->ar_attribute = DW_AT_comp_dir;
+ /* assume that form is string, no debug_str yet */
+ new_attr->ar_attribute_form = DW_FORM_string;
+ new_attr->ar_nbytes = strlen(current_working_directory) + 1;
+ new_attr->ar_next = NULL;
+ new_attr->ar_reloc_len = 0;
+ new_attr->ar_data = (char *)
+ _dwarf_p_get_alloc(ownerdie->di_dbg,
+ strlen(current_working_directory)+1);
+ if (new_attr->ar_data == NULL) {
+ DWARF_P_DBG_ERROR(NULL, DW_DLE_STRING_ALLOC,
+ (Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ strcpy(new_attr->ar_data, current_working_directory);
+
+ new_attr->ar_rel_type = R_MIPS_NONE;
+
+ /* add attribute to the die */
+ _dwarf_pro_add_at_to_die(ownerdie, new_attr);
+ return new_attr;
+}
+
+int
+_dwarf_pro_add_AT_fde(Dwarf_P_Debug dbg,
+ Dwarf_P_Die die,
+ Dwarf_Unsigned offset, Dwarf_Error * error)
+{
+ Dwarf_P_Attribute new_attr;
+ int uwordb_size = dbg->de_offset_size;
+
+ if (die == NULL) {
+ DWARF_P_DBG_ERROR(NULL, DW_DLE_DIE_NULL, -1);
+ }
+ new_attr = (Dwarf_P_Attribute)
+ _dwarf_p_get_alloc(dbg,sizeof(struct Dwarf_P_Attribute_s));
+ if (new_attr == NULL) {
+ DWARF_P_DBG_ERROR(NULL, DW_DLE_ATTR_ALLOC, -1);
+ }
+
+ /* fill in the information */
+ new_attr->ar_attribute = DW_AT_MIPS_fde;
+ new_attr->ar_attribute_form = dbg->de_ar_data_attribute_form;;
+ new_attr->ar_rel_type = dbg->de_offset_reloc;
+ new_attr->ar_nbytes = uwordb_size;
+ new_attr->ar_next = NULL;
+ new_attr->ar_reloc_len = uwordb_size;
+ new_attr->ar_data = (char *)
+ _dwarf_p_get_alloc(dbg, uwordb_size);
+ if (new_attr->ar_data == NULL) {
+ DWARF_P_DBG_ERROR(NULL, DW_DLE_ADDR_ALLOC, DW_DLV_NOCOUNT);
+ }
+ {
+ Dwarf_Unsigned du = offset;
+
+ WRITE_UNALIGNED(dbg, (void *) new_attr->ar_data,
+ (const void *) &du, sizeof(du), uwordb_size);
+ }
+
+ _dwarf_pro_add_at_to_die(die, new_attr);
+
+ return 0;
+}
+
+int
+_dwarf_pro_add_AT_macro_info(Dwarf_P_Debug dbg,
+ Dwarf_P_Die die,
+ Dwarf_Unsigned offset, Dwarf_Error * error)
+{
+ Dwarf_P_Attribute new_attr;
+ int uwordb_size = dbg->de_offset_size;
+
+ if (die == NULL) {
+ DWARF_P_DBG_ERROR(NULL, DW_DLE_DIE_NULL, -1);
+ }
+ new_attr = (Dwarf_P_Attribute)
+ _dwarf_p_get_alloc(dbg,sizeof(struct Dwarf_P_Attribute_s));
+ if (new_attr == NULL) {
+ DWARF_P_DBG_ERROR(NULL, DW_DLE_ATTR_ALLOC, -1);
+ }
+
+ /* fill in the information */
+ new_attr->ar_attribute = DW_AT_macro_info;
+ new_attr->ar_attribute_form = dbg->de_ar_data_attribute_form;
+ new_attr->ar_rel_type = dbg->de_offset_reloc;
+
+ new_attr->ar_nbytes = uwordb_size;
+ new_attr->ar_next = NULL;
+ new_attr->ar_reloc_len = uwordb_size;
+ new_attr->ar_data = (char *)
+ _dwarf_p_get_alloc(dbg, uwordb_size);
+ if (new_attr->ar_data == NULL) {
+ DWARF_P_DBG_ERROR(NULL, DW_DLE_ADDR_ALLOC, DW_DLV_NOCOUNT);
+ }
+ {
+ Dwarf_Unsigned du = offset;
+
+ WRITE_UNALIGNED(dbg, (void *) new_attr->ar_data,
+ (const void *) &du, sizeof(du), uwordb_size);
+ }
+
+ _dwarf_pro_add_at_to_die(die, new_attr);
+
+ return 0;
+}
+
+
+void
+_dwarf_pro_add_at_to_die(Dwarf_P_Die die, Dwarf_P_Attribute attr)
+{
+ if (die->di_last_attr) {
+ die->di_last_attr->ar_next = attr;
+ die->di_last_attr = attr;
+ die->di_n_attr++;
+ } else {
+ die->di_n_attr = 1;
+ die->di_attrs = die->di_last_attr = attr;
+ }
+}
diff --git a/usr/src/lib/libdwarf/common/pro_die.h b/usr/src/lib/libdwarf/common/pro_die.h
new file mode 100644
index 0000000000..01c00e79bd
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_die.h
@@ -0,0 +1,68 @@
+/*
+
+ Copyright (C) 2000,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 struct holds the abbreviation table, before they are written
+ on disk. Holds a linked list of abbreviations, each consisting of
+ a bitmap for attributes and a bitmap for forms
+*/
+typedef struct Dwarf_P_Abbrev_s *Dwarf_P_Abbrev;
+
+struct Dwarf_P_Abbrev_s {
+ Dwarf_Unsigned abb_idx; /* index of abbreviation */
+ Dwarf_Tag abb_tag; /* tag of die */
+ Dwarf_Ubyte abb_children; /* if children are present */
+ Dwarf_ufixed *abb_attrs; /* holds names of attrs */
+ Dwarf_ufixed *abb_forms; /* forms of attributes */
+ int abb_n_attr; /* num of attrs = # of forms */
+ Dwarf_P_Abbrev abb_next;
+};
+
+/* used in pro_section.c */
+
+int _dwarf_pro_add_AT_fde(Dwarf_P_Debug dbg, Dwarf_P_Die die,
+ Dwarf_Unsigned offset, Dwarf_Error * error);
+
+int _dwarf_pro_add_AT_stmt_list(Dwarf_P_Debug dbg,
+ Dwarf_P_Die first_die,
+ Dwarf_Error * error);
+
+int _dwarf_pro_add_AT_macro_info(Dwarf_P_Debug dbg,
+ Dwarf_P_Die first_die,
+ Dwarf_Unsigned offset,
+ Dwarf_Error * error);
diff --git a/usr/src/lib/libdwarf/common/pro_encode_nm.c b/usr/src/lib/libdwarf/common/pro_encode_nm.c
new file mode 100644
index 0000000000..d6215dc56b
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_encode_nm.c
@@ -0,0 +1,123 @@
+/*
+
+ Copyright (C) 2000,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
+
+*/
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#include <string.h>
+#include "pro_incl.h"
+
+#define MORE_BYTES 0x80
+#define DATA_MASK 0x7f
+#define DIGIT_WIDTH 7
+#define SIGN_BIT 0x40
+
+
+/*-------------------------------------------------------------
+ Encode val as a leb128. This encodes it as an unsigned
+ number.
+---------------------------------------------------------------*/
+/* return DW_DLV_ERROR or DW_DLV_OK.
+** space to write leb number is provided by caller, with caller
+** passing length.
+** number of bytes used returned thru nbytes arg
+*/
+int
+_dwarf_pro_encode_leb128_nm(Dwarf_Unsigned val, int *nbytes,
+ char *space, int splen)
+{
+ char *a;
+ char *end = space + splen;
+
+ a = space;
+ do {
+ unsigned char uc;
+
+ if (a >= end) {
+ return DW_DLV_ERROR;
+ }
+ uc = val & DATA_MASK;
+ val >>= DIGIT_WIDTH;
+ if (val != 0) {
+ uc |= MORE_BYTES;
+ }
+ *a = uc;
+ a++;
+ } while (val);
+ *nbytes = a - space;
+ return DW_DLV_OK;
+}
+
+/* return DW_DLV_ERROR or DW_DLV_OK.
+** space to write leb number is provided by caller, with caller
+** passing length.
+** number of bytes used returned thru nbytes arg
+** encodes a signed number.
+*/
+int
+_dwarf_pro_encode_signed_leb128_nm(Dwarf_Signed value, int *nbytes,
+ char *space, int splen)
+{
+ char *str;
+ Dwarf_Signed sign = -(value < 0);
+ int more = 1;
+ char *end = space + splen;
+
+ str = space;
+
+ do {
+ unsigned char byte = value & DATA_MASK;
+
+ value >>= DIGIT_WIDTH;
+
+ if (str >= end) {
+ return DW_DLV_ERROR;
+ }
+ /*
+ * Remaining chunks would just contain the sign bit, and this chunk
+ * has already captured at least one sign bit.
+ */
+ if (value == sign && ((byte & SIGN_BIT) == (sign & SIGN_BIT))) {
+ more = 0;
+ } else {
+ byte |= MORE_BYTES;
+ }
+ *str = byte;
+ str++;
+ } while (more);
+ *nbytes = str - space;
+ return DW_DLV_OK;
+}
diff --git a/usr/src/lib/libdwarf/common/pro_encode_nm.h b/usr/src/lib/libdwarf/common/pro_encode_nm.h
new file mode 100644
index 0000000000..d08e4d5148
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_encode_nm.h
@@ -0,0 +1,48 @@
+/*
+
+ Copyright (C) 2000,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
+
+*/
+
+
+
+/* Bytes needed to encode a number.
+ Not a tight bound, just a reasonable bound.
+*/
+#define ENCODE_SPACE_NEEDED (2*sizeof(Dwarf_Unsigned))
+
+
+int _dwarf_pro_encode_leb128_nm(Dwarf_Unsigned val, int *nbytes,
+ char *space, int splen);
+
+int _dwarf_pro_encode_signed_leb128_nm(Dwarf_Signed value, int *nbytes,
+ char *space, int splen);
diff --git a/usr/src/lib/libdwarf/common/pro_error.c b/usr/src/lib/libdwarf/common/pro_error.c
new file mode 100644
index 0000000000..d408a391e2
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_error.c
@@ -0,0 +1,97 @@
+/*
+
+ 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
+
+*/
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#ifdef HAVE_ELF_H
+#include <elf.h>
+#endif
+
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include "pro_incl.h"
+
+extern char *_dwarf_errmsgs[];
+
+/*
+ This function performs error handling as described in the
+ libdwarf consumer document section 3. Dbg is the Dwarf_P_debug
+ structure being processed. Error is a pointer to the pointer
+ to the error descriptor that will be returned. Errval is an
+ error code listed in dwarf_error.h.
+*/
+void
+_dwarf_p_error(Dwarf_P_Debug dbg,
+ Dwarf_Error * error, Dwarf_Word errval)
+{
+ Dwarf_Error errptr;
+
+ /* Allow NULL dbg on entry, since sometimes that can happen and we
+ want to report the upper-level error, not this one. */
+ if ((Dwarf_Sword) errval < 0)
+ printf("ERROR VALUE: %ld - %s\n",
+ (long) errval, _dwarf_errmsgs[-errval - 1]);
+ if (error != NULL) {
+ errptr = (Dwarf_Error)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_Error_s));
+ if (errptr == NULL) {
+ fprintf(stderr,
+ "Could not allocate Dwarf_Error structure\n");
+ abort();
+ }
+ errptr->er_errval = (Dwarf_Sword) errval;
+ *error = errptr;
+ return;
+ }
+
+ if (dbg != NULL && dbg->de_errhand != NULL) {
+ errptr = (Dwarf_Error)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_Error_s));
+ if (errptr == NULL) {
+ fprintf(stderr,
+ "Could not allocate Dwarf_Error structure\n");
+ abort();
+ }
+ errptr->er_errval = (Dwarf_Sword) errval;
+ dbg->de_errhand(errptr, dbg->de_errarg);
+ return;
+ }
+
+ abort();
+}
diff --git a/usr/src/lib/libdwarf/common/pro_error.h b/usr/src/lib/libdwarf/common/pro_error.h
new file mode 100644
index 0000000000..c37035301b
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_error.h
@@ -0,0 +1,52 @@
+/*
+
+ Copyright (C) 2000,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
+
+*/
+
+
+
+
+/* Handle error passing in the name of the Dwarf_P_Debug
+ User must supply {} around the macro.
+ Putting the {} here leads to macro uses that don't look like C.
+ The error argument to dwarf_error is hard coded here as 'error'
+*/
+#define DWARF_P_DBG_ERROR(dbg,errval,retval) \
+ _dwarf_p_error(dbg,error,errval); return(retval);
+
+struct Dwarf_Error_s {
+ Dwarf_Sword er_errval;
+};
+
+void _dwarf_p_error(Dwarf_P_Debug dbg, Dwarf_Error * error,
+ Dwarf_Word errval);
diff --git a/usr/src/lib/libdwarf/common/pro_expr.c b/usr/src/lib/libdwarf/common/pro_expr.c
new file mode 100644
index 0000000000..4c701748a6
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_expr.c
@@ -0,0 +1,597 @@
+/*
+
+ Copyright (C) 2000,2004,2006 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright 2007-2010 Sun Microsystems, 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
+
+*/
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include "pro_incl.h"
+#include "pro_expr.h"
+
+/*
+ This function creates a new expression
+ struct that can be used to build up a
+ location expression.
+*/
+Dwarf_P_Expr
+dwarf_new_expr(Dwarf_P_Debug dbg, Dwarf_Error * error)
+{
+ Dwarf_P_Expr ret_expr;
+
+ if (dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return (NULL);
+ }
+
+ ret_expr = (Dwarf_P_Expr)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Expr_s));
+ if (ret_expr == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (NULL);
+ }
+
+ ret_expr->ex_dbg = dbg;
+
+ return (ret_expr);
+}
+
+
+Dwarf_Unsigned
+dwarf_add_expr_gen(Dwarf_P_Expr expr,
+ Dwarf_Small opcode,
+ Dwarf_Unsigned val1,
+ Dwarf_Unsigned val2, Dwarf_Error * error)
+{
+ char encode_buffer[2 * ENCODE_SPACE_NEEDED]; /* 2* since
+ used to
+ concatenate
+ 2 leb's
+ below */
+ char encode_buffer2[ENCODE_SPACE_NEEDED];
+ int res;
+ Dwarf_P_Debug dbg = expr->ex_dbg;
+
+ /*
+ Give the buffer where the operands are first going to be
+ assembled the largest alignment. */
+ Dwarf_Unsigned operand_buffer[10];
+
+ /*
+ Size of the byte stream buffer that needs to be memcpy-ed. */
+ int operand_size;
+
+ /*
+ Points to the byte stream for the first operand, and finally to
+ the buffer that is memcp-ed into the Dwarf_P_Expr_s struct. */
+ Dwarf_Small *operand;
+
+ /* Size of the byte stream for second operand. */
+ int operand2_size;
+
+ /* Points to next byte to be written in Dwarf_P_Expr_s struct. */
+ Dwarf_Small *next_byte_ptr;
+
+ /* Offset past the last byte written into Dwarf_P_Expr_s. */
+ int next_byte_offset;
+
+ /* ***** BEGIN CODE ***** */
+
+ if (expr == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_EXPR_NULL);
+ return (DW_DLV_NOCOUNT);
+ }
+
+ if (expr->ex_dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_NOCOUNT);
+ }
+
+ operand = NULL;
+ operand_size = 0;
+
+ switch (opcode) {
+ case DW_OP_reg0:
+ case DW_OP_reg1:
+ case DW_OP_reg2:
+ case DW_OP_reg3:
+ case DW_OP_reg4:
+ case DW_OP_reg5:
+ case DW_OP_reg6:
+ case DW_OP_reg7:
+ case DW_OP_reg8:
+ case DW_OP_reg9:
+ case DW_OP_reg10:
+ case DW_OP_reg11:
+ case DW_OP_reg12:
+ case DW_OP_reg13:
+ case DW_OP_reg14:
+ case DW_OP_reg15:
+ case DW_OP_reg16:
+ case DW_OP_reg17:
+ case DW_OP_reg18:
+ case DW_OP_reg19:
+ case DW_OP_reg20:
+ case DW_OP_reg21:
+ case DW_OP_reg22:
+ case DW_OP_reg23:
+ case DW_OP_reg24:
+ case DW_OP_reg25:
+ case DW_OP_reg26:
+ case DW_OP_reg27:
+ case DW_OP_reg28:
+ case DW_OP_reg29:
+ case DW_OP_reg30:
+ case DW_OP_reg31:
+ break;
+
+ case DW_OP_breg0:
+ case DW_OP_breg1:
+ case DW_OP_breg2:
+ case DW_OP_breg3:
+ case DW_OP_breg4:
+ case DW_OP_breg5:
+ case DW_OP_breg6:
+ case DW_OP_breg7:
+ case DW_OP_breg8:
+ case DW_OP_breg9:
+ case DW_OP_breg10:
+ case DW_OP_breg11:
+ case DW_OP_breg12:
+ case DW_OP_breg13:
+ case DW_OP_breg14:
+ case DW_OP_breg15:
+ case DW_OP_breg16:
+ case DW_OP_breg17:
+ case DW_OP_breg18:
+ case DW_OP_breg19:
+ case DW_OP_breg20:
+ case DW_OP_breg21:
+ case DW_OP_breg22:
+ case DW_OP_breg23:
+ case DW_OP_breg24:
+ case DW_OP_breg25:
+ case DW_OP_breg26:
+ case DW_OP_breg27:
+ case DW_OP_breg28:
+ case DW_OP_breg29:
+ case DW_OP_breg30:
+ case DW_OP_breg31:
+ res = _dwarf_pro_encode_signed_leb128_nm(val1,
+ &operand_size,
+ encode_buffer,
+ sizeof(encode_buffer));
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(expr->ex_dbg, error, DW_DLE_EXPR_LENGTH_BAD);
+ return (DW_DLV_NOCOUNT);
+ }
+ operand = (Dwarf_Small *) encode_buffer;
+ break;
+
+ case DW_OP_regx:
+ res = _dwarf_pro_encode_leb128_nm(val1, &operand_size,
+ encode_buffer,
+ sizeof(encode_buffer));
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(expr->ex_dbg, error, DW_DLE_EXPR_LENGTH_BAD);
+ return (DW_DLV_NOCOUNT);
+ }
+ operand = (Dwarf_Small *) encode_buffer;
+ break;
+
+ case DW_OP_lit0:
+ case DW_OP_lit1:
+ case DW_OP_lit2:
+ case DW_OP_lit3:
+ case DW_OP_lit4:
+ case DW_OP_lit5:
+ case DW_OP_lit6:
+ case DW_OP_lit7:
+ case DW_OP_lit8:
+ case DW_OP_lit9:
+ case DW_OP_lit10:
+ case DW_OP_lit11:
+ case DW_OP_lit12:
+ case DW_OP_lit13:
+ case DW_OP_lit14:
+ case DW_OP_lit15:
+ case DW_OP_lit16:
+ case DW_OP_lit17:
+ case DW_OP_lit18:
+ case DW_OP_lit19:
+ case DW_OP_lit20:
+ case DW_OP_lit21:
+ case DW_OP_lit22:
+ case DW_OP_lit23:
+ case DW_OP_lit24:
+ case DW_OP_lit25:
+ case DW_OP_lit26:
+ case DW_OP_lit27:
+ case DW_OP_lit28:
+ case DW_OP_lit29:
+ case DW_OP_lit30:
+ case DW_OP_lit31:
+ break;
+
+ case DW_OP_addr:
+ _dwarf_p_error(expr->ex_dbg, error, DW_DLE_BAD_EXPR_OPCODE);
+ return (DW_DLV_NOCOUNT);
+
+ case DW_OP_const1u:
+ case DW_OP_const1s:
+ operand = (Dwarf_Small *) & operand_buffer[0];
+ WRITE_UNALIGNED(dbg, operand, &val1, sizeof(val1), 1);
+ operand_size = 1;
+ break;
+
+ case DW_OP_const2u:
+ case DW_OP_const2s:
+ operand = (Dwarf_Small *) & operand_buffer[0];
+ WRITE_UNALIGNED(dbg, operand, &val1, sizeof(val1), 2);
+ operand_size = 2;
+ break;
+
+ case DW_OP_const4u:
+ case DW_OP_const4s:
+ operand = (Dwarf_Small *) & operand_buffer[0];
+ WRITE_UNALIGNED(dbg, operand, &val1, sizeof(val1), 4);
+ operand_size = 4;
+ break;
+
+ case DW_OP_const8u:
+ case DW_OP_const8s:
+ operand = (Dwarf_Small *) & operand_buffer[0];
+ WRITE_UNALIGNED(dbg, operand, &val1, sizeof(val1), 8);
+ operand_size = 8;
+ break;
+
+ case DW_OP_constu:
+ res = _dwarf_pro_encode_leb128_nm(val1,
+ &operand_size,
+ encode_buffer,
+ sizeof(encode_buffer));
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(expr->ex_dbg, error, DW_DLE_EXPR_LENGTH_BAD);
+ return (DW_DLV_NOCOUNT);
+ }
+ operand = (Dwarf_Small *) encode_buffer;
+ break;
+
+ case DW_OP_consts:
+ res = _dwarf_pro_encode_signed_leb128_nm(val1,
+ &operand_size,
+ encode_buffer,
+ sizeof(encode_buffer));
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(expr->ex_dbg, error, DW_DLE_EXPR_LENGTH_BAD);
+ return (DW_DLV_NOCOUNT);
+ }
+ operand = (Dwarf_Small *) encode_buffer;
+ break;
+
+ case DW_OP_fbreg:
+ res = _dwarf_pro_encode_signed_leb128_nm(val1,
+ &operand_size,
+ encode_buffer,
+ sizeof(encode_buffer));
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(expr->ex_dbg, error, DW_DLE_EXPR_LENGTH_BAD);
+ return (DW_DLV_NOCOUNT);
+ }
+ operand = (Dwarf_Small *) encode_buffer;
+ break;
+
+ case DW_OP_bregx:
+ res = _dwarf_pro_encode_leb128_nm(val1, &operand_size,
+ encode_buffer,
+ sizeof(encode_buffer));
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(expr->ex_dbg, error, DW_DLE_EXPR_LENGTH_BAD);
+ return (DW_DLV_NOCOUNT);
+ }
+ operand = (Dwarf_Small *) encode_buffer;
+ /* put this one directly into 'operand' at tail of prev value */
+ res = _dwarf_pro_encode_signed_leb128_nm(val2, &operand2_size,
+ ((char *) operand) +
+ operand_size,
+ sizeof
+ (encode_buffer2));
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(expr->ex_dbg, error, DW_DLE_EXPR_LENGTH_BAD);
+ return (DW_DLV_NOCOUNT);
+ }
+ operand_size += operand2_size;
+
+ case DW_OP_dup:
+ case DW_OP_drop:
+ break;
+
+ case DW_OP_pick:
+ operand = (Dwarf_Small *) & operand_buffer[0];
+ WRITE_UNALIGNED(dbg, operand, (const void *) &val1,
+ sizeof(val1), 1);
+ operand_size = 1;
+ break;
+
+ case DW_OP_over:
+ case DW_OP_swap:
+ case DW_OP_rot:
+ case DW_OP_deref:
+ case DW_OP_xderef:
+ break;
+
+ case DW_OP_deref_size:
+ case DW_OP_xderef_size:
+ operand = (Dwarf_Small *) & operand_buffer[0];
+ WRITE_UNALIGNED(dbg, operand, (const void *) &val1,
+ sizeof(val1), 1);
+ operand_size = 1;
+ break;
+
+ case DW_OP_abs:
+ case DW_OP_and:
+ case DW_OP_div:
+ case DW_OP_minus:
+ case DW_OP_mod:
+ case DW_OP_mul:
+ case DW_OP_neg:
+ case DW_OP_not:
+ case DW_OP_or:
+ case DW_OP_plus:
+ break;
+
+ case DW_OP_plus_uconst:
+ res = _dwarf_pro_encode_leb128_nm(val1, &operand_size,
+ encode_buffer,
+ sizeof(encode_buffer));
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(expr->ex_dbg, error, DW_DLE_EXPR_LENGTH_BAD);
+ return (DW_DLV_NOCOUNT);
+ }
+ operand = (Dwarf_Small *) encode_buffer;
+ break;
+
+ case DW_OP_shl:
+ case DW_OP_shr:
+ case DW_OP_shra:
+ case DW_OP_xor:
+ break;
+
+ case DW_OP_le:
+ case DW_OP_ge:
+ case DW_OP_eq:
+ case DW_OP_lt:
+ case DW_OP_gt:
+ case DW_OP_ne:
+ break;
+
+ case DW_OP_skip:
+ case DW_OP_bra:
+ /* FIX: unhandled! OP_bra, OP_skip! */
+ _dwarf_p_error(expr->ex_dbg, error, DW_DLE_BAD_EXPR_OPCODE);
+ return (DW_DLV_NOCOUNT);
+
+ case DW_OP_piece:
+ res = _dwarf_pro_encode_leb128_nm(val1, &operand_size,
+ encode_buffer,
+ sizeof(encode_buffer));
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(expr->ex_dbg, error, DW_DLE_EXPR_LENGTH_BAD);
+ return (DW_DLV_NOCOUNT);
+ }
+ operand = (Dwarf_Small *) encode_buffer;
+ break;
+
+ case DW_OP_nop:
+ break;
+ case DW_OP_push_object_address: /* DWARF3 */
+ break;
+ case DW_OP_call2: /* DWARF3 */
+ operand = (Dwarf_Small *) & operand_buffer[0];
+ WRITE_UNALIGNED(dbg, operand, &val1, sizeof(val1), 2);
+ operand_size = 2;
+ break;
+
+ case DW_OP_call4: /* DWARF3 */
+ operand = (Dwarf_Small *) & operand_buffer[0];
+ WRITE_UNALIGNED(dbg, operand, &val1, sizeof(val1), 4);
+ operand_size = 4;
+ break;
+
+ case DW_OP_call_ref: /* DWARF3 */
+ operand = (Dwarf_Small *) & operand_buffer[0];
+ WRITE_UNALIGNED(dbg, operand, &val1, sizeof(val1),
+ dbg->de_offset_size);
+ operand_size = dbg->de_offset_size;
+ break;
+ case DW_OP_form_tls_address: /* DWARF3f */
+ break;
+ case DW_OP_call_frame_cfa: /* DWARF3f */
+ break;
+ case DW_OP_bit_piece: /* DWARF3f */
+ res = _dwarf_pro_encode_leb128_nm(val1, &operand_size,
+ encode_buffer,
+ sizeof(encode_buffer));
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(expr->ex_dbg, error, DW_DLE_EXPR_LENGTH_BAD);
+ return (DW_DLV_NOCOUNT);
+ }
+ operand = (Dwarf_Small *) encode_buffer;
+ /* put this one directly into 'operand' at tail of prev value */
+ res = _dwarf_pro_encode_leb128_nm(val2, &operand2_size,
+ ((char *) operand) +
+ operand_size,
+ sizeof(encode_buffer2));
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(expr->ex_dbg, error, DW_DLE_EXPR_LENGTH_BAD);
+ return (DW_DLV_NOCOUNT);
+ }
+ operand_size += operand2_size;
+
+
+ default:
+ _dwarf_p_error(expr->ex_dbg, error, DW_DLE_BAD_EXPR_OPCODE);
+ return (DW_DLV_NOCOUNT);
+ }
+
+ next_byte_offset = expr->ex_next_byte_offset + operand_size + 1;
+
+ if (next_byte_offset > MAXIMUM_LOC_EXPR_LENGTH) {
+ _dwarf_p_error(expr->ex_dbg, error, DW_DLE_EXPR_LENGTH_BAD);
+ return (DW_DLV_NOCOUNT);
+ }
+
+ next_byte_ptr =
+ &(expr->ex_byte_stream[0]) + expr->ex_next_byte_offset;
+
+ *next_byte_ptr = opcode;
+ next_byte_ptr++;
+ memcpy(next_byte_ptr, operand, operand_size);
+
+ expr->ex_next_byte_offset = next_byte_offset;
+ return (next_byte_offset);
+}
+
+Dwarf_Unsigned
+dwarf_add_expr_addr_b(Dwarf_P_Expr expr,
+ Dwarf_Unsigned addr,
+ Dwarf_Unsigned sym_index, Dwarf_Error * error)
+{
+ Dwarf_P_Debug dbg;
+ Dwarf_Small *next_byte_ptr;
+ Dwarf_Unsigned next_byte_offset;
+ int upointer_size;
+
+ if (expr == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_EXPR_NULL);
+ return (DW_DLV_NOCOUNT);
+ }
+
+ dbg = expr->ex_dbg;
+ if (dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_NOCOUNT);
+ }
+
+ upointer_size = dbg->de_pointer_size;
+ next_byte_offset = expr->ex_next_byte_offset + upointer_size + 1;
+ if (next_byte_offset > MAXIMUM_LOC_EXPR_LENGTH) {
+ _dwarf_p_error(dbg, error, DW_DLE_EXPR_LENGTH_BAD);
+ return (DW_DLV_NOCOUNT);
+ }
+
+ next_byte_ptr =
+ &(expr->ex_byte_stream[0]) + expr->ex_next_byte_offset;
+
+ *next_byte_ptr = DW_OP_addr;
+ next_byte_ptr++;
+ WRITE_UNALIGNED(dbg, next_byte_ptr, (const void *) &addr,
+ sizeof(addr), upointer_size);
+
+ if (expr->ex_reloc_offset != 0) {
+ _dwarf_p_error(dbg, error, DW_DLE_MULTIPLE_RELOC_IN_EXPR);
+ return (DW_DLV_NOCOUNT);
+ }
+
+ expr->ex_reloc_sym_index = sym_index;
+ expr->ex_reloc_offset = expr->ex_next_byte_offset + 1;
+
+ expr->ex_next_byte_offset = next_byte_offset;
+ return (next_byte_offset);
+}
+
+Dwarf_Unsigned
+dwarf_add_expr_addr(Dwarf_P_Expr expr,
+ Dwarf_Unsigned addr,
+ Dwarf_Signed sym_index, Dwarf_Error * error)
+{
+ return
+ dwarf_add_expr_addr_b(expr, addr, (Dwarf_Unsigned) sym_index,
+ error);
+}
+
+
+Dwarf_Unsigned
+dwarf_expr_current_offset(Dwarf_P_Expr expr, Dwarf_Error * error)
+{
+ if (expr == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_EXPR_NULL);
+ return (DW_DLV_NOCOUNT);
+ }
+
+ if (expr->ex_dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_NOCOUNT);
+ }
+
+ return (expr->ex_next_byte_offset);
+}
+
+void
+dwarf_expr_reset(Dwarf_P_Expr expr, Dwarf_Error * error)
+{
+ if (expr == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_EXPR_NULL);
+ return;
+ }
+ expr->ex_next_byte_offset=0;
+}
+
+
+Dwarf_Addr
+dwarf_expr_into_block(Dwarf_P_Expr expr,
+ Dwarf_Unsigned * length, Dwarf_Error * error)
+{
+ if (expr == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_EXPR_NULL);
+ return (DW_DLV_BADADDR);
+ }
+
+ if (expr->ex_dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_BADADDR);
+ }
+
+ if (length != NULL)
+ *length = expr->ex_next_byte_offset;
+ /* The following cast from pointer to integer is ok as long as
+ Dwarf_Addr is at least as large as a pointer. Which is a
+ requirement of libdwarf so must be satisfied (some compilers
+ emit a warning about the following line). */
+ return ((Dwarf_Addr)(uintptr_t) &(expr->ex_byte_stream[0]));
+}
diff --git a/usr/src/lib/libdwarf/common/pro_expr.h b/usr/src/lib/libdwarf/common/pro_expr.h
new file mode 100644
index 0000000000..202f2d30d5
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_expr.h
@@ -0,0 +1,45 @@
+/*
+
+ Copyright (C) 2000,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
+
+*/
+
+
+#define MAXIMUM_LOC_EXPR_LENGTH 20
+
+struct Dwarf_P_Expr_s {
+ Dwarf_Small ex_byte_stream[MAXIMUM_LOC_EXPR_LENGTH];
+ Dwarf_P_Debug ex_dbg;
+ Dwarf_Unsigned ex_next_byte_offset;
+ Dwarf_Unsigned ex_reloc_sym_index;
+ Dwarf_Unsigned ex_reloc_offset;
+};
diff --git a/usr/src/lib/libdwarf/common/pro_finish.c b/usr/src/lib/libdwarf/common/pro_finish.c
new file mode 100644
index 0000000000..bc43a5f0f4
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_finish.c
@@ -0,0 +1,57 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright 2002-2010 Sun Microsystems, 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
+
+*/
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#include "pro_incl.h"
+
+/*---------------------------------------------------------------
+ This routine deallocates all memory, and does some
+ finishing up
+-----------------------------------------------------------------*/
+ /*ARGSUSED*/ Dwarf_Unsigned
+dwarf_producer_finish(Dwarf_P_Debug dbg, Dwarf_Error * error)
+{
+ if (dbg->de_version_magic_number != PRO_VERSION_MAGIC) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_IA, DW_DLV_NOCOUNT);
+ }
+
+ /* this frees all blocks, then frees dbg. */
+ _dwarf_p_dealloc_all(dbg);
+ return 0;
+}
diff --git a/usr/src/lib/libdwarf/common/pro_forms.c b/usr/src/lib/libdwarf/common/pro_forms.c
new file mode 100644
index 0000000000..fec9a39c60
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_forms.c
@@ -0,0 +1,1182 @@
+/*
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright 2002-2010 Sun Microsystems, Inc. All rights reserved.
+ Portions Copyright 2007-2010 David Anderson. 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
+
+*/
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include "pro_incl.h"
+#include "pro_expr.h"
+
+#ifndef R_MIPS_NONE
+#define R_MIPS_NONE 0
+#endif
+
+
+ /* Indicates no relocation needed. */
+#define NO_ELF_SYM_INDEX 0
+
+
+/* adds an attribute to a die */
+extern void _dwarf_pro_add_at_to_die(Dwarf_P_Die die,
+ Dwarf_P_Attribute attr);
+
+/*
+ This function adds an attribute whose value is
+ a target address to the given die. The attribute
+ is given the name provided by attr. The address
+ is given in pc_value.
+*/
+
+static Dwarf_P_Attribute
+local_add_AT_address(Dwarf_P_Debug dbg,
+ Dwarf_P_Die ownerdie,
+ Dwarf_Half attr,
+ Dwarf_Signed form,
+ Dwarf_Unsigned pc_value,
+ Dwarf_Unsigned sym_index,
+ Dwarf_Error * error);
+
+/* old interface */
+Dwarf_P_Attribute
+dwarf_add_AT_targ_address(Dwarf_P_Debug dbg,
+ Dwarf_P_Die ownerdie,
+ Dwarf_Half attr,
+ Dwarf_Unsigned pc_value,
+ Dwarf_Signed sym_index, Dwarf_Error * error)
+{
+ return
+ dwarf_add_AT_targ_address_b(dbg,
+ ownerdie,
+ attr,
+ pc_value,
+ (Dwarf_Unsigned) sym_index, error);
+}
+
+/* New interface, replacing dwarf_add_AT_targ_address.
+ Essentially just makes sym_index a Dwarf_Unsigned
+ so for symbolic relocations it can be a full address.
+*/
+Dwarf_P_Attribute
+dwarf_add_AT_targ_address_b(Dwarf_P_Debug dbg,
+ Dwarf_P_Die ownerdie,
+ Dwarf_Half attr,
+ Dwarf_Unsigned pc_value,
+ Dwarf_Unsigned sym_index,
+ Dwarf_Error * error)
+{
+ switch (attr) {
+ case DW_AT_low_pc:
+ case DW_AT_high_pc:
+
+ /* added to support location lists */
+ /* no way to check that this is a loclist-style address though */
+ case DW_AT_location:
+ case DW_AT_string_length:
+ case DW_AT_return_addr:
+ case DW_AT_frame_base:
+ case DW_AT_segment:
+ case DW_AT_static_link:
+ case DW_AT_use_location:
+ case DW_AT_vtable_elem_location:
+ case DW_AT_const_value: /* Gcc can generate this as address. */
+ case DW_AT_entry_pc:
+ break;
+ default:
+ if ( attr < DW_AT_lo_user || attr > DW_AT_hi_user ) {
+ _dwarf_p_error(dbg, error, DW_DLE_INPUT_ATTR_BAD);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ break;
+ }
+
+ return local_add_AT_address(dbg, ownerdie, attr, DW_FORM_addr,
+ pc_value, sym_index, error);
+}
+
+Dwarf_P_Attribute
+dwarf_add_AT_ref_address(Dwarf_P_Debug dbg,
+ Dwarf_P_Die ownerdie,
+ Dwarf_Half attr,
+ Dwarf_Unsigned pc_value,
+ Dwarf_Unsigned sym_index,
+ Dwarf_Error * error)
+{
+ switch (attr) {
+ case DW_AT_type:
+ case DW_AT_import:
+ break;
+
+ default:
+ if ( attr < DW_AT_lo_user || attr > DW_AT_hi_user ) {
+ _dwarf_p_error(dbg, error, DW_DLE_INPUT_ATTR_BAD);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ break;
+ }
+
+ return local_add_AT_address(dbg, ownerdie, attr, DW_FORM_ref_addr,
+ pc_value, sym_index, error);
+}
+
+
+/* Make sure attribute types are checked before entering here. */
+static Dwarf_P_Attribute
+local_add_AT_address(Dwarf_P_Debug dbg,
+ Dwarf_P_Die ownerdie,
+ Dwarf_Half attr,
+ Dwarf_Signed form,
+ Dwarf_Unsigned pc_value,
+ Dwarf_Unsigned sym_index,
+ Dwarf_Error * error)
+{
+ Dwarf_P_Attribute new_attr;
+ int upointer_size = dbg->de_pointer_size;
+
+ if (dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ if (ownerdie == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_DIE_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ /* attribute types have already been checked */
+ /* switch (attr) { ... } */
+
+ new_attr = (Dwarf_P_Attribute)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Attribute_s));
+ if (new_attr == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ new_attr->ar_attribute = attr;
+ new_attr->ar_attribute_form = form;
+ new_attr->ar_nbytes = upointer_size;
+ new_attr->ar_rel_symidx = sym_index;
+ new_attr->ar_reloc_len = upointer_size;
+ new_attr->ar_next = 0;
+ if (sym_index != NO_ELF_SYM_INDEX)
+ new_attr->ar_rel_type = dbg->de_ptr_reloc;
+ else
+ new_attr->ar_rel_type = R_MIPS_NONE;
+
+ new_attr->ar_data = (char *)
+ _dwarf_p_get_alloc(dbg, upointer_size);
+ if (new_attr->ar_data == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ WRITE_UNALIGNED(dbg, new_attr->ar_data,
+ (const void *) &pc_value,
+ sizeof(pc_value), upointer_size);
+
+ /* add attribute to the die */
+ _dwarf_pro_add_at_to_die(ownerdie, new_attr);
+ return new_attr;
+}
+
+/*
+ * Functions to compress and uncompress data from normal
+ * arrays of integral types into arrays of LEB128 numbers.
+ * Extend these functions as needed to handle wider input
+ * variety. Return values should be freed with _dwarf_p_dealloc
+ * after they aren't needed any more.
+ */
+
+/* return value points to an array of LEB number */
+
+void *
+dwarf_compress_integer_block(
+ Dwarf_P_Debug dbg,
+ Dwarf_Bool unit_is_signed,
+ Dwarf_Small unit_length_in_bits,
+ void* input_block,
+ Dwarf_Unsigned input_length_in_units,
+ Dwarf_Unsigned* output_length_in_bytes_ptr,
+ Dwarf_Error* error
+)
+{
+ Dwarf_Unsigned output_length_in_bytes = 0;
+ char * output_block = 0;
+ char encode_buffer[ENCODE_SPACE_NEEDED];
+ int i = 0;
+ char * ptr = 0;
+ int remain = 0;
+ int result = 0;
+
+ if (dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return((void *)DW_DLV_BADADDR);
+ }
+
+ if (unit_is_signed == false ||
+ unit_length_in_bits != 32 ||
+ input_block == NULL ||
+ input_length_in_units == 0 ||
+ output_length_in_bytes_ptr == NULL) {
+
+ _dwarf_p_error(NULL, error, DW_DLE_BADBITC);
+ return ((void *) DW_DLV_BADADDR);
+ }
+
+ /* At this point we assume the format is: signed 32 bit */
+
+ /* first compress everything to find the total size. */
+
+ output_length_in_bytes = 0;
+ for (i=0; i<input_length_in_units; i++) {
+ int unit_encoded_size;
+ Dwarf_sfixed unit; /* this is fixed at signed-32-bits */
+
+ unit = ((Dwarf_sfixed*)input_block)[i];
+
+ result = _dwarf_pro_encode_signed_leb128_nm(unit, &unit_encoded_size,
+ encode_buffer,sizeof(encode_buffer));
+ if (result != DW_DLV_OK) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return((Dwarf_P_Attribute)DW_DLV_BADADDR);
+ }
+ output_length_in_bytes += unit_encoded_size;
+ }
+
+
+ /* then alloc */
+
+ output_block = (void *)
+ _dwarf_p_get_alloc(dbg, output_length_in_bytes);
+ if (output_block == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return((void*)DW_DLV_BADADDR);
+ }
+
+ /* then compress again and copy into new buffer */
+
+ ptr = output_block;
+ remain = output_length_in_bytes;
+ for (i=0; i<input_length_in_units; i++) {
+ int unit_encoded_size;
+ Dwarf_sfixed unit; /* this is fixed at signed-32-bits */
+
+ unit = ((Dwarf_sfixed*)input_block)[i];
+
+ result = _dwarf_pro_encode_signed_leb128_nm(unit, &unit_encoded_size,
+ ptr, remain);
+ if (result != DW_DLV_OK) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return((Dwarf_P_Attribute)DW_DLV_BADADDR);
+ }
+ remain -= unit_encoded_size;
+ ptr += unit_encoded_size;
+ }
+
+ if (remain != 0) {
+ _dwarf_p_dealloc(dbg, (unsigned char *)output_block);
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return((Dwarf_P_Attribute)DW_DLV_BADADDR);
+ }
+
+ *output_length_in_bytes_ptr = output_length_in_bytes;
+ return (void*) output_block;
+
+}
+
+void
+dwarf_dealloc_compressed_block(Dwarf_P_Debug dbg, void * space)
+{
+ _dwarf_p_dealloc(dbg, space);
+}
+
+/* This is very similar to targ_address but results in a different FORM */
+/* dbg->de_ar_data_attribute_form is data4 or data8
+ and dwarf4 changes the definition for such on DW_AT_high_pc.
+ DWARF 3: the FORM here has no defined meaning for dwarf3.
+ DWARF 4: the FORM here means that for DW_AT_high_pc the value
+ is not a high address but is instead an offset
+ from a (separate) DW_AT_low_pc.
+ The intent for DWARF4 is that this is not a relocated
+ address at all. Instead a simple offset.
+ But this should NOT be called for a simple non-relocated offset.
+ So do not call this with an attr of DW_AT_high_pc.
+ Use dwarf_add_AT_unsigned_const() (for example) instead of
+ dwarf_add_AT_dataref when the value is a simple offset .
+*/
+Dwarf_P_Attribute
+dwarf_add_AT_dataref(
+ Dwarf_P_Debug dbg,
+ Dwarf_P_Die ownerdie,
+ Dwarf_Half attr,
+ Dwarf_Unsigned pc_value,
+ Dwarf_Unsigned sym_index,
+ Dwarf_Error * error)
+{
+ /* TODO: Add checking here */
+ return local_add_AT_address(dbg, ownerdie, attr,
+ dbg->de_ar_data_attribute_form,
+ pc_value,
+ sym_index,
+ error);
+}
+
+
+
+Dwarf_P_Attribute
+dwarf_add_AT_block(
+ Dwarf_P_Debug dbg,
+ Dwarf_P_Die ownerdie,
+ Dwarf_Half attr,
+ Dwarf_Small *block_data,
+ Dwarf_Unsigned block_size,
+ Dwarf_Error *error
+)
+{
+ Dwarf_P_Attribute new_attr;
+ int result;
+ char encode_buffer[ENCODE_SPACE_NEEDED];
+ int len_size;
+ char * attrdata;
+
+ if (dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return((Dwarf_P_Attribute)DW_DLV_BADADDR);
+ }
+
+ if (ownerdie == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_DIE_NULL);
+ return((Dwarf_P_Attribute)DW_DLV_BADADDR);
+ }
+
+ /* I don't mess with block1, block2, block4, not worth the effort */
+
+ /* So, encode the length into LEB128 */
+ result = _dwarf_pro_encode_leb128_nm(block_size, &len_size,
+ encode_buffer,sizeof(encode_buffer));
+ if (result != DW_DLV_OK) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return((Dwarf_P_Attribute)DW_DLV_BADADDR);
+ }
+
+ /* Allocate the new attribute */
+ new_attr = (Dwarf_P_Attribute)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Attribute_s));
+ if (new_attr == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return((Dwarf_P_Attribute)DW_DLV_BADADDR);
+ }
+
+ /* Fill in the attribute */
+ new_attr->ar_attribute = attr;
+ new_attr->ar_attribute_form = DW_FORM_block;
+ new_attr->ar_nbytes = len_size + block_size;
+ new_attr->ar_next = 0;
+
+ new_attr->ar_data = attrdata = (char *)
+ _dwarf_p_get_alloc(dbg, len_size + block_size);
+ if (new_attr->ar_data == NULL) {
+ /* free the block we got earlier */
+ _dwarf_p_dealloc(dbg, (unsigned char *) new_attr);
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return((Dwarf_P_Attribute)DW_DLV_BADADDR);
+ }
+
+ /* write length and data to attribute data buffer */
+ memcpy(attrdata, encode_buffer, len_size);
+ attrdata += len_size;
+ memcpy(attrdata, block_data, block_size);
+
+ /* add attribute to the die */
+ _dwarf_pro_add_at_to_die(ownerdie, new_attr);
+
+ return new_attr;
+}
+
+
+/*
+ This function adds attributes whose value
+ is an unsigned constant. It determines the
+ size of the value field from the value of
+ the constant.
+*/
+Dwarf_P_Attribute
+dwarf_add_AT_unsigned_const(Dwarf_P_Debug dbg,
+ Dwarf_P_Die ownerdie,
+ Dwarf_Half attr,
+ Dwarf_Unsigned value, Dwarf_Error * error)
+{
+ Dwarf_P_Attribute new_attr;
+ Dwarf_Half attr_form;
+ Dwarf_Small size;
+
+ if (dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ if (ownerdie == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_DIE_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ 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_encoding:
+ case DW_AT_identifier_case:
+ case DW_AT_MIPS_loop_unroll_factor:
+ case DW_AT_MIPS_software_pipeline_depth:
+ break;
+
+ case DW_AT_decl_column:
+ case DW_AT_decl_file:
+ case DW_AT_decl_line:
+ case DW_AT_const_value:
+ case DW_AT_start_scope:
+ case DW_AT_stride_size:
+ case DW_AT_count:
+ case DW_AT_associated:
+ case DW_AT_allocated:
+ case DW_AT_upper_bound:
+ case DW_AT_lower_bound:
+ case DW_AT_call_file:
+ case DW_AT_call_line:
+ break;
+
+ default: {
+ if ( attr < DW_AT_lo_user || attr > DW_AT_hi_user ) {
+ _dwarf_p_error(dbg, error, DW_DLE_INPUT_ATTR_BAD);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ break;
+ }
+ }
+
+ /*
+ Compute the number of bytes needed to hold constant. */
+ if (value <= UCHAR_MAX) {
+ attr_form = DW_FORM_data1;
+ size = 1;
+ } else if (value <= USHRT_MAX) {
+ attr_form = DW_FORM_data2;
+ size = 2;
+ } else if (value <= UINT_MAX) {
+ attr_form = DW_FORM_data4;
+ size = 4;
+ } else {
+ attr_form = DW_FORM_data8;
+ size = 8;
+ }
+
+ new_attr = (Dwarf_P_Attribute)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Attribute_s));
+ if (new_attr == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ new_attr->ar_attribute = attr;
+ new_attr->ar_attribute_form = attr_form;
+ new_attr->ar_rel_type = R_MIPS_NONE;
+ new_attr->ar_reloc_len = 0; /* irrelevant: unused with R_MIPS_NONE */
+ new_attr->ar_nbytes = size;
+ new_attr->ar_next = 0;
+
+ new_attr->ar_data = (char *)
+ _dwarf_p_get_alloc(dbg, size);
+ if (new_attr->ar_data == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ WRITE_UNALIGNED(dbg, new_attr->ar_data,
+ (const void *) &value, sizeof(value), size);
+
+ /* add attribute to the die */
+ _dwarf_pro_add_at_to_die(ownerdie, new_attr);
+ return new_attr;
+}
+
+
+/*
+ This function adds attributes whose value
+ is an signed constant. It determines the
+ size of the value field from the value of
+ the constant.
+*/
+Dwarf_P_Attribute
+dwarf_add_AT_signed_const(Dwarf_P_Debug dbg,
+ Dwarf_P_Die ownerdie,
+ Dwarf_Half attr,
+ Dwarf_Signed value, Dwarf_Error * error)
+{
+ Dwarf_P_Attribute new_attr;
+ Dwarf_Half attr_form;
+ Dwarf_Small size;
+
+ if (dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ if (ownerdie == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_DIE_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ switch (attr) {
+ case DW_AT_lower_bound:
+ case DW_AT_upper_bound:
+ case DW_AT_const_value:
+ case DW_AT_bit_offset:
+ case DW_AT_bit_size:
+ case DW_AT_byte_size:
+ case DW_AT_count:
+ case DW_AT_byte_stride:
+ case DW_AT_bit_stride:
+ case DW_AT_allocated:
+ case DW_AT_associated:
+ break;
+
+ default:{
+ if ( attr < DW_AT_lo_user || attr > DW_AT_hi_user ) {
+ _dwarf_p_error(dbg, error, DW_DLE_INPUT_ATTR_BAD);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ }
+ break;
+ }
+
+ /*
+ Compute the number of bytes needed to hold constant. */
+ if (value >= SCHAR_MIN && value <= SCHAR_MAX) {
+ attr_form = DW_FORM_data1;
+ size = 1;
+ } else if (value >= SHRT_MIN && value <= SHRT_MAX) {
+ attr_form = DW_FORM_data2;
+ size = 2;
+ } else if (value >= INT_MIN && value <= INT_MAX) {
+ attr_form = DW_FORM_data4;
+ size = 4;
+ } else {
+ attr_form = DW_FORM_data8;
+ size = 8;
+ }
+
+ new_attr = (Dwarf_P_Attribute)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Attribute_s));
+ if (new_attr == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ new_attr->ar_attribute = attr;
+ new_attr->ar_attribute_form = attr_form;
+ new_attr->ar_rel_type = R_MIPS_NONE;
+ new_attr->ar_reloc_len = 0; /* irrelevant: unused with R_MIPS_NONE */
+ new_attr->ar_nbytes = size;
+ new_attr->ar_next = 0;
+
+ new_attr->ar_data = (char *)
+ _dwarf_p_get_alloc(dbg, size);
+ if (new_attr->ar_data == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ WRITE_UNALIGNED(dbg, new_attr->ar_data,
+ (const void *) &value, sizeof(value), size);
+
+ /* add attribute to the die */
+ _dwarf_pro_add_at_to_die(ownerdie, new_attr);
+ return new_attr;
+}
+
+
+/*
+ This function adds attributes whose value
+ is a location expression.
+*/
+Dwarf_P_Attribute
+dwarf_add_AT_location_expr(Dwarf_P_Debug dbg,
+ Dwarf_P_Die ownerdie,
+ Dwarf_Half attr,
+ Dwarf_P_Expr loc_expr, Dwarf_Error * error)
+{
+ char encode_buffer[ENCODE_SPACE_NEEDED];
+ int res;
+ Dwarf_P_Attribute new_attr;
+ Dwarf_Half attr_form;
+ char *len_str = 0;
+ int len_size;
+ int block_size;
+ char *block_dest_ptr;
+ int do_len_as_int = 0;
+
+ if (dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ if (ownerdie == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_DIE_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ if (loc_expr == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_EXPR_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ if (loc_expr->ex_dbg != dbg) {
+ _dwarf_p_error(dbg, error, DW_DLE_LOC_EXPR_BAD);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ block_size = loc_expr->ex_next_byte_offset;
+
+ switch (attr) {
+ case DW_AT_location:
+ case DW_AT_string_length:
+ case DW_AT_const_value:
+ case DW_AT_use_location:
+ case DW_AT_return_addr:
+ case DW_AT_data_member_location:
+ case DW_AT_frame_base:
+ case DW_AT_static_link:
+ case DW_AT_vtable_elem_location:
+ case DW_AT_lower_bound:
+ case DW_AT_upper_bound:
+ case DW_AT_count:
+ case DW_AT_associated:
+ case DW_AT_allocated:
+ case DW_AT_data_location:
+ case DW_AT_byte_stride:
+ case DW_AT_bit_stride:
+ case DW_AT_byte_size:
+ case DW_AT_bit_size:
+ break;
+
+ default:
+ if ( attr < DW_AT_lo_user || attr > DW_AT_hi_user ) {
+ _dwarf_p_error(dbg, error, DW_DLE_INPUT_ATTR_BAD);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ break;
+ }
+
+ /*
+ Compute the number of bytes needed to hold constant. */
+ if (block_size <= UCHAR_MAX) {
+ attr_form = DW_FORM_block1;
+ len_size = 1;
+ do_len_as_int = 1;
+ } else if (block_size <= USHRT_MAX) {
+ attr_form = DW_FORM_block2;
+ len_size = 2;
+ do_len_as_int = 1;
+ } else if (block_size <= UINT_MAX) {
+ attr_form = DW_FORM_block4;
+ len_size = 4;
+ do_len_as_int = 1;
+ } else {
+ attr_form = DW_FORM_block;
+ res = _dwarf_pro_encode_leb128_nm(block_size, &len_size,
+ encode_buffer,
+ sizeof(encode_buffer));
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ len_str = (char *) encode_buffer;
+ }
+
+ new_attr = (Dwarf_P_Attribute)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Attribute_s));
+ if (new_attr == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ new_attr->ar_attribute = attr;
+ new_attr->ar_attribute_form = attr_form;
+ new_attr->ar_reloc_len = dbg->de_pointer_size;
+ if (loc_expr->ex_reloc_sym_index != NO_ELF_SYM_INDEX) {
+ new_attr->ar_rel_type = dbg->de_ptr_reloc;
+ } else {
+ new_attr->ar_rel_type = R_MIPS_NONE;
+ }
+ new_attr->ar_rel_symidx = loc_expr->ex_reloc_sym_index;
+ new_attr->ar_rel_offset =
+ (Dwarf_Word) loc_expr->ex_reloc_offset + len_size;
+
+ new_attr->ar_nbytes = block_size + len_size;
+
+ new_attr->ar_next = 0;
+ new_attr->ar_data = block_dest_ptr =
+ (char *) _dwarf_p_get_alloc(dbg, block_size + len_size);
+ if (new_attr->ar_data == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ if (do_len_as_int) {
+ WRITE_UNALIGNED(dbg, block_dest_ptr, (const void *) &block_size,
+ sizeof(block_size), len_size);
+ } else {
+ /* Is uleb number form, DW_FORM_block. See above. */
+ memcpy(block_dest_ptr, len_str, len_size);
+ }
+ block_dest_ptr += len_size;
+ memcpy(block_dest_ptr, &(loc_expr->ex_byte_stream[0]), block_size);
+
+ /* add attribute to the die */
+ _dwarf_pro_add_at_to_die(ownerdie, new_attr);
+ return new_attr;
+}
+
+
+/*
+ This function adds attributes of reference class.
+ The references here are local CU references,
+ not DW_FORM_ref_addr.
+ The offset field is 4 bytes for 32-bit objects,
+ and 8-bytes for 64-bit objects. Otherdie is the
+ that is referenced by ownerdie.
+
+ For reference attributes, the ar_data and ar_nbytes
+ are not needed. Instead, the ar_ref_die points to
+ the other die, and its di_offset value is used as
+ the reference value.
+*/
+Dwarf_P_Attribute
+dwarf_add_AT_reference(Dwarf_P_Debug dbg,
+ Dwarf_P_Die ownerdie,
+ Dwarf_Half attr,
+ Dwarf_P_Die otherdie, Dwarf_Error * error)
+{
+ Dwarf_P_Attribute new_attr;
+
+ if (dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ if (ownerdie == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_DIE_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ if (otherdie == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_DIE_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ switch (attr) {
+ case DW_AT_specification:
+ case DW_AT_discr:
+ case DW_AT_common_reference:
+ case DW_AT_import:
+ case DW_AT_containing_type:
+ case DW_AT_default_value:
+ case DW_AT_abstract_origin:
+ case DW_AT_friend:
+ case DW_AT_priority:
+ case DW_AT_type:
+ case DW_AT_lower_bound:
+ case DW_AT_upper_bound:
+ case DW_AT_count:
+ case DW_AT_associated:
+ case DW_AT_allocated:
+ case DW_AT_bit_offset:
+ case DW_AT_bit_size:
+ case DW_AT_byte_size:
+ case DW_AT_sibling:
+ case DW_AT_bit_stride:
+ case DW_AT_byte_stride:
+ case DW_AT_namelist_item:
+ break;
+
+ default:
+ if ( attr < DW_AT_lo_user || attr > DW_AT_hi_user ) {
+ _dwarf_p_error(dbg, error, DW_DLE_INPUT_ATTR_BAD);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ break;
+ }
+
+ new_attr = (Dwarf_P_Attribute)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Attribute_s));
+ if (new_attr == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ new_attr->ar_attribute = attr;
+ new_attr->ar_attribute_form = dbg->de_ar_ref_attr_form;
+ new_attr->ar_nbytes = dbg->de_offset_size;
+ new_attr->ar_reloc_len = dbg->de_offset_size;
+ new_attr->ar_ref_die = otherdie;
+ new_attr->ar_rel_type = R_MIPS_NONE;
+ new_attr->ar_next = 0;
+
+ /* add attribute to the die */
+ _dwarf_pro_add_at_to_die(ownerdie, new_attr);
+ return new_attr;
+}
+
+
+/*
+ This function adds attributes of the flag class.
+*/
+Dwarf_P_Attribute
+dwarf_add_AT_flag(Dwarf_P_Debug dbg,
+ Dwarf_P_Die ownerdie,
+ Dwarf_Half attr,
+ Dwarf_Small flag, Dwarf_Error * error)
+{
+ Dwarf_P_Attribute new_attr;
+
+ if (dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ if (ownerdie == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_DIE_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+#if 0
+ switch (attr) {
+ case DW_AT_is_optional:
+ case DW_AT_artificial:
+ case DW_AT_declaration:
+ case DW_AT_external:
+ case DW_AT_prototyped:
+ case DW_AT_variable_parameter:
+ break;
+
+ default:
+ if ( attr < DW_AT_lo_user || attr > DW_AT_hi_user ) {
+ _dwarf_p_error(dbg, error, DW_DLE_INPUT_ATTR_BAD);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ break;
+ }
+#endif
+
+ new_attr = (Dwarf_P_Attribute)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Attribute_s));
+ if (new_attr == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ new_attr->ar_attribute = attr;
+ new_attr->ar_attribute_form = DW_FORM_flag;
+ new_attr->ar_nbytes = 1;
+ new_attr->ar_reloc_len = 0; /* not used */
+ new_attr->ar_rel_type = R_MIPS_NONE;
+ new_attr->ar_next = 0;
+
+ new_attr->ar_data = (char *)
+ _dwarf_p_get_alloc(dbg, 1);
+ if (new_attr->ar_data == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ memcpy(new_attr->ar_data, &flag, 1);
+
+ /* add attribute to the die */
+ _dwarf_pro_add_at_to_die(ownerdie, new_attr);
+ return new_attr;
+}
+
+
+/*
+ This function adds values of attributes
+ belonging to the string class.
+*/
+Dwarf_P_Attribute
+dwarf_add_AT_string(Dwarf_P_Debug dbg,
+ Dwarf_P_Die ownerdie,
+ Dwarf_Half attr, char *string, Dwarf_Error * error)
+{
+ Dwarf_P_Attribute new_attr;
+
+ if (dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ if (ownerdie == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_DIE_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ new_attr = (Dwarf_P_Attribute)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Attribute_s));
+ if (new_attr == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ switch (attr) {
+ case DW_AT_name:
+ case DW_AT_comp_dir:
+ case DW_AT_const_value:
+ case DW_AT_producer:
+ break;
+
+ default:
+ if ( attr < DW_AT_lo_user || attr > DW_AT_hi_user ) {
+ _dwarf_p_error(dbg, error, DW_DLE_INPUT_ATTR_BAD);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ break;
+ }
+
+ new_attr->ar_attribute = attr;
+ new_attr->ar_attribute_form = DW_FORM_string;
+ new_attr->ar_nbytes = strlen(string) + 1;
+ new_attr->ar_next = 0;
+
+ new_attr->ar_data =
+ (char *) _dwarf_p_get_alloc(dbg, strlen(string)+1);
+ if (new_attr->ar_data == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ strcpy(new_attr->ar_data, string);
+ new_attr->ar_rel_type = R_MIPS_NONE;
+ new_attr->ar_reloc_len = 0; /* unused for R_MIPS_NONE */
+
+ /* add attribute to the die */
+ _dwarf_pro_add_at_to_die(ownerdie, new_attr);
+ return new_attr;
+}
+
+
+Dwarf_P_Attribute
+dwarf_add_AT_const_value_string(Dwarf_P_Die ownerdie,
+ char *string_value, Dwarf_Error * error)
+{
+ Dwarf_P_Attribute new_attr;
+
+ if (ownerdie == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DIE_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ new_attr = (Dwarf_P_Attribute)
+ _dwarf_p_get_alloc(ownerdie->di_dbg, sizeof(struct Dwarf_P_Attribute_s));
+ if (new_attr == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ new_attr->ar_attribute = DW_AT_const_value;
+ new_attr->ar_attribute_form = DW_FORM_string;
+ new_attr->ar_nbytes = strlen(string_value) + 1;
+ new_attr->ar_next = 0;
+
+ new_attr->ar_data =
+ (char *) _dwarf_p_get_alloc(ownerdie->di_dbg, strlen(string_value)+1);
+ if (new_attr->ar_data == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ strcpy(new_attr->ar_data, string_value);
+ new_attr->ar_rel_type = R_MIPS_NONE;
+ new_attr->ar_reloc_len = 0; /* unused for R_MIPS_NONE */
+
+ /* add attribute to the die */
+ _dwarf_pro_add_at_to_die(ownerdie, new_attr);
+ return new_attr;
+}
+
+
+Dwarf_P_Attribute
+dwarf_add_AT_producer(Dwarf_P_Die ownerdie,
+ char *producer_string, Dwarf_Error * error)
+{
+ Dwarf_P_Attribute new_attr;
+
+ if (ownerdie == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DIE_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ new_attr = (Dwarf_P_Attribute)
+ _dwarf_p_get_alloc(ownerdie->di_dbg, sizeof(struct Dwarf_P_Attribute_s));
+ if (new_attr == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ new_attr->ar_attribute = DW_AT_producer;
+ new_attr->ar_attribute_form = DW_FORM_string;
+ new_attr->ar_nbytes = strlen(producer_string) + 1;
+ new_attr->ar_next = 0;
+
+ new_attr->ar_data =
+ (char *) _dwarf_p_get_alloc(ownerdie->di_dbg, strlen(producer_string)+1);
+ if (new_attr->ar_data == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ strcpy(new_attr->ar_data, producer_string);
+ new_attr->ar_rel_type = R_MIPS_NONE;
+ new_attr->ar_reloc_len = 0; /* unused for R_MIPS_NONE */
+
+ /* add attribute to the die */
+ _dwarf_pro_add_at_to_die(ownerdie, new_attr);
+ return new_attr;
+}
+
+
+Dwarf_P_Attribute
+dwarf_add_AT_const_value_signedint(Dwarf_P_Die ownerdie,
+ Dwarf_Signed signed_value,
+ Dwarf_Error * error)
+{
+ Dwarf_P_Attribute new_attr;
+ int leb_size;
+ char encode_buffer[ENCODE_SPACE_NEEDED];
+ int res;
+
+ if (ownerdie == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DIE_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ new_attr = (Dwarf_P_Attribute)
+ _dwarf_p_get_alloc(ownerdie->di_dbg, sizeof(struct Dwarf_P_Attribute_s));
+ if (new_attr == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ new_attr->ar_attribute = DW_AT_const_value;
+ new_attr->ar_attribute_form = DW_FORM_sdata;
+ new_attr->ar_rel_type = R_MIPS_NONE;
+ new_attr->ar_reloc_len = 0; /* unused for R_MIPS_NONE */
+ new_attr->ar_next = 0;
+
+ res = _dwarf_pro_encode_signed_leb128_nm(signed_value, &leb_size,
+ encode_buffer,
+ sizeof(encode_buffer));
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(NULL, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ new_attr->ar_data = (char *)
+ _dwarf_p_get_alloc(ownerdie->di_dbg, leb_size);
+ if (new_attr->ar_data == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ memcpy(new_attr->ar_data, encode_buffer, leb_size);
+ new_attr->ar_nbytes = leb_size;
+
+ /* add attribute to the die */
+ _dwarf_pro_add_at_to_die(ownerdie, new_attr);
+ return new_attr;
+}
+
+
+Dwarf_P_Attribute
+dwarf_add_AT_const_value_unsignedint(Dwarf_P_Die ownerdie,
+ Dwarf_Unsigned unsigned_value,
+ Dwarf_Error * error)
+{
+ Dwarf_P_Attribute new_attr;
+ int leb_size;
+ char encode_buffer[ENCODE_SPACE_NEEDED];
+ int res;
+
+ if (ownerdie == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DIE_NULL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ new_attr = (Dwarf_P_Attribute)
+ _dwarf_p_get_alloc(ownerdie->di_dbg, sizeof(struct Dwarf_P_Attribute_s));
+ if (new_attr == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+
+ new_attr->ar_attribute = DW_AT_const_value;
+ new_attr->ar_attribute_form = DW_FORM_udata;
+ new_attr->ar_rel_type = R_MIPS_NONE;
+ new_attr->ar_reloc_len = 0; /* unused for R_MIPS_NONE */
+ new_attr->ar_next = 0;
+
+ res = _dwarf_pro_encode_leb128_nm(unsigned_value, &leb_size,
+ encode_buffer,
+ sizeof(encode_buffer));
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(NULL, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ new_attr->ar_data = (char *)
+ _dwarf_p_get_alloc(ownerdie->di_dbg, leb_size);
+ if (new_attr->ar_data == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_ALLOC_FAIL);
+ return ((Dwarf_P_Attribute) DW_DLV_BADADDR);
+ }
+ memcpy(new_attr->ar_data, encode_buffer, leb_size);
+ new_attr->ar_nbytes = leb_size;
+
+ /* add attribute to the die */
+ _dwarf_pro_add_at_to_die(ownerdie, new_attr);
+ return new_attr;
+}
diff --git a/usr/src/lib/libdwarf/common/pro_frame.c b/usr/src/lib/libdwarf/common/pro_frame.c
new file mode 100644
index 0000000000..bd1ef6a637
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_frame.c
@@ -0,0 +1,598 @@
+/*
+
+ Copyright (C) 2000,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
+
+*/
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include "pro_incl.h"
+#include "pro_frame.h"
+
+static void _dwarf_pro_add_to_fde(Dwarf_P_Fde fde,
+ Dwarf_P_Frame_Pgm inst);
+
+/*-------------------------------------------------------------------------
+ This function adds a cie struct to the debug pointer. Its in the
+ form of a linked list.
+ augmenter: string reps augmentation (implementation defined)
+ code_align: alignment of code
+ data_align: alignment of data
+ init_bytes: byts having initial instructions
+ init_n_bytes: number of bytes of initial instructions
+--------------------------------------------------------------------------*/
+Dwarf_Unsigned
+dwarf_add_frame_cie(Dwarf_P_Debug dbg,
+ char *augmenter,
+ Dwarf_Small code_align,
+ Dwarf_Small data_align,
+ Dwarf_Small return_reg,
+ Dwarf_Ptr init_bytes,
+ Dwarf_Unsigned init_n_bytes, Dwarf_Error * error)
+{
+ Dwarf_P_Cie curcie;
+
+ if (dbg->de_frame_cies == NULL) {
+ dbg->de_frame_cies = (Dwarf_P_Cie)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Cie_s));
+ if (dbg->de_frame_cies == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_CIE_ALLOC, DW_DLV_NOCOUNT);
+ }
+ curcie = dbg->de_frame_cies;
+ dbg->de_n_cie = 1;
+ dbg->de_last_cie = curcie;
+ } else {
+ curcie = dbg->de_last_cie;
+ curcie->cie_next = (Dwarf_P_Cie)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Cie_s));
+ if (curcie->cie_next == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_CIE_ALLOC, DW_DLV_NOCOUNT);
+ }
+ curcie = curcie->cie_next;
+ dbg->de_n_cie++;
+ dbg->de_last_cie = curcie;
+ }
+ curcie->cie_version = DW_CIE_VERSION;
+ curcie->cie_aug = augmenter;
+ curcie->cie_code_align = code_align;
+ curcie->cie_data_align = data_align;
+ curcie->cie_ret_reg = return_reg;
+ curcie->cie_inst = (char *) init_bytes;
+ curcie->cie_inst_bytes = (long) init_n_bytes;
+ curcie->cie_next = NULL;
+ return dbg->de_n_cie;
+}
+
+
+/*-------------------------------------------------------------------------
+ This functions adds a fde struct to the debug pointer. Its in the
+ form of a linked list.
+ die: subprogram/function die corresponding to this fde
+ cie: cie referred to by this fde, obtained from call to
+ add_frame_cie() routine.
+ virt_addr: beginning address
+ code_len: length of code reps by the fde
+--------------------------------------------------------------------------*/
+ /*ARGSUSED*/ /* pretend all args used */
+ Dwarf_Unsigned
+dwarf_add_frame_fde(Dwarf_P_Debug dbg,
+ Dwarf_P_Fde fde,
+ Dwarf_P_Die die,
+ Dwarf_Unsigned cie,
+ Dwarf_Unsigned virt_addr,
+ Dwarf_Unsigned code_len,
+ Dwarf_Unsigned symidx, Dwarf_Error * error)
+{
+ return dwarf_add_frame_fde_b(dbg, fde, die, cie, virt_addr,
+ code_len, symidx, 0, 0, error);
+}
+
+/*ARGSUSED10*/
+Dwarf_Unsigned
+dwarf_add_frame_fde_b(Dwarf_P_Debug dbg,
+ Dwarf_P_Fde fde,
+ Dwarf_P_Die die,
+ Dwarf_Unsigned cie,
+ Dwarf_Unsigned virt_addr,
+ Dwarf_Unsigned code_len,
+ Dwarf_Unsigned symidx,
+ Dwarf_Unsigned symidx_of_end,
+ Dwarf_Addr offset_from_end_sym,
+ Dwarf_Error * error)
+{
+ Dwarf_P_Fde curfde;
+
+ fde->fde_die = die;
+ fde->fde_cie = (long) cie;
+ fde->fde_initloc = virt_addr;
+ fde->fde_r_symidx = symidx;
+ fde->fde_addr_range = code_len;
+ fde->fde_offset_into_exception_tables = DW_DLX_NO_EH_OFFSET;
+ fde->fde_exception_table_symbol = 0;
+ fde->fde_end_symbol_offset = offset_from_end_sym;
+ fde->fde_end_symbol = symidx_of_end;
+ fde->fde_dbg = dbg;
+
+ curfde = dbg->de_last_fde;
+ if (curfde == NULL) {
+ dbg->de_frame_fdes = fde;
+ dbg->de_last_fde = fde;
+ dbg->de_n_fde = 1;
+ } else {
+ curfde->fde_next = fde;
+ dbg->de_last_fde = fde;
+ dbg->de_n_fde++;
+ }
+ return dbg->de_n_fde;
+}
+
+/*-------------------------------------------------------------------------
+ This functions adds information to an fde. The fde is
+ linked into the linked list of fde's maintained in the Dwarf_P_Debug
+ structure.
+ dbg: The debug descriptor.
+ fde: The fde to be added.
+ die: subprogram/function die corresponding to this fde
+ cie: cie referred to by this fde, obtained from call to
+ add_frame_cie() routine.
+ virt_addr: beginning address
+ code_len: length of code reps by the fde
+ symidx: The symbol id of the symbol wrt to which relocation needs
+ to be performed for 'virt_addr'.
+ offset_into_exception_tables: The start of exception tables for
+ this function (indicated as an offset into the exception
+ tables). A value of -1 indicates that there is no exception
+ table entries associated with this function.
+ exception_table_symbol: The symbol id of the section for exception
+ tables wrt to which the offset_into_exception_tables will
+ be relocated.
+--------------------------------------------------------------------------*/
+Dwarf_Unsigned
+dwarf_add_frame_info(Dwarf_P_Debug dbg,
+ Dwarf_P_Fde fde,
+ Dwarf_P_Die die,
+ Dwarf_Unsigned cie,
+ Dwarf_Unsigned virt_addr,
+ Dwarf_Unsigned code_len,
+ Dwarf_Unsigned symidx,
+ Dwarf_Signed offset_into_exception_tables,
+ Dwarf_Unsigned exception_table_symbol,
+ Dwarf_Error * error)
+{
+
+ return dwarf_add_frame_info_b(dbg, fde, die, cie, virt_addr,
+ code_len, symidx,
+ /* end_symbol */ 0,
+ /* offset_from_end */ 0,
+ offset_into_exception_tables,
+ exception_table_symbol, error);
+
+}
+
+ /*ARGSUSED*/ /* pretend all args used */
+Dwarf_Unsigned
+dwarf_add_frame_info_b(Dwarf_P_Debug dbg,
+ Dwarf_P_Fde fde,
+ Dwarf_P_Die die,
+ Dwarf_Unsigned cie,
+ Dwarf_Unsigned virt_addr,
+ Dwarf_Unsigned code_len,
+ Dwarf_Unsigned symidx,
+ Dwarf_Unsigned end_symidx,
+ Dwarf_Unsigned offset_from_end_symbol,
+ Dwarf_Signed offset_into_exception_tables,
+ Dwarf_Unsigned exception_table_symbol,
+ Dwarf_Error * error)
+{
+ Dwarf_P_Fde curfde;
+
+ fde->fde_die = die;
+ fde->fde_cie = (long) cie;
+ fde->fde_initloc = virt_addr;
+ fde->fde_r_symidx = symidx;
+ fde->fde_addr_range = code_len;
+ fde->fde_offset_into_exception_tables =
+ offset_into_exception_tables;
+ fde->fde_exception_table_symbol = exception_table_symbol;
+ fde->fde_end_symbol_offset = offset_from_end_symbol;
+ fde->fde_end_symbol = end_symidx;
+ fde->fde_dbg = dbg;
+
+ curfde = dbg->de_last_fde;
+ if (curfde == NULL) {
+ dbg->de_frame_fdes = fde;
+ dbg->de_last_fde = fde;
+ dbg->de_n_fde = 1;
+ } else {
+ curfde->fde_next = fde;
+ dbg->de_last_fde = fde;
+ dbg->de_n_fde++;
+ }
+ return dbg->de_n_fde;
+}
+
+/* This is an alternate to inserting frame instructions
+ one instruction at a time. But use either this
+ or instruction level, not both in one fde. */
+int
+dwarf_insert_fde_inst_bytes(Dwarf_P_Debug dbg,
+ Dwarf_P_Fde fde,Dwarf_Unsigned len, Dwarf_Ptr ibytes,
+ Dwarf_Error *error)
+{
+ if( len == 0) {
+ return DW_DLV_OK;
+ }
+ if(fde->fde_block || fde->fde_inst) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_DUPLICATE_INST_BLOCK,
+ (int)DW_DLV_BADADDR);
+ }
+ fde->fde_block = (Dwarf_Ptr)_dwarf_p_get_alloc(dbg, len);
+ memcpy(fde->fde_block,ibytes,len);
+ fde->fde_inst_block_size = len;
+ fde->fde_n_bytes += len;
+ return DW_DLV_OK;
+}
+
+
+
+/*-------------------------------------------------------------------
+ Create a new fde.
+---------------------------------------------------------------------*/
+Dwarf_P_Fde
+dwarf_new_fde(Dwarf_P_Debug dbg, Dwarf_Error * error)
+{
+ Dwarf_P_Fde fde;
+
+ fde = (Dwarf_P_Fde)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Fde_s));
+ if (fde == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_FDE_ALLOC,
+ (Dwarf_P_Fde) DW_DLV_BADADDR);
+ }
+
+ fde->fde_uwordb_size = dbg->de_offset_size;
+
+ return fde;
+}
+
+
+/*------------------------------------------------------------------------
+ Add a cfe_offset instruction to the fde passed in.
+-------------------------------------------------------------------------*/
+Dwarf_P_Fde
+dwarf_fde_cfa_offset(Dwarf_P_Fde fde,
+ Dwarf_Unsigned reg,
+ Dwarf_Signed offset, Dwarf_Error * error)
+{
+ Dwarf_Ubyte opc, regno;
+ char *ptr;
+ Dwarf_P_Frame_Pgm curinst;
+ int nbytes;
+ int res;
+ char buff1[ENCODE_SPACE_NEEDED];
+ Dwarf_P_Debug dbg = fde->fde_dbg;
+
+ curinst = (Dwarf_P_Frame_Pgm)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Frame_Pgm_s));
+ if (curinst == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_FPGM_ALLOC,
+ (Dwarf_P_Fde) DW_DLV_BADADDR);
+ }
+ opc = DW_CFA_offset;
+ regno = reg;
+ if (regno & 0xc0) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_REGNO_OVFL,
+ (Dwarf_P_Fde) DW_DLV_BADADDR);
+ }
+ opc = opc | regno; /* lower 6 bits are register number */
+ curinst->dfp_opcode = opc;
+ res = _dwarf_pro_encode_leb128_nm(offset, &nbytes,
+ buff1, sizeof(buff1));
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC);
+ return ((Dwarf_P_Fde) DW_DLV_BADADDR);
+ }
+ ptr = (char *) _dwarf_p_get_alloc(dbg, nbytes);
+ if (ptr == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC);
+ return ((Dwarf_P_Fde) DW_DLV_BADADDR);
+ }
+ memcpy(ptr, buff1, nbytes);
+
+ curinst->dfp_args = ptr;
+ curinst->dfp_nbytes = nbytes;
+ curinst->dfp_next = NULL;
+
+ _dwarf_pro_add_to_fde(fde, curinst);
+ return fde;
+}
+
+/*
+ Generic routine to add opcode to fde instructions. val1 and
+ val2 are parameters whose interpretation depends on the 'op'.
+
+ This does not work properly for DW_DLC_SYMBOLIC_RELOCATIONS
+ for DW_CFA_set_loc or DW_DVA_advance_loc* 'op', as
+ these ops normally are addresses or (DW_CFA_set_loc)
+ or code lengths (DW_DVA_advance_loc*) and such must be
+ represented with relocations and symbol indices for
+ DW_DLC_SYMBOLIC_RELOCATIONS.
+
+ This does not treat all DW_CFA instructions yet.
+
+ For certain operations a val? value must be
+ signed (though passed in as unsigned here).
+
+ Currently this does not check that the frame
+ version is 3(for dwarf3) or 4 (for dwarf4)
+ when applying operations that are only valid for
+ dwarf3 or dwarf4.
+
+*/
+Dwarf_P_Fde
+dwarf_add_fde_inst(Dwarf_P_Fde fde,
+ Dwarf_Small op,
+ Dwarf_Unsigned val1,
+ Dwarf_Unsigned val2, Dwarf_Error * error)
+{
+ Dwarf_P_Frame_Pgm curinst;
+ int nbytes, nbytes1, nbytes2;
+ Dwarf_Ubyte db;
+ Dwarf_Half dh;
+ Dwarf_Word dw;
+ Dwarf_Unsigned du;
+ char *ptr;
+ int res;
+ char buff1[ENCODE_SPACE_NEEDED];
+ char buff2[ENCODE_SPACE_NEEDED];
+ Dwarf_P_Debug dbg = fde->fde_dbg;
+ /* This is a hack telling the code when to transform
+ a value to a signed leb number. */
+ int signed_second = 0;
+ int signed_first = 0;
+
+
+ nbytes = 0;
+ ptr = NULL;
+ curinst = (Dwarf_P_Frame_Pgm)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Frame_Pgm_s));
+ if (curinst == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_FPGM_ALLOC);
+ return ((Dwarf_P_Fde) DW_DLV_BADADDR);
+ }
+
+ switch (op) {
+
+ case DW_CFA_advance_loc:
+ if (val1 <= 0x3f) {
+ db = val1;
+ op |= db;
+ }
+ /* test not portable FIX */
+ else if (val1 <= UCHAR_MAX) {
+ op = DW_CFA_advance_loc1;
+ db = val1;
+ ptr = (char *) _dwarf_p_get_alloc(dbg, 1);
+ if (ptr == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC);
+ return ((Dwarf_P_Fde) DW_DLV_BADADDR);
+ }
+ memcpy((void *) ptr, (const void *) &db, 1);
+ nbytes = 1;
+ }
+ /* test not portable FIX */
+ else if (val1 <= USHRT_MAX) {
+ op = DW_CFA_advance_loc2;
+ dh = val1;
+ ptr = (char *) _dwarf_p_get_alloc(dbg, 2);
+ if (ptr == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC);
+ return ((Dwarf_P_Fde) DW_DLV_BADADDR);
+ }
+ memcpy((void *) ptr, (const void *) &dh, 2);
+ nbytes = 2;
+ }
+ /* test not portable FIX */
+ else if (val1 <= ULONG_MAX) {
+ op = DW_CFA_advance_loc4;
+ dw = (Dwarf_Word) val1;
+ ptr = (char *) _dwarf_p_get_alloc(dbg, 4);
+ if (ptr == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC);
+ return ((Dwarf_P_Fde) DW_DLV_BADADDR);
+ }
+ memcpy((void *) ptr, (const void *) &dw, 4);
+ nbytes = 4;
+ } else {
+ op = DW_CFA_MIPS_advance_loc8;
+ du = val1;
+ ptr =
+ (char *) _dwarf_p_get_alloc(dbg,
+ sizeof(Dwarf_Unsigned));
+ if (ptr == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC);
+ return ((Dwarf_P_Fde) DW_DLV_BADADDR);
+ }
+ memcpy((void *) ptr, (const void *) &du, 8);
+ nbytes = 8;
+ }
+ break;
+
+ case DW_CFA_offset:
+ if (val1 <= MAX_6_BIT_VALUE) {
+ db = val1;
+ op |= db;
+ res = _dwarf_pro_encode_leb128_nm(val2, &nbytes,
+ buff1, sizeof(buff1));
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC);
+ return ((Dwarf_P_Fde) DW_DLV_BADADDR);
+ }
+ ptr = (char *) _dwarf_p_get_alloc(dbg, nbytes);
+ if (ptr == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC);
+ return ((Dwarf_P_Fde) DW_DLV_BADADDR);
+ }
+ memcpy(ptr, buff1, nbytes);
+
+ } else {
+ op = DW_CFA_offset_extended;
+ goto two_leb;
+ }
+ break;
+ case DW_CFA_offset_extended_sf: /* DWARF3 */
+ signed_second = 1;
+ goto two_leb;
+ case DW_CFA_offset_extended:
+ goto two_leb;
+
+ case DW_CFA_undefined:
+ case DW_CFA_same_value:
+ goto one_leb;
+
+ case DW_CFA_val_offset:
+ goto two_leb;
+ case DW_CFA_val_offset_sf:
+ signed_second = 1;
+ goto two_leb;
+ case DW_CFA_def_cfa_sf:
+ signed_second = 1;
+ goto two_leb;
+ case DW_CFA_register:
+ case DW_CFA_def_cfa:
+ two_leb:
+ res = _dwarf_pro_encode_leb128_nm(val1, &nbytes1,
+ buff1, sizeof(buff1));
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC);
+ return ((Dwarf_P_Fde) DW_DLV_BADADDR);
+ }
+ if (!signed_second) {
+ res = _dwarf_pro_encode_leb128_nm(val2, &nbytes2,
+ buff2, sizeof(buff2));
+ } else {
+ Dwarf_Signed val2s = val2;
+ res = _dwarf_pro_encode_signed_leb128_nm(val2s, &nbytes2,
+ buff2, sizeof(buff2));
+ }
+
+ res = _dwarf_pro_encode_leb128_nm(val2, &nbytes2,
+ buff2, sizeof(buff2));
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC);
+ return ((Dwarf_P_Fde) DW_DLV_BADADDR);
+ }
+
+ ptr = (char *) _dwarf_p_get_alloc(dbg, nbytes1 + nbytes2);
+ if (ptr == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC);
+ return ((Dwarf_P_Fde) DW_DLV_BADADDR);
+ }
+ memcpy(ptr, buff1, nbytes1);
+ memcpy(ptr + nbytes1, buff2, nbytes2);
+ nbytes = nbytes1 + nbytes2;
+ break;
+
+ case DW_CFA_def_cfa_offset_sf: /* DWARF3 */
+ signed_first = 1;
+ goto one_leb;
+ case DW_CFA_def_cfa_register:
+ case DW_CFA_def_cfa_offset:
+ one_leb:
+ if(!signed_first) {
+ res = _dwarf_pro_encode_leb128_nm(val1, &nbytes,
+ buff1, sizeof(buff1));
+ } else {
+ Dwarf_Signed val1s = val1;
+ res = _dwarf_pro_encode_signed_leb128_nm(val1s, &nbytes,
+ buff1, sizeof(buff1));
+ }
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC);
+ return ((Dwarf_P_Fde) DW_DLV_BADADDR);
+ }
+ ptr = (char *) _dwarf_p_get_alloc(dbg, nbytes);
+ if (ptr == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_STRING_ALLOC);
+ return ((Dwarf_P_Fde) DW_DLV_BADADDR);
+ }
+ memcpy(ptr, buff1, nbytes);
+ break;
+ case DW_CFA_def_cfa_expression: /* DWARF3 */
+ /* FIXME: argument is dwarf expr, not handled yet. */
+ case DW_CFA_expression: /* DWARF3 */
+ /* First arg: ULEB reg num. 2nd arg dwarf expr in form block.
+ FIXME: not handled yet. */
+ case DW_CFA_val_expression: /* DWARF3f */
+ /* First arg: ULEB reg num. 2nd arg dwarf expr in form block.
+ FIXME: not handled yet. */
+ default:
+ _dwarf_p_error(dbg, error, DW_DLE_DEBUGFRAME_ERROR);
+ return ((Dwarf_P_Fde) DW_DLV_BADADDR);
+ }
+
+ curinst->dfp_opcode = op;
+ curinst->dfp_args = ptr;
+ curinst->dfp_nbytes = nbytes;
+ curinst->dfp_next = NULL;
+
+ _dwarf_pro_add_to_fde(fde, curinst);
+ return fde;
+}
+
+
+/*------------------------------------------------------------------------
+ Instructions are added to an fde in the form of a linked
+ list. This function manages the linked list.
+-------------------------------------------------------------------------*/
+void
+_dwarf_pro_add_to_fde(Dwarf_P_Fde fde, Dwarf_P_Frame_Pgm curinst)
+{
+ if (fde->fde_last_inst) {
+ fde->fde_last_inst->dfp_next = curinst;
+ fde->fde_last_inst = curinst;
+ fde->fde_n_inst++;
+ fde->fde_n_bytes +=
+ (long) (curinst->dfp_nbytes + sizeof(Dwarf_Ubyte));
+ } else {
+ fde->fde_last_inst = curinst;
+ fde->fde_inst = curinst;
+ fde->fde_n_inst = 1;
+ fde->fde_n_bytes =
+ (long) (curinst->dfp_nbytes + sizeof(Dwarf_Ubyte));
+ }
+}
diff --git a/usr/src/lib/libdwarf/common/pro_frame.h b/usr/src/lib/libdwarf/common/pro_frame.h
new file mode 100644
index 0000000000..df60d369ed
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_frame.h
@@ -0,0 +1,132 @@
+/*
+
+ Copyright (C) 2000,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
+
+*/
+
+
+
+/*
+ Largest register value that can be coded into
+ the opcode since there are only 6 bits in the
+ register field.
+*/
+#define MAX_6_BIT_VALUE 0x3f
+
+/*
+ This struct holds debug_frame instructions
+*/
+typedef struct Dwarf_P_Frame_Pgm_s *Dwarf_P_Frame_Pgm;
+
+struct Dwarf_P_Frame_Pgm_s {
+ Dwarf_Ubyte dfp_opcode; /* opcode - includes reg # */
+ char *dfp_args; /* operands */
+ int dfp_nbytes; /* number of bytes in args */
+#if 0
+ Dwarf_Unsigned dfp_sym_index; /* 0 unless reloc needed */
+#endif
+ Dwarf_P_Frame_Pgm dfp_next;
+};
+
+
+/*
+ This struct has cie related information. Used to gather data
+ from user program, and later to transform to disk form
+*/
+struct Dwarf_P_Cie_s {
+ Dwarf_Ubyte cie_version;
+ char *cie_aug; /* augmentation */
+ Dwarf_Ubyte cie_code_align; /* alignment of code */
+ Dwarf_Sbyte cie_data_align;
+ Dwarf_Ubyte cie_ret_reg; /* return register # */
+ char *cie_inst; /* initial instruction */
+ long cie_inst_bytes;
+ /* no of init_inst */
+ Dwarf_P_Cie cie_next;
+};
+
+
+/* producer fields */
+struct Dwarf_P_Fde_s {
+ Dwarf_Unsigned fde_unused1;
+
+ /* function/subr die for this fde */
+ Dwarf_P_Die fde_die;
+
+ /* index to asso. cie */
+ Dwarf_Word fde_cie;
+
+ /* Address of first location of the code this frame applies to If
+ fde_end_symbol non-zero, this represents the offset from the
+ symbol indicated by fde_r_symidx */
+ Dwarf_Addr fde_initloc;
+
+ /* Relocation symbol for address of the code this frame applies to.
+ */
+ Dwarf_Unsigned fde_r_symidx;
+
+ /* Bytes of instr for this fde, if known */
+ Dwarf_Unsigned fde_addr_range;
+
+ /* linked list of instructions we will put in fde. */
+ Dwarf_P_Frame_Pgm fde_inst;
+
+ /* number of instructions in fde */
+ long fde_n_inst;
+
+ /* number of bytes of inst in fde */
+ long fde_n_bytes;
+
+ /* offset into exception table for this function. */
+ Dwarf_Signed fde_offset_into_exception_tables;
+
+ /* The symbol for the exception table elf section. */
+ Dwarf_Unsigned fde_exception_table_symbol;
+
+ /* pointer to last inst */
+ Dwarf_P_Frame_Pgm fde_last_inst;
+
+ Dwarf_P_Fde fde_next;
+
+ /* The symbol and offset of the end symbol. When fde_end_symbol is
+ non-zero we must represent the */
+ Dwarf_Addr fde_end_symbol_offset;
+ Dwarf_Unsigned fde_end_symbol;
+
+ int fde_uwordb_size;
+ Dwarf_P_Debug fde_dbg;
+
+ /* If fde_block is non-null, then it is the set of instructions.
+ so we should use it rather than fde_inst. */
+ Dwarf_Unsigned fde_inst_block_size;
+ void *fde_block;
+};
diff --git a/usr/src/lib/libdwarf/common/pro_funcs.c b/usr/src/lib/libdwarf/common/pro_funcs.c
new file mode 100644
index 0000000000..8ff05500bb
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_funcs.c
@@ -0,0 +1,62 @@
+/*
+
+ Copyright (C) 2000,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
+
+*/
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_ELFACCESS_H
+#include <elfaccess.h>
+#endif
+#include "pro_incl.h"
+#include "pro_section.h"
+
+/*
+ This function adds another function name to the
+ list of function names for the given Dwarf_P_Debug.
+ It returns 0 on error, and 1 otherwise.
+*/
+Dwarf_Unsigned
+dwarf_add_funcname(Dwarf_P_Debug dbg,
+ Dwarf_P_Die die,
+ char *function_name, Dwarf_Error * error)
+{
+ return
+ _dwarf_add_simple_name_entry(dbg, die, function_name,
+ dwarf_snk_funcname, error);
+
+}
diff --git a/usr/src/lib/libdwarf/common/pro_incl.h b/usr/src/lib/libdwarf/common/pro_incl.h
new file mode 100644
index 0000000000..10bce470c2
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_incl.h
@@ -0,0 +1,92 @@
+/*
+
+ Copyright (C) 2000,2002,2004 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright 2002-2010 Sun Microsystems, Inc. All rights reserved.
+ Portions Copyright 2008-2010 David Anderson. 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
+
+*/
+
+
+#ifdef HAVE_ELF_H
+#include <elf.h>
+#elif defined(HAVE_LIBELF_H)
+/* On one platform without elf.h this gets Elf32_Rel
+ type defined (a required type). */
+#include <libelf.h>
+#endif
+
+#if defined(sun)
+#include <sys/elf_SPARC.h>
+#include <sys/elf_386.h>
+#endif
+
+/* The target address is given: the place in the source integer
+ is to be determined.
+*/
+#ifdef WORDS_BIGENDIAN
+#define WRITE_UNALIGNED(dbg,dest,source, srclength,len_out) \
+ { \
+ dbg->de_copy_word(dest, \
+ ((char *)source) +srclength-len_out, \
+ len_out) ; \
+ }
+
+
+#else /* LITTLE ENDIAN */
+
+#define WRITE_UNALIGNED(dbg,dest,source, srclength,len_out) \
+ { \
+ dbg->de_copy_word( (dest) , \
+ ((char *)source) , \
+ len_out) ; \
+ }
+#endif
+
+
+#if defined(sparc) && defined(sun)
+#define REL32 Elf32_Rela
+#define REL64 Elf64_Rela
+#define REL_SEC_PREFIX ".rela"
+#else
+#define REL32 Elf32_Rel
+#define REL64 Elf64_Rel
+#define REL_SEC_PREFIX ".rel"
+#endif
+
+#include "dwarf.h"
+#include "libdwarf.h"
+
+#include "pro_opaque.h"
+#include "pro_error.h"
+#include "pro_util.h"
+#include "pro_encode_nm.h"
+#include "pro_alloc.h"
diff --git a/usr/src/lib/libdwarf/common/pro_init.c b/usr/src/lib/libdwarf/common/pro_init.c
new file mode 100644
index 0000000000..d696113a67
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_init.c
@@ -0,0 +1,261 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright 2002-2010 Sun Microsystems, Inc. All rights reserved.
+ Portions Copyright 2008-2010 David Anderson, 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
+
+*/
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#include <stdio.h>
+#include <string.h>
+#include "pro_incl.h"
+#include "pro_section.h" /* for MAGIC_SECT_NO */
+#include "pro_reloc_symbolic.h"
+#include "pro_reloc_stream.h"
+
+
+static void common_init(Dwarf_P_Debug dbg, Dwarf_Unsigned flags);
+
+void *_dwarf_memcpy_swap_bytes(void *s1, const void *s2, size_t len);
+
+/*--------------------------------------------------------------------
+ This function sets up a new dwarf producing region.
+ flags: Indicates type of access method, one of DW_DLC* macros
+ func(): Used to create a new object file, a call back function
+ errhand(): Error Handler provided by user
+ errarg: Argument to errhand()
+ error: returned error value
+--------------------------------------------------------------------*/
+ /* We want the following to have an elf section number that matches
+ 'nothing' */
+static struct Dwarf_P_Section_Data_s init_sect = {
+ MAGIC_SECT_NO, 0, 0, 0, 0
+};
+
+Dwarf_P_Debug
+dwarf_producer_init_b(Dwarf_Unsigned flags,
+ Dwarf_Callback_Func_b func,
+ Dwarf_Handler errhand,
+ Dwarf_Ptr errarg, Dwarf_Error * error)
+{
+ Dwarf_P_Debug dbg;
+ dbg = (Dwarf_P_Debug) _dwarf_p_get_alloc(NULL,
+ sizeof(struct
+ Dwarf_P_Debug_s));
+ if (dbg == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_DBG_ALLOC,
+ (Dwarf_P_Debug) DW_DLV_BADADDR);
+ }
+ memset((void *) dbg, 0, sizeof(struct Dwarf_P_Debug_s));
+ /* For the time being */
+ if (func == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_NO_CALLBACK_FUNC,
+ (Dwarf_P_Debug) DW_DLV_BADADDR);
+ }
+ dbg->de_callback_func_b = func;
+ dbg->de_errhand = errhand;
+ dbg->de_errarg = errarg;
+ common_init(dbg, flags);
+ return dbg;
+
+}
+
+Dwarf_P_Debug
+dwarf_producer_init(Dwarf_Unsigned flags,
+ Dwarf_Callback_Func func,
+ Dwarf_Handler errhand,
+ Dwarf_Ptr errarg, Dwarf_Error * error)
+{
+
+ Dwarf_P_Debug dbg;
+
+
+
+ dbg = (Dwarf_P_Debug) _dwarf_p_get_alloc(NULL,
+ sizeof(struct
+ Dwarf_P_Debug_s));
+ if (dbg == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_DBG_ALLOC,
+ (Dwarf_P_Debug) DW_DLV_BADADDR);
+ }
+ memset((void *) dbg, 0, sizeof(struct Dwarf_P_Debug_s));
+ /* For the time being */
+ if (func == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_NO_CALLBACK_FUNC,
+ (Dwarf_P_Debug) DW_DLV_BADADDR);
+ }
+ dbg->de_callback_func = func;
+ dbg->de_errhand = errhand;
+ dbg->de_errarg = errarg;
+ common_init(dbg, flags);
+ return dbg;
+}
+static void
+common_init(Dwarf_P_Debug dbg, Dwarf_Unsigned flags)
+{
+ unsigned int k;
+
+
+ dbg->de_version_magic_number = PRO_VERSION_MAGIC;
+ dbg->de_n_debug_sect = 0;
+ dbg->de_debug_sects = &init_sect;
+ dbg->de_current_active_section = &init_sect;
+ dbg->de_flags = flags;
+
+ /* Now, with flags set, can use 64bit tests */
+
+
+
+#if defined(HAVE_STRICT_DWARF2_32BIT_OFFSET)
+ /* This is cygnus 32bit offset, as specified in pure dwarf2 v2.0.0.
+ It is consistent with normal DWARF2/3 generation of always
+ generating 32 bit offsets. */
+ dbg->de_64bit_extension = 0;
+ dbg->de_pointer_size = (IS_64BIT(dbg) ? 8 : 4);
+ dbg->de_offset_size = (IS_64BIT(dbg) ? 4 : 4);
+ dbg->de_ptr_reloc =
+ IS_64BIT(dbg) ? Get_REL64_isa(dbg) : Get_REL32_isa(dbg);
+ /* non-MIPS, dwarf lengths and offsets are 32 bits even for 64bit
+ pointer environments. */
+ /* Get_REL32_isa here supports 64-bit-pointer dwarf with pure
+ dwarf2 v2.0.0 32bit offsets, as emitted by cygnus tools. And
+ pure 32 bit offset dwarf for 32bit pointer apps. */
+
+ dbg->de_offset_reloc = Get_REL32_isa(dbg);
+#elif defined(HAVE_SGI_IRIX_OFFSETS)
+ /* MIPS-SGI-IRIX 32 or 64, where offsets and lengths are both 64 bit for
+ 64bit pointer objects and both 32 bit for 32bit pointer objects.
+ And a dwarf-reader must check elf info to tell which applies. */
+ dbg->de_64bit_extension = 0;
+ dbg->de_pointer_size = (IS_64BIT(dbg) ? 8 : 4);
+ dbg->de_offset_size = (IS_64BIT(dbg) ? 8 : 4);
+ dbg->de_ptr_reloc =
+ IS_64BIT(dbg) ? Get_REL64_isa(dbg) : Get_REL32_isa(dbg);
+ dbg->de_offset_reloc = dbg->de_ptr_reloc;
+#else /* HAVE_DWARF2_99_EXTENSION or default. */
+ /* Revised 64 bit output, using distingushed values. Per 1999
+ dwarf3. This allows run-time selection of offset size. */
+ dbg->de_64bit_extension = (IS_64BIT(dbg) ? 1 : 0);
+ dbg->de_pointer_size = (IS_64BIT(dbg) ? 8 : 4);
+ if( flags & DW_DLC_OFFSET_SIZE_64 && (dbg->de_pointer_size == 8)) {
+ /* When it's 64 bit address, a 64bit offset is sensible.
+ Arguably a 32 bit address with 64 bit offset could be
+ sensible, but who would want that? */
+ dbg->de_offset_size = 8;
+ dbg->de_64bit_extension = 1;
+ } else {
+ dbg->de_offset_size = 4;
+ dbg->de_64bit_extension = 0;
+ }
+ dbg->de_ptr_reloc =
+ IS_64BIT(dbg) ? Get_REL64_isa(dbg) : Get_REL32_isa(dbg);
+ /* Non-MIPS, dwarf lengths and offsets are 32 bits even for 64bit
+ pointer environments. */
+ /* Get_REL??_isa here supports 64bit-offset dwarf. For 64bit, we
+ emit the extension bytes. */
+
+ dbg->de_offset_reloc = IS_64BIT(dbg) ? Get_REL64_isa(dbg)
+ : Get_REL32_isa(dbg);
+#endif /* HAVE_DWARF2_99_EXTENSION etc. */
+
+ dbg->de_exc_reloc = Get_REL_SEGREL_isa(dbg);
+
+ dbg->de_is_64bit = IS_64BIT(dbg);
+
+
+ if (flags & DW_DLC_SYMBOLIC_RELOCATIONS) {
+ dbg->de_relocation_record_size =
+ sizeof(struct Dwarf_Relocation_Data_s);
+ } else {
+
+#if HAVE_ELF64_GETEHDR
+ dbg->de_relocation_record_size =
+ IS_64BIT(dbg)? sizeof(REL64) : sizeof(REL32);
+#else
+ dbg->de_relocation_record_size = sizeof(REL32);
+#endif
+
+ }
+
+ if (dbg->de_offset_size == 8) {
+ dbg->de_ar_data_attribute_form = DW_FORM_data8;
+ dbg->de_ar_ref_attr_form = DW_FORM_ref8;
+ } else {
+ dbg->de_ar_data_attribute_form = DW_FORM_data4;
+ dbg->de_ar_ref_attr_form = DW_FORM_ref4;
+ }
+
+ if (flags & DW_DLC_SYMBOLIC_RELOCATIONS) {
+ dbg->de_reloc_name = _dwarf_pro_reloc_name_symbolic;
+ dbg->de_reloc_pair = _dwarf_pro_reloc_length_symbolic;
+ dbg->de_transform_relocs_to_disk =
+ _dwarf_symbolic_relocs_to_disk;
+ } else {
+ if (IS_64BIT(dbg)) {
+ dbg->de_reloc_name = _dwarf_pro_reloc_name_stream64;
+ } else {
+ dbg->de_reloc_name = _dwarf_pro_reloc_name_stream32;
+ }
+ dbg->de_reloc_pair = 0;
+ dbg->de_transform_relocs_to_disk = _dwarf_stream_relocs_to_disk;
+ }
+ for (k = 0; k < NUM_DEBUG_SECTIONS; ++k) {
+
+ Dwarf_P_Per_Reloc_Sect prel = &dbg->de_reloc_sect[k];
+
+ prel->pr_slots_per_block_to_alloc = DEFAULT_SLOTS_PER_BLOCK;
+ }
+ /* First assume host, target same endianness */
+ dbg->de_same_endian = 1;
+ dbg->de_copy_word = memcpy;
+#ifdef WORDS_BIGENDIAN
+ /* host is big endian, so what endian is target? */
+ if (flags & DW_DLC_TARGET_LITTLEENDIAN) {
+ dbg->de_same_endian = 0;
+ dbg->de_copy_word = _dwarf_memcpy_swap_bytes;
+ }
+#else /* little endian */
+ /* host is little endian, so what endian is target? */
+ if (flags & DW_DLC_TARGET_BIGENDIAN) {
+ dbg->de_same_endian = 0;
+ dbg->de_copy_word = _dwarf_memcpy_swap_bytes;
+ }
+#endif /* !WORDS_BIGENDIAN */
+
+
+ return;
+
+}
diff --git a/usr/src/lib/libdwarf/common/pro_line.c b/usr/src/lib/libdwarf/common/pro_line.c
new file mode 100644
index 0000000000..69d3e339f0
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_line.c
@@ -0,0 +1,300 @@
+/*
+
+ Copyright (C) 2000,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
+
+*/
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_ELF_H
+#include <elf.h>
+#endif
+#include "pro_incl.h"
+#include "pro_line.h"
+
+Dwarf_Unsigned _dwarf_pro_add_line_entry(Dwarf_P_Debug,
+ Dwarf_Unsigned file_index,
+ Dwarf_Addr code_address,
+ Dwarf_Unsigned symidx,
+ Dwarf_Unsigned line_no,
+ Dwarf_Signed col_no,
+ Dwarf_Bool is_stmt_begin,
+ Dwarf_Bool is_bb_begin,
+ Dwarf_Ubyte opc,
+ Dwarf_Error * error);
+
+/*-------------------------------------------------------------------------
+ Add a entry to the line information section
+ file_index: index of file in file entries, obtained from
+ add_file_entry() call.
+
+ This function actually calls _dwarf_pro_add_line_entry(), with
+ an extra parameter, the opcode. Done so that interface calls
+ dwarf_lne_set_address() and dwarf_lne_end_sequence() can use
+ this internal routine.
+---------------------------------------------------------------------------*/
+Dwarf_Unsigned
+dwarf_add_line_entry(Dwarf_P_Debug dbg,
+ Dwarf_Unsigned file_index,
+ Dwarf_Addr code_address,
+ Dwarf_Unsigned line_no,
+ Dwarf_Signed col_no,
+ Dwarf_Bool is_stmt_begin,
+ Dwarf_Bool is_bb_begin, Dwarf_Error * error)
+{
+ Dwarf_Unsigned retval;
+
+ retval = _dwarf_pro_add_line_entry(dbg, file_index, code_address, 0,
+ line_no, col_no, is_stmt_begin,
+ is_bb_begin, 0, error);
+ return retval;
+}
+
+/*------------------------------------------------------------------------
+ Ask to emit DW_LNE_set_address opcode explicitly. Used by be
+ to emit start of a new .text section, or to force a relocated
+ address into debug line information entry.
+-------------------------------------------------------------------------*/
+Dwarf_Unsigned
+dwarf_lne_set_address(Dwarf_P_Debug dbg,
+ Dwarf_Addr offs,
+ Dwarf_Unsigned symidx, Dwarf_Error * error)
+{
+ Dwarf_Ubyte opc;
+ Dwarf_Unsigned retval;
+
+ opc = DW_LNE_set_address;
+ retval =
+ _dwarf_pro_add_line_entry(dbg, 0, offs, symidx, 0, 0, 0, 0, opc,
+ error);
+ return retval;
+}
+
+/*------------------------------------------------------------------------
+ Ask to emit end_seqence opcode. Used normally at the end of a
+ compilation unit. Can also be used in the middle if there
+ are gaps in the region described by the code address.
+-------------------------------------------------------------------------*/
+Dwarf_Unsigned
+dwarf_lne_end_sequence(Dwarf_P_Debug dbg,
+ Dwarf_Addr end_address, Dwarf_Error * error)
+{
+ Dwarf_Ubyte opc;
+ Dwarf_Unsigned retval;
+
+ opc = DW_LNE_end_sequence;
+ retval =
+ _dwarf_pro_add_line_entry(dbg, 0, end_address, 0, 0, 0, 0, 0,
+ opc, error);
+ return retval;
+}
+
+/*----------------------------------------------------------------------------
+ Add an entry in the internal list of lines mantained by producer.
+ Opc indicates if an opcode needs to be generated, rather than just
+ an entry in the matrix. During opcodes generation time, these
+ opcodes will be used.
+-----------------------------------------------------------------------------*/
+Dwarf_Unsigned
+_dwarf_pro_add_line_entry(Dwarf_P_Debug dbg,
+ Dwarf_Unsigned file_index,
+ Dwarf_Addr code_address,
+ Dwarf_Unsigned symidx,
+ Dwarf_Unsigned line_no,
+ Dwarf_Signed col_no,
+ Dwarf_Bool is_stmt_begin,
+ Dwarf_Bool is_bb_begin,
+ Dwarf_Ubyte opc, Dwarf_Error * error)
+{
+ if (dbg->de_lines == NULL) {
+ dbg->de_lines = (Dwarf_P_Line)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Line_s));
+ if (dbg->de_lines == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_LINE_ALLOC, DW_DLV_NOCOUNT);
+ }
+ dbg->de_last_line = dbg->de_lines;
+ _dwarf_pro_reg_init(dbg->de_lines);
+
+ } else {
+ dbg->de_last_line->dpl_next = (Dwarf_P_Line)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Line_s));
+ if (dbg->de_last_line->dpl_next == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_LINE_ALLOC, DW_DLV_NOCOUNT);
+ }
+ dbg->de_last_line = dbg->de_last_line->dpl_next;
+ _dwarf_pro_reg_init(dbg->de_last_line);
+ }
+ dbg->de_last_line->dpl_address = code_address;
+ dbg->de_last_line->dpl_file = (unsigned long) file_index;
+ dbg->de_last_line->dpl_line = (unsigned long) line_no;
+ dbg->de_last_line->dpl_column = (unsigned long) col_no;
+ dbg->de_last_line->dpl_is_stmt = is_stmt_begin;
+ dbg->de_last_line->dpl_basic_block = is_bb_begin;
+ dbg->de_last_line->dpl_opc = opc;
+ dbg->de_last_line->dpl_r_symidx = symidx;
+
+ return (0);
+}
+
+/*-----------------------------------------------------------------------
+ Add a directory declaration to the debug_line section. Stored
+ in linked list.
+------------------------------------------------------------------------*/
+Dwarf_Unsigned
+dwarf_add_directory_decl(Dwarf_P_Debug dbg,
+ char *name, Dwarf_Error * error)
+{
+ if (dbg->de_inc_dirs == NULL) {
+ dbg->de_inc_dirs = (Dwarf_P_Inc_Dir)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Inc_Dir_s));
+ if (dbg->de_inc_dirs == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_INCDIR_ALLOC, DW_DLV_NOCOUNT);
+ }
+ dbg->de_last_inc_dir = dbg->de_inc_dirs;
+ dbg->de_n_inc_dirs = 1;
+ } else {
+ dbg->de_last_inc_dir->did_next = (Dwarf_P_Inc_Dir)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Inc_Dir_s));
+ if (dbg->de_last_inc_dir->did_next == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_INCDIR_ALLOC, DW_DLV_NOCOUNT);
+ }
+ dbg->de_last_inc_dir = dbg->de_last_inc_dir->did_next;
+ dbg->de_n_inc_dirs++;
+ }
+ dbg->de_last_inc_dir->did_name =
+ (char *) _dwarf_p_get_alloc(dbg, strlen(name) + 1);
+ if (dbg->de_last_inc_dir->did_name == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_STRING_ALLOC, DW_DLV_NOCOUNT);
+ }
+ strcpy(dbg->de_last_inc_dir->did_name, name);
+ dbg->de_last_inc_dir->did_next = NULL;
+
+ return dbg->de_n_inc_dirs;
+}
+
+/*-----------------------------------------------------------------------
+ Add a file entry declaration to the debug_line section. Stored
+ in linked list. The data is immediately encodes as leb128
+ and stored in Dwarf_P_F_Entry_s struct.
+------------------------------------------------------------------------*/
+Dwarf_Unsigned
+dwarf_add_file_decl(Dwarf_P_Debug dbg,
+ char *name,
+ Dwarf_Unsigned dir_idx,
+ Dwarf_Unsigned time_mod,
+ Dwarf_Unsigned length, Dwarf_Error * error)
+{
+ Dwarf_P_F_Entry cur;
+ char *ptr;
+ int nbytes_idx, nbytes_time, nbytes_len;
+ char buffidx[ENCODE_SPACE_NEEDED];
+ char bufftime[ENCODE_SPACE_NEEDED];
+ char bufflen[ENCODE_SPACE_NEEDED];
+ int res;
+
+ if (dbg->de_file_entries == NULL) {
+ dbg->de_file_entries = (Dwarf_P_F_Entry)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_F_Entry_s));
+ if (dbg->de_file_entries == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_FILE_ENTRY_ALLOC,
+ DW_DLV_NOCOUNT);
+ }
+ cur = dbg->de_file_entries;
+ dbg->de_last_file_entry = cur;
+ dbg->de_n_file_entries = 1;
+ } else {
+ cur = dbg->de_last_file_entry;
+ cur->dfe_next = (Dwarf_P_F_Entry)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_F_Entry_s));
+ if (cur->dfe_next == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_FILE_ENTRY_ALLOC,
+ DW_DLV_NOCOUNT);
+ }
+ cur = cur->dfe_next;
+ dbg->de_last_file_entry = cur;
+ dbg->de_n_file_entries++;
+ }
+ cur->dfe_name = (char *) _dwarf_p_get_alloc(dbg, strlen(name) + 1);
+ if (cur->dfe_name == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_ALLOC_FAIL, DW_DLV_NOCOUNT);
+ }
+ strcpy((char *) cur->dfe_name, name);
+ res = _dwarf_pro_encode_leb128_nm(dir_idx, &nbytes_idx,
+ buffidx, sizeof(buffidx));
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_ALLOC_FAIL, DW_DLV_NOCOUNT);
+ }
+ res = _dwarf_pro_encode_leb128_nm(time_mod, &nbytes_time,
+ bufftime, sizeof(bufftime));
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_ALLOC_FAIL, DW_DLV_NOCOUNT);
+ }
+ res = _dwarf_pro_encode_leb128_nm(length, &nbytes_len,
+ bufflen, sizeof(bufflen));
+ cur->dfe_args = (char *)
+ _dwarf_p_get_alloc(dbg, nbytes_idx + nbytes_time + nbytes_len);
+ if (cur->dfe_args == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_ALLOC_FAIL, DW_DLV_NOCOUNT);
+ }
+ ptr = cur->dfe_args;
+ memcpy((void *) ptr, buffidx, nbytes_idx);
+ ptr += nbytes_idx;
+ memcpy((void *) ptr, bufftime, nbytes_time);
+ ptr += nbytes_time;
+ memcpy((void *) ptr, bufflen, nbytes_len);
+ ptr += nbytes_len;
+ cur->dfe_nbytes = nbytes_idx + nbytes_time + nbytes_len;
+ cur->dfe_next = NULL;
+
+ return dbg->de_n_file_entries;
+}
+
+
+/*---------------------------------------------------------------------
+ Initialize a row of the matrix for line numbers, meaning
+ initialize the struct corresponding to it
+----------------------------------------------------------------------*/
+void
+_dwarf_pro_reg_init(Dwarf_P_Line cur_line)
+{
+ cur_line->dpl_address = 0;
+ cur_line->dpl_file = 1;
+ cur_line->dpl_line = 1;
+ cur_line->dpl_column = 0;
+ cur_line->dpl_is_stmt = DEFAULT_IS_STMT;
+ cur_line->dpl_basic_block = false;
+ cur_line->dpl_next = NULL;
+}
diff --git a/usr/src/lib/libdwarf/common/pro_line.h b/usr/src/lib/libdwarf/common/pro_line.h
new file mode 100644
index 0000000000..eed941239d
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_line.h
@@ -0,0 +1,116 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright 2007-2010 Sun Microsystems, 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
+
+*/
+
+
+
+#define VERSION 2
+#ifdef __i386
+#define MIN_INST_LENGTH 1
+#else
+#define MIN_INST_LENGTH 4
+#endif
+#define DEFAULT_IS_STMT false
+ /* line base and range are temporarily defines.
+ They need to be calculated later */
+#define LINE_BASE -1
+#define LINE_RANGE 4
+
+#define OPCODE_BASE 10
+#define MAX_OPCODE 255
+
+
+/*
+ This struct is used to hold entries in the include directories
+ part of statement prologue.
+*/
+struct Dwarf_P_Inc_Dir_s {
+ char *did_name; /* name of directory */
+ Dwarf_P_Inc_Dir did_next;
+};
+
+
+/*
+ This struct holds file entries for the statement prologue.
+ Defined in pro_line.h
+*/
+struct Dwarf_P_F_Entry_s {
+ char *dfe_name;
+ char *dfe_args; /* has dir index, time of modification,
+ length in bytes. Encodes as leb128 */
+ int dfe_nbytes; /* number of bytes in args */
+ Dwarf_P_F_Entry dfe_next;
+};
+
+
+/*
+ Struct holding line number information for each of the producer
+ line entries
+*/
+struct Dwarf_P_Line_s {
+ /* code address */
+ Dwarf_Addr dpl_address;
+
+ /* file index, index into file entry */
+ Dwarf_Word dpl_file;
+
+ /* line number */
+ Dwarf_Word dpl_line;
+
+ /* column number */
+ Dwarf_Word dpl_column;
+
+ /* whether its a beginning of a stmt */
+ Dwarf_Ubyte dpl_is_stmt;
+
+ /* whether its a beginning of basic blk */
+ Dwarf_Ubyte dpl_basic_block;
+
+ /* used to store opcodes set_address, and end_seq */
+ Dwarf_Ubyte dpl_opc;
+
+ /*
+ Used only for relocations. Has index of symbol relative to
+ which relocation has to be done (the S part in S + A) */
+ Dwarf_Unsigned dpl_r_symidx;
+
+ Dwarf_P_Line dpl_next;
+};
+
+/*
+ to initialize state machine registers, definition in
+ pro_line.c
+*/
+void _dwarf_pro_reg_init(Dwarf_P_Line);
diff --git a/usr/src/lib/libdwarf/common/pro_macinfo.c b/usr/src/lib/libdwarf/common/pro_macinfo.c
new file mode 100644
index 0000000000..cfa820aee6
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_macinfo.c
@@ -0,0 +1,472 @@
+/*
+
+ Copyright (C) 2000,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
+
+*/
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#include <stdio.h>
+#include <string.h>
+#include "pro_incl.h"
+#include "pro_section.h"
+#include "pro_macinfo.h"
+
+/*
+ I don't much like the error strings this generates, since
+ like the rest of libdwarf they are simple strings with
+ no useful numbers in them. But that's not something I can
+ fix without more work than I have time for
+ right now. davea Nov 94.
+*/
+
+/* these are gross overestimates of the number of
+** bytes needed to store a number in LEB form.
+** Just estimates, and since blocks are reasonable size,
+** the end-block waste is small.
+** Of course the waste is NOT present on disk.
+*/
+
+#define COMMAND_LEN ENCODE_SPACE_NEEDED
+#define LINE_LEN ENCODE_SPACE_NEEDED
+#define BASE_MACINFO_MALLOC_LEN 2048
+
+static int
+libdwarf_compose_begin(Dwarf_P_Debug dbg, int code,
+ size_t maxlen, int *compose_error_type)
+{
+ unsigned char *nextchar;
+ struct dw_macinfo_block_s *curblk = dbg->de_current_macinfo;
+
+ if (curblk == 0) {
+ struct dw_macinfo_block_s *newb;
+ size_t len;
+
+ /* initial allocation */
+ size_t blen = BASE_MACINFO_MALLOC_LEN;
+
+ if (blen < maxlen) {
+ blen = 2 * maxlen;
+ }
+ len = sizeof(struct dw_macinfo_block_s) + blen;
+ newb =
+ (struct dw_macinfo_block_s *) _dwarf_p_get_alloc(dbg, len);
+ if (!newb) {
+ *compose_error_type = DW_DLE_MACINFO_MALLOC_FAIL;
+ return DW_DLV_ERROR;
+ }
+ newb->mb_data =
+ (char *) newb + sizeof(struct dw_macinfo_block_s);
+ newb->mb_avail_len = blen;
+ newb->mb_used_len = 0;
+ newb->mb_macinfo_data_space_len = blen;
+ dbg->de_first_macinfo = newb;
+ dbg->de_current_macinfo = newb;
+ curblk = newb;
+ } else if (curblk->mb_avail_len < maxlen) {
+ struct dw_macinfo_block_s *newb;
+ size_t len;
+
+ /* no space left in block: allocate a new block */
+ size_t blen =
+ dbg->de_current_macinfo->mb_macinfo_data_space_len * 2;
+ if (blen < maxlen) {
+ blen = 2 * maxlen;
+ }
+ len = sizeof(struct dw_macinfo_block_s) + blen;
+ newb =
+ (struct dw_macinfo_block_s *) _dwarf_p_get_alloc(dbg, len);
+ if (!newb) {
+ *compose_error_type = DW_DLE_MACINFO_MALLOC_FAIL;
+ return DW_DLV_ERROR;
+ }
+ newb->mb_data =
+ (char *) newb + sizeof(struct dw_macinfo_block_s);
+ newb->mb_avail_len = blen;
+ newb->mb_used_len = 0;
+ newb->mb_macinfo_data_space_len = blen;
+ dbg->de_first_macinfo->mb_next = newb;
+ dbg->de_current_macinfo = newb;
+ curblk = newb;
+ }
+ /* now curblk has enough room */
+ dbg->de_compose_avail = curblk->mb_avail_len;
+ dbg->de_compose_used_len = curblk->mb_used_len;
+ nextchar =
+ (unsigned char *) (curblk->mb_data + dbg->de_compose_used_len);
+ *nextchar = code;
+ dbg->de_compose_avail--;
+ ++dbg->de_compose_used_len;
+ return DW_DLV_OK;
+}
+
+
+
+static void
+libdwarf_compose_add_string(Dwarf_P_Debug dbg, char *string, size_t len)
+{
+ struct dw_macinfo_block_s *curblk = dbg->de_current_macinfo;
+ unsigned char *nextchar;
+
+ nextchar =
+ (unsigned char *) (curblk->mb_data + dbg->de_compose_used_len);
+
+ len += 1; /* count the null terminator */
+
+ memcpy(nextchar, string, len);
+ dbg->de_compose_avail -= len;
+ dbg->de_compose_used_len += len;
+ return;
+
+}
+static int
+libdwarf_compose_add_line(Dwarf_P_Debug dbg,
+ Dwarf_Unsigned line, int *compose_error_type)
+{
+ struct dw_macinfo_block_s *curblk = dbg->de_current_macinfo;
+ unsigned char *nextchar;
+ int res;
+ int nbytes;
+
+ nextchar =
+ (unsigned char *) (curblk->mb_data + dbg->de_compose_used_len);
+
+ /* Put the created leb number directly into the macro buffer If
+ dbg->de_compose_avail is > INT_MAX this will not work as the
+ 'int' will look negative to _dwarf_pro_encode_leb128_nm! */
+
+ res = _dwarf_pro_encode_leb128_nm(line, &nbytes,
+ (char *) nextchar,
+ (int) dbg->de_compose_avail);
+ if (res != DW_DLV_OK) {
+ *compose_error_type = DW_DLE_MACINFO_INTERNAL_ERROR_SPACE;
+ return DW_DLV_ERROR;
+ }
+
+ dbg->de_compose_avail -= nbytes;
+ dbg->de_compose_used_len += nbytes;
+ return DW_DLV_OK;
+}
+
+/*
+ This function actually 'commits' the space used by the
+ preceeding calls.
+*/
+static int
+libdwarf_compose_complete(Dwarf_P_Debug dbg, int *compose_error_type)
+{
+ struct dw_macinfo_block_s *curblk = dbg->de_current_macinfo;
+
+ if (dbg->de_compose_used_len > curblk->mb_macinfo_data_space_len) {
+ *compose_error_type = DW_DLE_MACINFO_INTERNAL_ERROR_SPACE;
+ return DW_DLV_ERROR;
+ }
+ curblk->mb_avail_len = dbg->de_compose_avail;
+ curblk->mb_used_len = dbg->de_compose_used_len;
+ return DW_DLV_OK;
+}
+
+
+
+int
+dwarf_def_macro(Dwarf_P_Debug dbg,
+ Dwarf_Unsigned line,
+ char *macname, char *macvalue, Dwarf_Error * error)
+{
+ size_t len;
+ size_t len2;
+ size_t length_est;
+ int res;
+ int compose_error_type;
+
+ if (dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ if (macname == 0) {
+ _dwarf_p_error(NULL, error, DW_DLE_MACINFO_STRING_NULL);
+ return (DW_DLV_ERROR);
+ }
+ len = strlen(macname) + 1;
+ if (len == 0) {
+ _dwarf_p_error(NULL, error, DW_DLE_MACINFO_STRING_EMPTY);
+ return (DW_DLV_ERROR);
+ }
+ if (macvalue) {
+ len2 = strlen(macvalue) + 1;
+ } else {
+ len2 = 0;
+ }
+ length_est = COMMAND_LEN + LINE_LEN + len + len2 + 1; /* 1
+ for
+ space
+ character
+ we
+ add */
+ res = libdwarf_compose_begin(dbg, DW_MACINFO_define, length_est,
+ &compose_error_type);
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(NULL, error, compose_error_type);
+ return (DW_DLV_ERROR);
+ }
+ res = libdwarf_compose_add_line(dbg, line, &compose_error_type);
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(NULL, error, compose_error_type);
+ return (DW_DLV_ERROR);
+ }
+ libdwarf_compose_add_string(dbg, macname, len);
+ libdwarf_compose_add_string(dbg, " ", 1);
+ if (macvalue) {
+ libdwarf_compose_add_string(dbg, " ", 1);
+ libdwarf_compose_add_string(dbg, macvalue, len2);
+ }
+ res = libdwarf_compose_complete(dbg, &compose_error_type);
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(NULL, error, compose_error_type);
+ return (DW_DLV_ERROR);
+ }
+ return DW_DLV_OK;
+}
+
+int
+dwarf_undef_macro(Dwarf_P_Debug dbg,
+ Dwarf_Unsigned line,
+ char *macname, Dwarf_Error * error)
+{
+
+ size_t len;
+ size_t length_est;
+ int res;
+ int compose_error_type;
+
+ if (dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ if (macname == 0) {
+ _dwarf_p_error(NULL, error, DW_DLE_MACINFO_STRING_NULL);
+ return (DW_DLV_ERROR);
+ }
+ len = strlen(macname) + 1;
+ if (len == 0) {
+ _dwarf_p_error(NULL, error, DW_DLE_MACINFO_STRING_EMPTY);
+ return (DW_DLV_ERROR);
+ }
+ length_est = COMMAND_LEN + LINE_LEN + len;
+ res = libdwarf_compose_begin(dbg, DW_MACINFO_undef, length_est,
+ &compose_error_type);
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(NULL, error, compose_error_type);
+ return (DW_DLV_ERROR);
+ }
+ res = libdwarf_compose_add_line(dbg, line, &compose_error_type);
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(NULL, error, compose_error_type);
+ return (DW_DLV_ERROR);
+ }
+ libdwarf_compose_add_string(dbg, macname, len);
+ res = libdwarf_compose_complete(dbg, &compose_error_type);
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(NULL, error, compose_error_type);
+ return (DW_DLV_ERROR);
+ }
+ return DW_DLV_OK;
+}
+
+int
+dwarf_start_macro_file(Dwarf_P_Debug dbg,
+ Dwarf_Unsigned fileindex,
+ Dwarf_Unsigned linenumber, Dwarf_Error * error)
+{
+ size_t length_est;
+ int res;
+ int compose_error_type;
+
+ if (dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ length_est = COMMAND_LEN + LINE_LEN + LINE_LEN;
+ res = libdwarf_compose_begin(dbg, DW_MACINFO_start_file, length_est,
+ &compose_error_type);
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(NULL, error, compose_error_type);
+ return (DW_DLV_ERROR);
+ }
+ res = libdwarf_compose_add_line(dbg, fileindex,
+ &compose_error_type);
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(NULL, error, compose_error_type);
+ return (DW_DLV_ERROR);
+ }
+ res = libdwarf_compose_add_line(dbg, linenumber,
+ &compose_error_type);
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(NULL, error, compose_error_type);
+ return (DW_DLV_ERROR);
+ }
+ return DW_DLV_OK;
+}
+
+int
+dwarf_end_macro_file(Dwarf_P_Debug dbg, Dwarf_Error * error)
+{
+ size_t length_est;
+ int res;
+ int compose_error_type;
+
+ if (dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ length_est = COMMAND_LEN;
+ res = libdwarf_compose_begin(dbg, DW_MACINFO_end_file, length_est,
+ &compose_error_type);
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(NULL, error, compose_error_type);
+ return (DW_DLV_ERROR);
+ }
+ res = libdwarf_compose_complete(dbg, &compose_error_type);
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(NULL, error, compose_error_type);
+ return (DW_DLV_ERROR);
+ }
+ return DW_DLV_OK;
+}
+
+int
+dwarf_vendor_ext(Dwarf_P_Debug dbg,
+ Dwarf_Unsigned constant,
+ char *string, Dwarf_Error * error)
+{
+ size_t len;
+ size_t length_est;
+ int res;
+ int compose_error_type;
+
+ if (dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return (DW_DLV_ERROR);
+ }
+ if (string == 0) {
+ _dwarf_p_error(NULL, error, DW_DLE_MACINFO_STRING_NULL);
+ return (DW_DLV_ERROR);
+ }
+ len = strlen(string) + 1;
+ if (len == 0) {
+ _dwarf_p_error(NULL, error, DW_DLE_MACINFO_STRING_EMPTY);
+ return (DW_DLV_ERROR);
+ }
+ length_est = COMMAND_LEN + LINE_LEN + len;
+ res = libdwarf_compose_begin(dbg, DW_MACINFO_vendor_ext, length_est,
+ &compose_error_type);
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(NULL, error, compose_error_type);
+ return (DW_DLV_ERROR);
+ }
+ res = libdwarf_compose_add_line(dbg, constant, &compose_error_type);
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(NULL, error, compose_error_type);
+ return (DW_DLV_ERROR);
+ }
+ libdwarf_compose_add_string(dbg, string, len);
+ libdwarf_compose_complete(dbg, &compose_error_type);
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(NULL, error, compose_error_type);
+ return (DW_DLV_ERROR);
+ }
+ return DW_DLV_OK;
+}
+
+
+
+int
+_dwarf_pro_transform_macro_info_to_disk(Dwarf_P_Debug dbg,
+ Dwarf_Error * error)
+{
+ /* Total num of bytes in .debug_macinfo section. */
+ Dwarf_Unsigned mac_num_bytes;
+
+ /* Points to first byte of .debug_macinfo buffer. */
+ Dwarf_Small *macinfo;
+
+ /* Fills in the .debug_macinfo buffer. */
+ Dwarf_Small *macinfo_ptr;
+
+
+ /* Used to scan the section data buffers. */
+ struct dw_macinfo_block_s *m_prev;
+ struct dw_macinfo_block_s *m_sect;
+
+
+ /* Get the size of the debug_macinfo data */
+ mac_num_bytes = 0;
+ for (m_sect = dbg->de_first_macinfo; m_sect != NULL;
+ m_sect = m_sect->mb_next) {
+ mac_num_bytes += m_sect->mb_used_len;
+ }
+ /* Tthe final entry has a type code of 0 to indicate It is final
+ for this CU Takes just 1 byte. */
+ mac_num_bytes += 1;
+
+ GET_CHUNK(dbg, dbg->de_elf_sects[DEBUG_MACINFO],
+ macinfo, (unsigned long) mac_num_bytes, error);
+ if (macinfo == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (0);
+ }
+
+ macinfo_ptr = macinfo;
+ m_prev = 0;
+ for (m_sect = dbg->de_first_macinfo; m_sect != NULL;
+ m_sect = m_sect->mb_next) {
+ memcpy(macinfo_ptr, m_sect->mb_data, m_sect->mb_used_len);
+ macinfo_ptr += m_sect->mb_used_len;
+ if (m_prev) {
+ _dwarf_p_dealloc(dbg, (Dwarf_Small *) m_prev);
+ m_prev = 0;
+ }
+ m_prev = m_sect;
+ }
+ *macinfo_ptr = 0; /* the type code of 0 as last entry */
+ if (m_prev) {
+ _dwarf_p_dealloc(dbg, (Dwarf_Small *) m_prev);
+ m_prev = 0;
+ }
+
+ dbg->de_first_macinfo = NULL;
+ dbg->de_current_macinfo = NULL;
+
+ return (int) dbg->de_n_debug_sect;
+}
diff --git a/usr/src/lib/libdwarf/common/pro_macinfo.h b/usr/src/lib/libdwarf/common/pro_macinfo.h
new file mode 100644
index 0000000000..852a0cec1f
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_macinfo.h
@@ -0,0 +1,40 @@
+/*
+
+ Copyright (C) 2000,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
+
+*/
+
+
+
+
+int _dwarf_pro_transform_macro_info_to_disk(Dwarf_P_Debug dbg,
+ Dwarf_Error * error);
diff --git a/usr/src/lib/libdwarf/common/pro_opaque.h b/usr/src/lib/libdwarf/common/pro_opaque.h
new file mode 100644
index 0000000000..befc69faa6
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_opaque.h
@@ -0,0 +1,484 @@
+/*
+
+ Copyright (C) 2000,2002,2004 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright 2002-2010 Sun Microsystems, 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
+
+*/
+
+
+#include <stddef.h>
+
+/*
+ Sgidefs included to define __uint32_t,
+ a guaranteed 4-byte quantity.
+*/
+#include "libdwarfdefs.h"
+
+#define true 1
+#define false 0
+
+/* to identify a cie */
+#define DW_CIE_ID ~(0x0)
+#define DW_CIE_VERSION 1
+
+/*Dwarf_Word is unsigned word usable for index, count in memory */
+/*Dwarf_Sword is signed word usable for index, count in memory */
+/* The are 32 or 64 bits depending if 64 bit longs or not, which
+** fits the ILP32 and LP64 models
+** These work equally well with ILP64.
+*/
+
+typedef unsigned long Dwarf_Word;
+typedef long Dwarf_Sword;
+
+
+typedef signed char Dwarf_Sbyte;
+typedef unsigned char Dwarf_Ubyte;
+typedef signed short Dwarf_Shalf;
+
+/*
+ On any change that makes libdwarf producer
+ incompatible, increment this number.
+ 1->2->3 ...
+
+*/
+#define PRO_VERSION_MAGIC 0xdead1
+
+
+/* these 2 are fixed sizes which must not vary with the
+** ILP32/LP64 model. These two stay at 32 bit.
+*/
+typedef __uint32_t Dwarf_ufixed;
+typedef __int32_t Dwarf_sfixed;
+
+/*
+ producer:
+ This struct is used to hold information about all
+ debug* sections. On creating a new section, section
+ names and indices are added to this struct
+ definition in pro_section.h
+*/
+typedef struct Dwarf_P_Section_Data_s *Dwarf_P_Section_Data;
+
+/*
+ producer:
+ This struct is used to hold entries in the include directories
+ part of statement prologue. Definition in pro_line.h
+*/
+typedef struct Dwarf_P_Inc_Dir_s *Dwarf_P_Inc_Dir;
+
+/*
+ producer:
+ This struct holds file entries for the statement prologue.
+ Defined in pro_line.h
+*/
+typedef struct Dwarf_P_F_Entry_s *Dwarf_P_F_Entry;
+
+/*
+ producer:
+ This struct holds information for each cie. Defn in pro_frame.h
+*/
+typedef struct Dwarf_P_Cie_s *Dwarf_P_Cie;
+
+/*
+ producer:
+ Struct to hold line number information, different from
+ Dwarf_Line opaque type.
+*/
+typedef struct Dwarf_P_Line_s *Dwarf_P_Line;
+
+/*
+ producer:
+ Struct to hold information about address ranges.
+*/
+typedef struct Dwarf_P_Simple_nameentry_s *Dwarf_P_Simple_nameentry;
+typedef struct Dwarf_P_Simple_name_header_s *Dwarf_P_Simple_name_header;
+typedef struct Dwarf_P_Arange_s *Dwarf_P_Arange;
+typedef struct Dwarf_P_Per_Reloc_Sect_s *Dwarf_P_Per_Reloc_Sect;
+typedef struct Dwarf_P_Per_Sect_String_Attrs_s *Dwarf_P_Per_Sect_String_Attrs;
+
+/* Defined to get at the elf section numbers and section name
+ indices in symtab for the dwarf sections
+ Must match .rel.* names in _dwarf_rel_section_names
+ exactly.
+*/
+#define DEBUG_INFO 0
+#define DEBUG_LINE 1
+#define DEBUG_ABBREV 2
+#define DEBUG_FRAME 3
+#define DEBUG_ARANGES 4
+#define DEBUG_PUBNAMES 5
+#define DEBUG_STR 6
+#define DEBUG_FUNCNAMES 7
+#define DEBUG_TYPENAMES 8
+#define DEBUG_VARNAMES 9
+#define DEBUG_WEAKNAMES 10
+#define DEBUG_MACINFO 11
+#define DEBUG_LOC 12
+
+ /* number of debug_* sections not including the relocations */
+#define NUM_DEBUG_SECTIONS DEBUG_LOC + 1
+
+
+struct Dwarf_P_Die_s {
+ Dwarf_Unsigned di_offset; /* offset in debug info */
+ char *di_abbrev; /* abbreviation */
+ Dwarf_Word di_abbrev_nbytes; /* # of bytes in abbrev */
+ Dwarf_Tag di_tag;
+ Dwarf_P_Die di_parent; /* parent of current die */
+ Dwarf_P_Die di_child; /* first child */
+ /* The last child field makes linking up children an O(1) operation,
+ See pro_die.c. */
+ Dwarf_P_Die di_last_child;
+ Dwarf_P_Die di_left; /* left sibling */
+ Dwarf_P_Die di_right; /* right sibling */
+ Dwarf_P_Attribute di_attrs; /* list of attributes */
+ Dwarf_P_Attribute di_last_attr; /* last attribute */
+ int di_n_attr; /* number of attributes */
+ Dwarf_P_Debug di_dbg; /* For memory management */
+ Dwarf_Unsigned di_marker; /* used to attach symbols to dies */
+};
+
+
+/* producer fields */
+struct Dwarf_P_Attribute_s {
+ Dwarf_Half ar_attribute; /* Attribute Value. */
+ Dwarf_Half ar_attribute_form; /* Attribute Form. */
+ Dwarf_P_Die ar_ref_die; /* die pointer if form ref */
+ char *ar_data; /* data, format given by form */
+ Dwarf_Unsigned ar_nbytes; /* no. of bytes of data */
+ Dwarf_Unsigned ar_rel_symidx; /* when attribute has a
+ relocatable value, holds
+ index of symbol in SYMTAB */
+ Dwarf_Ubyte ar_rel_type; /* relocation type */
+ Dwarf_Word ar_rel_offset; /* Offset of relocation within block */
+ char ar_reloc_len; /* Number of bytes that relocation
+ applies to. 4 or 8. Unused and may
+ be 0 if if ar_rel_type is
+ R_MIPS_NONE */
+ Dwarf_P_Attribute ar_next;
+};
+
+/* A block of .debug_macinfo data: this forms a series of blocks.
+** Each macinfo input is compressed immediately and put into
+** the current block if room, else a newblock allocated.
+** The space allocation is such that the block and the macinfo
+** data are one malloc block: free with a pointer to this and the
+** mb_data is freed automatically.
+** Like the struct hack, but legal ANSI C.
+*/
+struct dw_macinfo_block_s {
+ struct dw_macinfo_block_s *mb_next;
+ unsigned long mb_avail_len;
+ unsigned long mb_used_len;
+ unsigned long mb_macinfo_data_space_len;
+ char *mb_data; /* original malloc ptr. */
+};
+
+/* dwarf_sn_kind is for the array of similarly-treated
+ name -> cu ties
+*/
+enum dwarf_sn_kind { dwarf_snk_pubname, dwarf_snk_funcname,
+ dwarf_snk_weakname, dwarf_snk_typename,
+ dwarf_snk_varname,
+ dwarf_snk_entrycount /* this one must be last */
+};
+
+
+
+/* The calls to add a varname etc use a list of
+ these as the list.
+*/
+struct Dwarf_P_Simple_nameentry_s {
+ Dwarf_P_Die sne_die;
+ char *sne_name;
+ int sne_name_len;
+ Dwarf_P_Simple_nameentry sne_next;
+};
+
+/* An array of these, each of which heads a list
+ of Dwarf_P_Simple_nameentry
+*/
+struct Dwarf_P_Simple_name_header_s {
+ Dwarf_P_Simple_nameentry sn_head;
+ Dwarf_P_Simple_nameentry sn_tail;
+ Dwarf_Signed sn_count;
+
+ /* length that will be generated, not counting fixed header or
+ trailer */
+ Dwarf_Signed sn_net_len;
+};
+typedef int (*_dwarf_pro_reloc_name_func_ptr) (Dwarf_P_Debug dbg,
+ int sec_index,
+ Dwarf_Unsigned offset,/* r_offset */
+ Dwarf_Unsigned symidx,
+ enum Dwarf_Rel_Type type,
+ int reltarget_length);
+
+typedef int (*_dwarf_pro_reloc_length_func_ptr) (Dwarf_P_Debug dbg,
+ int sec_index, Dwarf_Unsigned offset,/* r_offset */
+ Dwarf_Unsigned start_symidx,
+ Dwarf_Unsigned end_symidx,
+ enum Dwarf_Rel_Type type,
+ int reltarget_length);
+typedef int (*_dwarf_pro_transform_relocs_func_ptr) (Dwarf_P_Debug dbg,
+ Dwarf_Signed *
+ new_sec_count);
+
+/*
+ Each slot in a block of slots could be:
+ a binary stream relocation entry (32 or 64bit relocation data)
+ a SYMBOLIC relocation entry.
+ During creation sometimes we create multiple chained blocks,
+ but sometimes we create a single long block.
+ Before returning reloc data to caller,
+ we switch to a single, long-enough,
+ block.
+
+ We make counters here Dwarf_Unsigned so that we
+ get sufficient alignment. Since we use space after
+ the struct (at malloc time) for user data which
+ must have Dwarf_Unsigned alignment, this
+ struct must have that alignment too.
+*/
+struct Dwarf_P_Relocation_Block_s {
+ Dwarf_Unsigned rb_slots_in_block; /* slots in block, as created */
+ Dwarf_Unsigned rb_next_slot_to_use; /* counter, start at 0. */
+ struct Dwarf_P_Relocation_Block_s *rb_next;
+ char *rb_where_to_add_next; /* pointer to next slot (might be past
+ end, depending on
+ rb_next_slot_to_use) */
+ char *rb_data; /* data area */
+};
+
+/* One of these per potential relocation section
+ So one per actual dwarf section.
+ Left zeroed when not used (some sections have
+ no relocations).
+*/
+struct Dwarf_P_Per_Reloc_Sect_s {
+ unsigned long pr_reloc_total_count; /* total number of entries
+ across all blocks */
+
+ unsigned long pr_slots_per_block_to_alloc; /* at Block alloc, this
+ is the default number of slots to use */
+
+ int pr_sect_num_of_reloc_sect; /* sect number returned by
+ de_callback_func() or de_callback_func_b() call, this is the sect
+ number of the relocation section. */
+
+ /* singly-linked list. add at and ('last') with count of blocks */
+ struct Dwarf_P_Relocation_Block_s *pr_first_block;
+ struct Dwarf_P_Relocation_Block_s *pr_last_block;
+ unsigned long pr_block_count;
+};
+
+#define DEFAULT_SLOTS_PER_BLOCK 3
+
+typedef struct memory_list_s {
+ struct memory_list_s *prev;
+ struct memory_list_s *next;
+} memory_list_t;
+
+struct Dwarf_P_Per_Sect_String_Attrs_s {
+ int sect_sa_section_number;
+ unsigned sect_sa_n_alloc;
+ unsigned sect_sa_n_used;
+ Dwarf_P_String_Attr sect_sa_list;
+};
+
+/* Fields used by producer */
+struct Dwarf_P_Debug_s {
+ /* used to catch dso passing dbg to another DSO with incompatible
+ version of libdwarf See PRO_VERSION_MAGIC */
+ int de_version_magic_number;
+
+ Dwarf_Handler de_errhand;
+ Dwarf_Ptr de_errarg;
+
+ /* Call back function, used to create .debug* sections. Provided
+ by user. Only of these used per dbg. */
+ Dwarf_Callback_Func de_callback_func;
+ Dwarf_Callback_Func_b de_callback_func_b;
+
+ /* Flags from producer_init call */
+ Dwarf_Unsigned de_flags;
+
+ /* This holds information on debug section stream output, including
+ the stream data */
+ Dwarf_P_Section_Data de_debug_sects;
+
+ /* Pointer to the 'current active' section */
+ Dwarf_P_Section_Data de_current_active_section;
+
+ /* Number of debug data streams globs. */
+ Dwarf_Word de_n_debug_sect;
+
+ /* File entry information, null terminated singly-linked list */
+ Dwarf_P_F_Entry de_file_entries;
+ Dwarf_P_F_Entry de_last_file_entry;
+ Dwarf_Unsigned de_n_file_entries;
+
+ /* Has the directories used to search for source files */
+ Dwarf_P_Inc_Dir de_inc_dirs;
+ Dwarf_P_Inc_Dir de_last_inc_dir;
+ Dwarf_Unsigned de_n_inc_dirs;
+
+ /* Has all the line number info for the stmt program */
+ Dwarf_P_Line de_lines;
+ Dwarf_P_Line de_last_line;
+
+ /* List of cie's for the debug unit */
+ Dwarf_P_Cie de_frame_cies;
+ Dwarf_P_Cie de_last_cie;
+ Dwarf_Unsigned de_n_cie;
+
+ /* Singly-linked list of fde's for the debug unit */
+ Dwarf_P_Fde de_frame_fdes;
+ Dwarf_P_Fde de_last_fde;
+ Dwarf_Unsigned de_n_fde;
+
+ /* First die, leads to all others */
+ Dwarf_P_Die de_dies;
+
+ /* Pointer to list of strings */
+ char *de_strings;
+
+ /* Pointer to chain of aranges */
+ Dwarf_P_Arange de_arange;
+ Dwarf_P_Arange de_last_arange;
+ Dwarf_Sword de_arange_count;
+
+ /* macinfo controls. */
+ /* first points to beginning of the list during creation */
+ struct dw_macinfo_block_s *de_first_macinfo;
+
+ /* current points to the current, unfilled, block */
+ struct dw_macinfo_block_s *de_current_macinfo;
+
+ /* Pointer to the first section, to support reset_section_bytes */
+ Dwarf_P_Section_Data de_first_debug_sect;
+
+ /* handles pubnames, weaknames, etc. See dwarf_sn_kind in
+ pro_opaque.h */
+ struct Dwarf_P_Simple_name_header_s
+ de_simple_name_headers[dwarf_snk_entrycount];
+
+ /* relocation data. not all sections will actally have relocation
+ info, of course */
+ struct Dwarf_P_Per_Reloc_Sect_s de_reloc_sect[NUM_DEBUG_SECTIONS];
+ int de_reloc_next_to_return; /* iterator on reloc sections
+ (SYMBOLIC output) */
+
+ /* used in remembering sections */
+ int de_elf_sects[NUM_DEBUG_SECTIONS]; /* elf sect number of
+ the section itself, DEBUG_LINE for example */
+
+ Dwarf_Unsigned de_sect_name_idx[NUM_DEBUG_SECTIONS]; /* section
+ name index or handle for the name of the symbol for
+ DEBUG_LINE for example */
+
+ int de_offset_reloc; /* offset reloc type, R_MIPS_32 for
+ example. Specific to the ABI being
+ produced. Relocates offset size
+ field */
+ int de_exc_reloc; /* reloc type specific to exception
+ table relocs. */
+ int de_ptr_reloc; /* standard reloc type, R_MIPS_32 for
+ example. Specific to the ABI being
+ produced. relocates pointer size
+ field */
+
+ unsigned char de_offset_size; /* section offset. Here to
+ avoid test of abi in macro
+ at run time MIPS -n32 4,
+ -64 8. */
+
+ unsigned char de_pointer_size; /* size of pointer in target.
+ Here to avoid test of abi in
+ macro at run time MIPS -n32
+ 4, -64 is 8. */
+
+ unsigned char de_is_64bit; /* non-zero if is 64bit. Else 32 bit:
+ used for passing this info as a flag
+ */
+ unsigned char de_relocation_record_size; /* reloc record size
+ varies by ABI and
+ relocation-output
+ method (stream or
+ symbolic) */
+
+ unsigned char de_64bit_extension; /* non-zero if creating 64 bit
+ offsets using dwarf2-99
+ extension proposal */
+
+ int de_ar_data_attribute_form; /* data8, data4 abi dependent */
+ int de_ar_ref_attr_form; /* ref8 ref4 , abi dependent */
+
+ /* simple name relocations */
+ _dwarf_pro_reloc_name_func_ptr de_reloc_name;
+
+ /* relocations for a length, requiring a pair of symbols */
+ _dwarf_pro_reloc_length_func_ptr de_reloc_pair;
+
+ _dwarf_pro_transform_relocs_func_ptr de_transform_relocs_to_disk;
+
+ /* following used for macro buffers */
+ unsigned long de_compose_avail;
+ unsigned long de_compose_used_len;
+
+ unsigned char de_same_endian;
+ void *(*de_copy_word) (void *, const void *, size_t);
+
+ /* Add new fields at the END of this struct to preserve some hope
+ of sensible behavior on dbg passing between DSOs linked with
+ mismatched libdwarf producer versions. */
+
+ Dwarf_P_Marker de_markers; /* pointer to array of markers */
+ unsigned de_marker_n_alloc;
+ unsigned de_marker_n_used;
+ int de_sect_sa_next_to_return; /* Iterator on sring attrib sects */
+ /* String attributes data of each section. */
+ struct Dwarf_P_Per_Sect_String_Attrs_s de_sect_string_attr[NUM_DEBUG_SECTIONS];
+};
+
+#define CURRENT_VERSION_STAMP 2
+
+Dwarf_Unsigned _dwarf_add_simple_name_entry(Dwarf_P_Debug dbg,
+ Dwarf_P_Die die,
+ char *entry_name,
+ enum dwarf_sn_kind
+ entrykind,
+ Dwarf_Error * error);
+
+
+#define DISTINGUISHED_VALUE 0xffffffff /* 64bit extension flag */
diff --git a/usr/src/lib/libdwarf/common/pro_pubnames.c b/usr/src/lib/libdwarf/common/pro_pubnames.c
new file mode 100644
index 0000000000..e07fe35943
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_pubnames.c
@@ -0,0 +1,63 @@
+/*
+
+ Copyright (C) 2000,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
+
+*/
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_ELFACCESS_H
+#include <elfaccess.h>
+#endif
+#include "pro_incl.h"
+#include "pro_section.h"
+
+
+/*
+ This function adds another public name to the
+ list of public names for the given Dwarf_P_Debug.
+ It returns 0 on error, and 1 otherwise.
+*/
+
+Dwarf_Unsigned
+dwarf_add_pubname(Dwarf_P_Debug dbg,
+ Dwarf_P_Die die,
+ char *pubname_name, Dwarf_Error * error)
+{
+ return
+ _dwarf_add_simple_name_entry(dbg, die, pubname_name,
+ dwarf_snk_pubname, error);
+}
diff --git a/usr/src/lib/libdwarf/common/pro_reloc.c b/usr/src/lib/libdwarf/common/pro_reloc.c
new file mode 100644
index 0000000000..66f16acbd0
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_reloc.c
@@ -0,0 +1,269 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright 2008-2010 David Anderson, 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
+
+*/
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#include <stdio.h>
+#include <string.h>
+/*#include <elfaccess.h> */
+#include "pro_incl.h"
+
+
+/*Do initial alloc of newslots slots.
+ Fails only if malloc fails.
+
+ Supposed to be called before any relocs allocated.
+ Ignored if after any allocated.
+
+ Part of an optimization, so that for a known 'newslots'
+ relocations count we can preallocate the right size block.
+ Called from just 2 places.
+
+ returns DW_DLV_OK or DW_DLV_ERROR
+*/
+int
+_dwarf_pro_pre_alloc_n_reloc_slots(Dwarf_P_Debug dbg,
+ int rel_sec_index,
+ Dwarf_Unsigned newslots)
+{
+ unsigned long len = 0;
+ struct Dwarf_P_Relocation_Block_s *data = 0;
+ Dwarf_P_Per_Reloc_Sect prel = &dbg->de_reloc_sect[rel_sec_index];
+ unsigned long slots_in_blk = (unsigned long) newslots;
+ unsigned long rel_rec_size = dbg->de_relocation_record_size;
+
+ if (prel->pr_first_block)
+ return DW_DLV_OK; /* do nothing */
+
+ len = sizeof(struct Dwarf_P_Relocation_Block_s) +
+ slots_in_blk * rel_rec_size;
+
+
+ data = (struct Dwarf_P_Relocation_Block_s *)
+ _dwarf_p_get_alloc(dbg, len);
+ if (!data) {
+ return DW_DLV_ERROR;
+ }
+ data->rb_slots_in_block = slots_in_blk; /* could use default
+ here, as fallback in
+ case our origininal
+ estimate wrong. When
+ we call this we
+ presumably know what
+ we are doing, so
+ keep this count for
+ now */
+ data->rb_next_slot_to_use = 0;
+ data->rb_where_to_add_next =
+ ((char *) data) + sizeof(struct Dwarf_P_Relocation_Block_s);
+ data->rb_data = data->rb_where_to_add_next;
+
+ prel->pr_first_block = data;
+ prel->pr_last_block = data;
+ prel->pr_block_count = 1;
+
+
+ return DW_DLV_OK;
+}
+
+
+/*Do alloc of slots.
+ Fails only if malloc fails.
+
+ Only allocator used.
+
+ returns DW_DLV_OK or DW_DLV_ERROR
+*/
+int
+_dwarf_pro_alloc_reloc_slots(Dwarf_P_Debug dbg, int rel_sec_index)
+{
+ unsigned long len = 0;
+ struct Dwarf_P_Relocation_Block_s *data = 0;
+ Dwarf_P_Per_Reloc_Sect prel = &dbg->de_reloc_sect[rel_sec_index];
+ unsigned long slots_in_blk = prel->pr_slots_per_block_to_alloc;
+ unsigned long rel_rec_size = dbg->de_relocation_record_size;
+
+ len = sizeof(struct Dwarf_P_Relocation_Block_s) +
+ slots_in_blk * rel_rec_size;
+
+ data = (struct Dwarf_P_Relocation_Block_s *)
+ _dwarf_p_get_alloc(dbg, len);
+ if (!data) {
+ return DW_DLV_ERROR;
+ }
+
+ if (prel->pr_first_block) {
+ prel->pr_last_block->rb_next = data;
+ prel->pr_last_block = data;
+ prel->pr_block_count += 1;
+
+ } else {
+
+ prel->pr_first_block = data;
+ prel->pr_last_block = data;
+ prel->pr_block_count = 1;
+ }
+
+ data->rb_slots_in_block = slots_in_blk;
+ data->rb_next_slot_to_use = 0;
+ data->rb_where_to_add_next =
+ ((char *) data) + sizeof(struct Dwarf_P_Relocation_Block_s);
+ data->rb_data = data->rb_where_to_add_next;
+
+ return DW_DLV_OK;
+
+}
+
+/*
+ Reserve a slot. return DW_DLV_OK if succeeds.
+
+ Return DW_DLV_ERROR if fails (malloc error).
+
+ Use the relrec_to_fill to pass back a pointer to
+ a slot space to use.
+*/
+int
+_dwarf_pro_reloc_get_a_slot(Dwarf_P_Debug dbg,
+ int base_sec_index, void **relrec_to_fill)
+{
+ struct Dwarf_P_Relocation_Block_s *data = 0;
+ Dwarf_P_Per_Reloc_Sect prel = &dbg->de_reloc_sect[base_sec_index];
+ unsigned long rel_rec_size = dbg->de_relocation_record_size;
+
+ char *ret_addr = 0;
+
+ data = prel->pr_last_block;
+ if ((data == 0) ||
+ (data->rb_next_slot_to_use >= data->rb_slots_in_block)) {
+ int res;
+
+ res = _dwarf_pro_alloc_reloc_slots(dbg, base_sec_index);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ }
+
+ data = prel->pr_last_block;
+ /* now we have an empty slot */
+ ret_addr = data->rb_where_to_add_next;
+
+ data->rb_where_to_add_next += rel_rec_size;
+ data->rb_next_slot_to_use += 1;
+
+ prel->pr_reloc_total_count += 1;
+
+ *relrec_to_fill = (void *) ret_addr;
+
+ return DW_DLV_OK;
+
+}
+
+/*
+ On success returns count of
+ .rel.* sections that are symbolic
+ thru count_of_relocation_sections.
+
+ On success, returns DW_DLV_OK.
+
+ If this is not a 'symbolic' run, returns
+ DW_DLV_NO_ENTRY.
+
+ No errors are possible.
+
+
+
+
+*/
+
+ /*ARGSUSED*/ int
+dwarf_get_relocation_info_count(Dwarf_P_Debug dbg,
+ Dwarf_Unsigned *
+ count_of_relocation_sections,
+ int *drd_buffer_version,
+ Dwarf_Error * error)
+{
+ if (dbg->de_flags & DW_DLC_SYMBOLIC_RELOCATIONS) {
+ int i;
+ unsigned int count = 0;
+
+ for (i = 0; i < NUM_DEBUG_SECTIONS; ++i) {
+ if (dbg->de_reloc_sect[i].pr_reloc_total_count > 0) {
+ ++count;
+ }
+ }
+ *count_of_relocation_sections = (Dwarf_Unsigned) count;
+ *drd_buffer_version = DWARF_DRD_BUFFER_VERSION;
+ return DW_DLV_OK;
+ }
+ return DW_DLV_NO_ENTRY;
+}
+
+int
+dwarf_get_relocation_info(Dwarf_P_Debug dbg,
+ Dwarf_Signed * elf_section_index,
+ Dwarf_Signed * elf_section_index_link,
+ Dwarf_Unsigned * relocation_buffer_count,
+ Dwarf_Relocation_Data * reldata_buffer,
+ Dwarf_Error * error)
+{
+ int next = dbg->de_reloc_next_to_return;
+
+ if (dbg->de_flags & DW_DLC_SYMBOLIC_RELOCATIONS) {
+ int i;
+
+ for (i = next; i < NUM_DEBUG_SECTIONS; ++i) {
+ Dwarf_P_Per_Reloc_Sect prel = &dbg->de_reloc_sect[i];
+
+ if (prel->pr_reloc_total_count > 0) {
+ dbg->de_reloc_next_to_return = i + 1;
+
+
+ /* ASSERT: prel->.pr_block_count == 1 */
+
+ *elf_section_index = prel->pr_sect_num_of_reloc_sect;
+ *elf_section_index_link = dbg->de_elf_sects[i];
+ *relocation_buffer_count = prel->pr_reloc_total_count;
+ *reldata_buffer = (Dwarf_Relocation_Data)
+ (prel->pr_first_block->rb_data);
+ return DW_DLV_OK;
+ }
+ }
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_REL_ALLOC, DW_DLV_ERROR);
+ }
+ return DW_DLV_NO_ENTRY;
+}
diff --git a/usr/src/lib/libdwarf/common/pro_reloc.h b/usr/src/lib/libdwarf/common/pro_reloc.h
new file mode 100644
index 0000000000..d2e6c67357
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_reloc.h
@@ -0,0 +1,47 @@
+/*
+
+ Copyright (C) 2000,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
+
+*/
+
+
+
+
+int _dwarf_pro_pre_alloc_n_reloc_slots(Dwarf_P_Debug dbg,
+ int rel_sec_index,
+ Dwarf_Unsigned newslots);
+
+int _dwarf_pro_alloc_reloc_slots(Dwarf_P_Debug dbg, int rel_sec_index);
+
+int _dwarf_pro_reloc_get_a_slot(Dwarf_P_Debug dbg,
+ int base_sec_index,
+ void **relrec_to_fill);
diff --git a/usr/src/lib/libdwarf/common/pro_reloc_stream.c b/usr/src/lib/libdwarf/common/pro_reloc_stream.c
new file mode 100644
index 0000000000..459779ceda
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_reloc_stream.c
@@ -0,0 +1,297 @@
+/*
+
+ Copyright (C) 2000,2001,2004 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright 2002-2010 Sun Microsystems, Inc. All rights reserved.
+ Portions Copyright 2008-2010 David Anderson, 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
+
+*/
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_ELFACCESS_H
+#include <elfaccess.h>
+#else
+/* Set r_info as defined by ELF generic ABI */
+#define Set_REL32_info(r,s,t) ((r).r_info = ELF32_R_INFO(s,t))
+#define Set_REL64_info(r,s,t) ((r).r_info = ELF64_R_INFO(s,t))
+#endif
+#include "pro_incl.h"
+#include "pro_section.h"
+#include "pro_reloc.h"
+#include "pro_reloc_stream.h"
+
+/*
+ Return DW_DLV_ERROR on malloc error or reltarget_length error.
+ Return DW_DLV_OK otherwise
+
+
+
+*/
+ /*ARGSUSED*/ int
+_dwarf_pro_reloc_name_stream64(Dwarf_P_Debug dbg,
+ int base_sec_index,
+ Dwarf_Unsigned offset, /* r_offset of reloc */
+ Dwarf_Unsigned symidx,
+ enum Dwarf_Rel_Type type,
+ int reltarget_length)
+{
+#if HAVE_ELF64_GETEHDR
+ REL64 *elf64_reloc = 0;
+ void *relrec_to_fill = 0;
+ int res = 0;
+ int rel_type = 0;
+
+ res = _dwarf_pro_reloc_get_a_slot(dbg, base_sec_index,
+ &relrec_to_fill);
+ if (res != DW_DLV_OK)
+ return res;
+
+
+ if (type == dwarf_drt_data_reloc) {
+ if (reltarget_length == dbg->de_offset_size) {
+ rel_type = dbg->de_offset_reloc;
+ } else if (reltarget_length == dbg->de_pointer_size) {
+ rel_type = dbg->de_ptr_reloc;
+ } else {
+ return DW_DLV_ERROR;
+ }
+ } else if (type == dwarf_drt_segment_rel) {
+ rel_type = dbg->de_exc_reloc;
+ } else {
+ /* We are in trouble: improper use of stream relocations.
+ Someone else will diagnose */
+ rel_type = 0;
+ }
+
+ elf64_reloc = (REL64 *)relrec_to_fill;
+ elf64_reloc->r_offset = offset;
+ Set_REL64_info(*elf64_reloc, symidx, rel_type);
+ return DW_DLV_OK;
+#else /* !HAVE_ELF64_GETEHDR */
+ return DW_DLV_ERROR;
+#endif /* #if HAVE_ELF64_GETEHDR */
+}
+
+/*
+ Return DW_DLV_ERROR on malloc error or reltarget_length error.
+ Return DW_DLV_OK otherwise
+ a binary reloc: 32bit ABI
+*/
+int
+_dwarf_pro_reloc_name_stream32(Dwarf_P_Debug dbg, int base_sec_index,
+ Dwarf_Unsigned offset, /* r_offset of reloc */
+ Dwarf_Unsigned symidx,
+ enum Dwarf_Rel_Type type,
+ int reltarget_length)
+{
+ REL32 *elf32_reloc = 0;
+ void *relrec_to_fill = 0;
+ int res = 0;
+ int rel_type = 0;
+
+ res = _dwarf_pro_reloc_get_a_slot(dbg, base_sec_index,
+ &relrec_to_fill);
+ if (res != DW_DLV_OK)
+ return res;
+ if (type == dwarf_drt_data_reloc) {
+ if (reltarget_length == dbg->de_offset_size) {
+ rel_type = dbg->de_offset_reloc;
+ } else if (reltarget_length == dbg->de_pointer_size) {
+ rel_type = dbg->de_ptr_reloc;
+ } else {
+ return DW_DLV_ERROR;
+ }
+ } else if (type == dwarf_drt_segment_rel) {
+ rel_type = dbg->de_exc_reloc;
+ } else {
+ /* We are in trouble: improper use of stream relocations.
+ Someone else will diagnose */
+ rel_type = 0;
+ }
+
+ elf32_reloc = (REL32*)relrec_to_fill;
+ elf32_reloc->r_offset = (Elf32_Addr) offset;
+ Set_REL32_info(*elf32_reloc, (Dwarf_Word) symidx, rel_type);
+ return DW_DLV_OK;
+
+ /* get a slot, fill in the slot entry */
+}
+
+
+
+/*
+ Return DW_DLV_OK.
+ Never can really do anything: lengths cannot
+ be represented as end-start in a stream.
+
+*/
+ /*ARGSUSED*/ int
+_dwarf_pro_reloc_length_stream(Dwarf_P_Debug dbg,
+ int base_sec_index,
+ Dwarf_Unsigned offset, /* r_offset of reloc */
+ Dwarf_Unsigned start_symidx,
+ Dwarf_Unsigned end_symidx,
+ enum Dwarf_Rel_Type type,
+ int reltarget_length)
+{
+ /* get a slot, fill in the slot entry */
+ return DW_DLV_OK;
+}
+
+
+/*
+ Ensure each stream is a single buffer and
+ add that single buffer to the set of stream buffers.
+
+ By creating a new buffer and copying if necessary.
+
+ Free the input set of buffers if we consolidate.
+ Return -1 on error (malloc failure)
+
+
+ Return DW_DLV_OK on success. Any other return indicates
+ malloc failed.
+
+*/
+int
+_dwarf_stream_relocs_to_disk(Dwarf_P_Debug dbg,
+ Dwarf_Signed * new_sec_count)
+{
+ unsigned long total_size = 0;
+ Dwarf_Small *data = 0;
+ int sec_index = 0;
+ unsigned long i = 0;
+ Dwarf_Error err = 0;
+ Dwarf_Error *error = &err;
+
+ Dwarf_Signed sec_count = 0;
+
+ Dwarf_P_Per_Reloc_Sect p_reloc = &dbg->de_reloc_sect[0];
+
+ for (i = 0; i < NUM_DEBUG_SECTIONS; ++i, ++p_reloc) {
+ unsigned long ct = p_reloc->pr_reloc_total_count;
+ unsigned len = 0;
+ struct Dwarf_P_Relocation_Block_s *p_blk = 0;
+ struct Dwarf_P_Relocation_Block_s *p_blk_last = 0;
+ Dwarf_P_Per_Reloc_Sect prb = 0;
+
+ if (ct == 0) {
+ continue;
+ }
+ prb = &dbg->de_reloc_sect[i];
+ len = dbg->de_relocation_record_size;
+ ++sec_count;
+
+ total_size = ct * len;
+ sec_index = prb->pr_sect_num_of_reloc_sect;
+ if (sec_index == 0) {
+ /* Call de_callback_func or de_callback_func_b, getting
+ section number of reloc section. */
+ int rel_section_index = 0;
+ Dwarf_Unsigned name_idx = 0;
+ int int_name = 0;
+ int err = 0;
+
+ if (dbg->de_callback_func_b) {
+ rel_section_index =
+ dbg->de_callback_func_b(_dwarf_rel_section_names[i],
+ /* size */
+ dbg->de_relocation_record_size,
+ /* type */ SHT_REL,
+ /* flags */ 0,
+ /* link to symtab, which we cannot
+ know */ 0,
+ /* info == link to sec rels apply to
+ */
+ dbg->de_elf_sects[i],
+ &name_idx, &err);
+ } else {
+ rel_section_index =
+ dbg->de_callback_func(_dwarf_rel_section_names[i],
+ /* size */
+ dbg->de_relocation_record_size,
+ /* type */ SHT_REL,
+ /* flags */ 0,
+ /* link to symtab, which we cannot
+ know */ 0,
+ /* info == link to sec rels apply to */
+ dbg->de_elf_sects[i], &int_name, &err);
+ name_idx = int_name;
+ }
+ if (rel_section_index == -1) {
+ {
+ _dwarf_p_error(dbg, error, DW_DLE_ELF_SECT_ERR);
+ return (DW_DLV_ERROR);
+ }
+
+ }
+ prb->pr_sect_num_of_reloc_sect = rel_section_index;
+ sec_index = rel_section_index;
+ }
+ GET_CHUNK(dbg, sec_index, data, total_size, &err);
+ p_blk = p_reloc->pr_first_block;
+
+ /* following loop executes at least once. Effects the
+ consolidation to a single block or, if already a single
+ block, simply copies to the output buffer. And frees the
+ input block. The new block is in the de_debug_sects list. */
+ while (p_blk) {
+
+ unsigned long len =
+ p_blk->rb_where_to_add_next - p_blk->rb_data;
+
+ memcpy(data, p_blk->rb_data, len);
+
+
+ data += len;
+
+ p_blk_last = p_blk;
+ p_blk = p_blk->rb_next;
+
+ _dwarf_p_dealloc(dbg, (Dwarf_Small *) p_blk_last);
+ }
+ /* ASSERT: sum of len copied == total_size */
+
+ /*
+ We have copied the input, now drop the pointers to it. For
+ debugging, leave the other data untouched. */
+ p_reloc->pr_first_block = 0;
+ p_reloc->pr_last_block = 0;
+ }
+
+ *new_sec_count = sec_count;
+ return DW_DLV_OK;
+}
diff --git a/usr/src/lib/libdwarf/common/pro_reloc_stream.h b/usr/src/lib/libdwarf/common/pro_reloc_stream.h
new file mode 100644
index 0000000000..892ea5baf3
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_reloc_stream.h
@@ -0,0 +1,63 @@
+/*
+
+ Copyright (C) 2000,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
+
+*/
+
+
+
+
+int _dwarf_pro_reloc_name_stream64(Dwarf_P_Debug dbg, int base_sec_index, Dwarf_Unsigned offset, /* r_offset
+ of
+ reloc
+ */
+ Dwarf_Unsigned symidx,
+ enum Dwarf_Rel_Type,
+ int reltarget_length);
+int _dwarf_pro_reloc_name_stream32(Dwarf_P_Debug dbg, int base_sec_index, Dwarf_Unsigned offset, /* r_offset
+ of
+ reloc
+ */
+ Dwarf_Unsigned symidx,
+ enum Dwarf_Rel_Type,
+ int reltarget_length);
+int _dwarf_pro_reloc_length_stream(Dwarf_P_Debug dbg, int base_sec_index, Dwarf_Unsigned offset, /* r_offset
+ of
+ reloc
+ */
+ Dwarf_Unsigned start_symidx,
+ Dwarf_Unsigned end_symidx,
+ enum Dwarf_Rel_Type,
+ int reltarget_length);
+
+int _dwarf_stream_relocs_to_disk(Dwarf_P_Debug dbg,
+ Dwarf_Signed * new_sec_count);
diff --git a/usr/src/lib/libdwarf/common/pro_reloc_symbolic.c b/usr/src/lib/libdwarf/common/pro_reloc_symbolic.c
new file mode 100644
index 0000000000..22080a00cd
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_reloc_symbolic.c
@@ -0,0 +1,276 @@
+/*
+
+ Copyright (C) 2000,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
+
+*/
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#include <stdio.h>
+#include <string.h>
+/*#include <elfaccess.h> */
+#include "pro_incl.h"
+#include "pro_section.h"
+#include "pro_reloc.h"
+#include "pro_reloc_symbolic.h"
+
+/*
+ Return DW_DLV_ERROR on malloc error.
+ Return DW_DLV_OK otherwise
+*/
+
+int
+_dwarf_pro_reloc_name_symbolic(Dwarf_P_Debug dbg,
+ int base_sec_index,
+ Dwarf_Unsigned offset, /* r_offset of reloc */
+ Dwarf_Unsigned symidx,
+ enum Dwarf_Rel_Type type,
+ int reltarget_length)
+{
+ /* get a slot, fill in the slot entry */
+ void *relrec_to_fill = 0;
+ int res = 0;
+ struct Dwarf_Relocation_Data_s *slotp;
+
+ res = _dwarf_pro_reloc_get_a_slot(dbg, base_sec_index,
+ &relrec_to_fill);
+ if (res != DW_DLV_OK)
+ return res;
+ slotp = (struct Dwarf_Relocation_Data_s *) relrec_to_fill;
+ slotp->drd_type = type;
+ slotp->drd_length = reltarget_length;
+ slotp->drd_offset = offset;
+ slotp->drd_symbol_index = symidx;
+ return DW_DLV_OK;
+}
+
+
+
+/*
+ Return DW_DLV_ERROR on malloc error.
+ Return DW_DLV_OK otherwise
+*/
+int
+_dwarf_pro_reloc_length_symbolic(Dwarf_P_Debug dbg,
+ int base_sec_index,
+ Dwarf_Unsigned offset, /* r_offset of reloc */
+ Dwarf_Unsigned start_symidx,
+ Dwarf_Unsigned end_symidx,
+ enum Dwarf_Rel_Type type,
+ int reltarget_length)
+{
+ /* get a slot, fill in the slot entry */
+ void *relrec_to_fill = 0;
+ int res = 0;
+ struct Dwarf_Relocation_Data_s *slotp1 = 0;
+ struct Dwarf_Relocation_Data_s *slotp2 = 0;
+
+ res = _dwarf_pro_reloc_get_a_slot(dbg, base_sec_index,
+ &relrec_to_fill);
+ if (res != DW_DLV_OK)
+ return res;
+ slotp1 = (struct Dwarf_Relocation_Data_s *) relrec_to_fill;
+ res = _dwarf_pro_reloc_get_a_slot(dbg, base_sec_index,
+ &relrec_to_fill);
+ if (res != DW_DLV_OK)
+ return res;
+ slotp2 = (struct Dwarf_Relocation_Data_s *) relrec_to_fill;
+
+ /* ASSERT: type == dwarf_drt_first_of_length_type_pair */
+ slotp1->drd_type = type;
+ slotp1->drd_length = reltarget_length;
+ slotp1->drd_offset = offset;
+ slotp1->drd_symbol_index = start_symidx;
+
+ slotp2->drd_type = dwarf_drt_second_of_length_pair;
+ slotp2->drd_length = reltarget_length;
+ slotp2->drd_offset = offset;
+ slotp2->drd_symbol_index = end_symidx;
+ return DW_DLV_OK;
+}
+
+/*
+ Reset whatever fields of Dwarf_P_Per_Reloc_Sect_s
+ we must to allow adding a fresh new single
+ block easily (block consolidation use only).
+
+*/
+static void
+_dwarf_reset_reloc_sect_info(struct Dwarf_P_Per_Reloc_Sect_s *pblk,
+ unsigned long ct)
+{
+
+
+ /* Do not zero pr_sect_num_of_reloc_sect */
+ pblk->pr_reloc_total_count = 0;
+ pblk->pr_first_block = 0;
+ pblk->pr_last_block = 0;
+ pblk->pr_block_count = 0;
+ pblk->pr_slots_per_block_to_alloc = ct;
+}
+
+/*
+ Ensure each stream is a single buffer and
+ add that single buffer to the set of stream buffers.
+
+ By creating a new buffer and copying if necessary.
+ (If > 1 block, reduce to 1 block)
+
+ Free the input set of buffers if we consolidate.
+
+ We pass back *new_sec_count as zero because we
+ are not creating normal sections for a .o, but
+ symbolic relocations, separately counted.
+
+ Return -1 on error (malloc failure)
+
+ Return DW_DLV_OK on success. Any other return indicates
+ malloc failed.
+*/
+int
+_dwarf_symbolic_relocs_to_disk(Dwarf_P_Debug dbg,
+ Dwarf_Signed * new_sec_count)
+{
+ /* unsigned long total_size =0; */
+ Dwarf_Small *data = 0;
+ int sec_index = 0;
+ int res = 0;
+ unsigned long i = 0;
+ Dwarf_Error error = 0;
+ Dwarf_Signed sec_count = 0;
+ Dwarf_P_Per_Reloc_Sect p_reloc = &dbg->de_reloc_sect[0];
+
+ for (i = 0; i < NUM_DEBUG_SECTIONS; ++i, ++p_reloc) {
+ unsigned long ct = p_reloc->pr_reloc_total_count;
+ struct Dwarf_P_Relocation_Block_s *p_blk;
+ struct Dwarf_P_Relocation_Block_s *p_blk_last;
+ int err;
+ if (ct == 0) {
+ continue;
+ }
+
+ /* len = dbg->de_relocation_record_size; */
+ ++sec_count;
+
+ /* total_size = ct *len; */
+ sec_index = p_reloc->pr_sect_num_of_reloc_sect;
+ if (sec_index == 0) {
+ /* Call de_callback_func or de_callback_func_b,
+ getting section number of reloc section. */
+ int rel_section_index = 0;
+ int int_name = 0;
+ Dwarf_Unsigned name_idx = 0;
+
+ /*
+ This is a bit of a fake, as we do not really have true
+ elf sections at all. Just the data such might contain.
+ But this lets the caller eventually link things
+ together: without this call we would not know what rel
+ data goes with what section when we are asked for the
+ real arrays. */
+
+ if (dbg->de_callback_func_b) {
+ rel_section_index =
+ dbg->de_callback_func_b(_dwarf_rel_section_names[i],
+ dbg->de_relocation_record_size,
+ /* type */ SHT_REL,
+ /* flags */ 0,
+ /* link to symtab, which we cannot
+ know */ SHN_UNDEF,
+ /* sec rels apply to */
+ dbg->de_elf_sects[i],
+ &name_idx, &err);
+ } else {
+ rel_section_index =
+ dbg->de_callback_func(_dwarf_rel_section_names[i],
+ dbg->de_relocation_record_size,
+ /* type */ SHT_REL,
+ /* flags */ 0,
+ /* link to symtab, which we cannot
+ know */ SHN_UNDEF,
+ /* sec rels apply to, in elf, sh_info */
+ dbg->de_elf_sects[i], &int_name, &err);
+ name_idx = int_name;
+ }
+ if (rel_section_index == -1) {
+ {
+ _dwarf_p_error(dbg, &error, DW_DLE_ELF_SECT_ERR);
+ return (DW_DLV_ERROR);
+ }
+ }
+ p_reloc->pr_sect_num_of_reloc_sect = rel_section_index;
+ sec_index = rel_section_index;
+ }
+
+ p_blk = p_reloc->pr_first_block;
+
+ if (p_reloc->pr_block_count > 1) {
+ struct Dwarf_P_Relocation_Block_s *new_blk;
+
+ /* HACK , not normal interfaces, trashing p_reloc current
+ contents! */
+ _dwarf_reset_reloc_sect_info(p_reloc, ct);
+
+ /* Creating new single block for all 'ct' entries */
+ res = _dwarf_pro_pre_alloc_n_reloc_slots(dbg, (int) i, ct);
+ if (res != DW_DLV_OK) {
+ return res;
+ }
+ new_blk = p_reloc->pr_first_block;
+
+ data = (Dwarf_Small *) new_blk->rb_data;
+
+ /* The following loop does the consolidation to a single
+ block and frees the input block(s). */
+ do {
+ unsigned long len =
+ p_blk->rb_where_to_add_next - p_blk->rb_data;
+ memcpy(data, p_blk->rb_data, len);
+ data += len;
+ p_blk_last = p_blk;
+ p_blk = p_blk->rb_next;
+ _dwarf_p_dealloc(dbg, (Dwarf_Small *) p_blk_last);
+ } while (p_blk);
+ /* ASSERT: sum of len copied == total_size */
+ new_blk->rb_next_slot_to_use = ct;
+ new_blk->rb_where_to_add_next = (char *) data;
+ p_reloc->pr_reloc_total_count = ct;
+
+ /* have now created a single block, but no change in slots
+ used (pr_reloc_total_count) */
+ }
+ }
+ *new_sec_count = 0;
+ return DW_DLV_OK;
+}
diff --git a/usr/src/lib/libdwarf/common/pro_reloc_symbolic.h b/usr/src/lib/libdwarf/common/pro_reloc_symbolic.h
new file mode 100644
index 0000000000..3d03a47863
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_reloc_symbolic.h
@@ -0,0 +1,55 @@
+/*
+
+ Copyright (C) 2000,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
+
+*/
+
+
+int _dwarf_pro_reloc_name_symbolic(Dwarf_P_Debug dbg, int base_sec_index, Dwarf_Unsigned offset, /* r_offset
+ of
+ reloc
+ */
+ Dwarf_Unsigned symidx,
+ enum Dwarf_Rel_Type,
+ int reltarget_length);
+int
+ _dwarf_pro_reloc_length_symbolic(Dwarf_P_Debug dbg, int base_sec_index, Dwarf_Unsigned offset, /* r_offset
+ of
+ reloc
+ */
+ Dwarf_Unsigned start_symidx,
+ Dwarf_Unsigned end_symidx,
+ enum Dwarf_Rel_Type,
+ int reltarget_length);
+
+int _dwarf_symbolic_relocs_to_disk(Dwarf_P_Debug dbg,
+ Dwarf_Signed * new_sec_count);
diff --git a/usr/src/lib/libdwarf/common/pro_section.c b/usr/src/lib/libdwarf/common/pro_section.c
new file mode 100644
index 0000000000..6503c2cf09
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_section.c
@@ -0,0 +1,2221 @@
+/*
+
+ Copyright (C) 2000,2004,2006 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright (C) 2007-2010 David Anderson. All Rights Reserved.
+ Portions Copyright 2002-2010 Sun Microsystems, 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
+
+*/
+/*
+ SGI has moved from the Crittenden Lane address.
+*/
+
+
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_ELFACCESS_H
+#include <elfaccess.h>
+#endif
+#include "pro_incl.h"
+#include "pro_section.h"
+#include "pro_line.h"
+#include "pro_frame.h"
+#include "pro_die.h"
+#include "pro_macinfo.h"
+#include "pro_types.h"
+
+#ifndef SHF_MIPS_NOSTRIP
+/* if this is not defined, we probably don't need it: just use 0 */
+#define SHF_MIPS_NOSTRIP 0
+#endif
+#ifndef R_MIPS_NONE
+#define R_MIPS_NONE 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/* must match up with pro_section.h defines of DEBUG_INFO etc
+and sectnames (below). REL_SEC_PREFIX is either ".rel" or ".rela"
+see pro_incl.h
+*/
+char *_dwarf_rel_section_names[] = {
+ REL_SEC_PREFIX ".debug_info",
+ REL_SEC_PREFIX ".debug_line",
+ REL_SEC_PREFIX ".debug_abbrev", /* no relocations on this, really */
+ REL_SEC_PREFIX ".debug_frame",
+ REL_SEC_PREFIX ".debug_aranges",
+ REL_SEC_PREFIX ".debug_pubnames",
+ REL_SEC_PREFIX ".debug_str",
+ REL_SEC_PREFIX ".debug_funcnames", /* sgi extension */
+ REL_SEC_PREFIX ".debug_typenames", /* sgi extension */
+ REL_SEC_PREFIX ".debug_varnames", /* sgi extension */
+ REL_SEC_PREFIX ".debug_weaknames", /* sgi extension */
+ REL_SEC_PREFIX ".debug_macinfo",
+ REL_SEC_PREFIX ".debug_loc"
+};
+
+/* names of sections. Ensure that it matches the defines
+ in pro_section.h, in the same order
+ Must match also _dwarf_rel_section_names above
+*/
+char *_dwarf_sectnames[] = {
+ ".debug_info",
+ ".debug_line",
+ ".debug_abbrev",
+ ".debug_frame",
+ ".debug_aranges",
+ ".debug_pubnames",
+ ".debug_str",
+ ".debug_funcnames", /* sgi extension */
+ ".debug_typenames", /* sgi extension */
+ ".debug_varnames", /* sgi extension */
+ ".debug_weaknames", /* sgi extension */
+ ".debug_macinfo",
+ ".debug_loc"
+};
+
+
+
+
+static Dwarf_Ubyte std_opcode_len[] = { 0, /* DW_LNS_copy */
+ 1, /* DW_LNS_advance_pc */
+ 1, /* DW_LNS_advance_line */
+ 1, /* DW_LNS_set_file */
+ 1, /* DW_LNS_set_column */
+ 0, /* DW_LNS_negate_stmt */
+ 0, /* DW_LNS_set_basic_block */
+ 0, /* DW_LNS_const_add_pc */
+ 1, /* DW_LNS_fixed_advance_pc */
+};
+
+/* struct to hold relocation entries. Its mantained as a linked
+ list of relocation structs, and will then be written at as a
+ whole into the relocation section. Whether its 32 bit or
+ 64 bit will be obtained from Dwarf_Debug pointer.
+*/
+
+typedef struct Dwarf_P_Rel_s *Dwarf_P_Rel;
+struct Dwarf_P_Rel_s {
+ Dwarf_P_Rel dr_next;
+ void *dr_rel_datap;
+};
+typedef struct Dwarf_P_Rel_Head_s *Dwarf_P_Rel_Head;
+struct Dwarf_P_Rel_Head_s {
+ struct Dwarf_P_Rel_s *drh_head;
+ struct Dwarf_P_Rel_s *drh_tail;
+};
+
+static int _dwarf_pro_generate_debugline(Dwarf_P_Debug dbg,
+ Dwarf_Error * error);
+static int _dwarf_pro_generate_debugframe(Dwarf_P_Debug dbg,
+ Dwarf_Error * error);
+static int _dwarf_pro_generate_debuginfo(Dwarf_P_Debug dbg,
+ Dwarf_Error * error);
+static Dwarf_P_Abbrev _dwarf_pro_getabbrev(Dwarf_P_Die, Dwarf_P_Abbrev);
+static int _dwarf_pro_match_attr
+ (Dwarf_P_Attribute, Dwarf_P_Abbrev, int no_attr);
+
+/* these macros used as return value for below functions */
+#define OPC_INCS_ZERO -1
+#define OPC_OUT_OF_RANGE -2
+#define LINE_OUT_OF_RANGE -3
+static int _dwarf_pro_get_opc(Dwarf_Unsigned addr_adv, int line_adv);
+
+
+/* BEGIN_LEN_SIZE is the size of the 'length' field in total.
+ Which may be 4,8, or 12 bytes!
+ 4 is standard DWARF2.
+ 8 is non-standard MIPS-IRIX 64-bit.
+ 12 is standard DWARF3 for 64 bit offsets.
+ Used in various routines: local variable names
+ must match the names here.
+*/
+#define BEGIN_LEN_SIZE (uwordb_size + extension_size)
+
+/*
+ Return TRUE if we need the section, FALSE otherwise
+
+ If any of the 'line-data-related' calls were made
+ including file or directory entries,
+ produce .debug_line .
+
+*/
+static int
+dwarf_need_debug_line_section(Dwarf_P_Debug dbg)
+{
+ if (dbg->de_lines == NULL && dbg->de_file_entries == NULL
+ && dbg->de_inc_dirs == NULL) {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*
+ Convert debug information to a format such that
+ it can be written on disk.
+ Called exactly once per execution.
+*/
+Dwarf_Signed
+dwarf_transform_to_disk_form(Dwarf_P_Debug dbg, Dwarf_Error * error)
+{
+ /*
+ Section data in written out in a number of buffers. Each
+ _generate_*() function returns a cumulative count of buffers for
+ all the sections. get_section_bytes() returns pointers to these
+ buffers one at a time. */
+ int nbufs = 0;
+ int sect = 0;
+ int err = 0;
+ Dwarf_Unsigned du = 0;
+
+ if (dbg->de_version_magic_number != PRO_VERSION_MAGIC) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_IA, DW_DLV_NOCOUNT);
+ }
+
+ /* Create dwarf section headers */
+ for (sect = 0; sect < NUM_DEBUG_SECTIONS; sect++) {
+ long flags = 0;
+
+ switch (sect) {
+
+ case DEBUG_INFO:
+ if (dbg->de_dies == NULL)
+ continue;
+ break;
+
+ case DEBUG_LINE:
+ if (dwarf_need_debug_line_section(dbg) == FALSE) {
+ continue;
+ }
+ break;
+
+ case DEBUG_ABBREV:
+ if (dbg->de_dies == NULL)
+ continue;
+ break;
+
+ case DEBUG_FRAME:
+ if (dbg->de_frame_cies == NULL)
+ continue;
+ flags = SHF_MIPS_NOSTRIP;
+ break;
+
+ case DEBUG_ARANGES:
+ if (dbg->de_arange == NULL)
+ continue;
+ break;
+
+ case DEBUG_PUBNAMES:
+ if (dbg->de_simple_name_headers[dwarf_snk_pubname].
+ sn_head == NULL)
+ continue;
+ break;
+
+ case DEBUG_STR:
+ if (dbg->de_strings == NULL)
+ continue;
+ break;
+
+ case DEBUG_FUNCNAMES:
+ if (dbg->de_simple_name_headers[dwarf_snk_funcname].
+ sn_head == NULL)
+ continue;
+ break;
+
+ case DEBUG_TYPENAMES:
+ if (dbg->de_simple_name_headers[dwarf_snk_typename].
+ sn_head == NULL)
+ continue;
+ break;
+
+ case DEBUG_VARNAMES:
+ if (dbg->de_simple_name_headers[dwarf_snk_varname].
+ sn_head == NULL)
+ continue;
+ break;
+
+ case DEBUG_WEAKNAMES:
+ if (dbg->de_simple_name_headers[dwarf_snk_weakname].
+ sn_head == NULL)
+ continue;
+ break;
+
+ case DEBUG_MACINFO:
+ if (dbg->de_first_macinfo == NULL)
+ continue;
+ break;
+ case DEBUG_LOC:
+ /* not handled yet */
+ continue;
+ default:
+ /* logic error: missing a case */
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_ELF_SECT_ERR, DW_DLV_NOCOUNT);
+ }
+ {
+ int new_base_elf_sect;
+
+ if (dbg->de_callback_func_b) {
+ new_base_elf_sect =
+ dbg->de_callback_func_b(_dwarf_sectnames[sect],
+ /* rec size */ 1,
+ SECTION_TYPE,
+ flags, SHN_UNDEF, 0, &du, &err);
+
+ } else {
+ int name_idx = 0;
+ new_base_elf_sect = dbg->de_callback_func(
+ _dwarf_sectnames[sect],
+ dbg->de_relocation_record_size,
+ SECTION_TYPE, flags,
+ SHN_UNDEF, 0,
+ &name_idx, &err);
+ du = name_idx;
+ }
+ if (new_base_elf_sect == -1) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_ELF_SECT_ERR,
+ DW_DLV_NOCOUNT);
+ }
+ dbg->de_elf_sects[sect] = new_base_elf_sect;
+
+ dbg->de_sect_name_idx[sect] = du;
+ }
+ }
+
+ nbufs = 0;
+
+ /*
+ Changing the order in which the sections are generated may cause
+ problems because of relocations. */
+
+ if (dwarf_need_debug_line_section(dbg) == TRUE) {
+ nbufs = _dwarf_pro_generate_debugline(dbg, error);
+ if (nbufs < 0) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_DEBUGLINE_ERROR,
+ DW_DLV_NOCOUNT);
+ }
+ }
+
+ if (dbg->de_frame_cies) {
+ nbufs = _dwarf_pro_generate_debugframe(dbg, error);
+ if (nbufs < 0) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_DEBUGFRAME_ERROR,
+ DW_DLV_NOCOUNT);
+ }
+ }
+ if (dbg->de_first_macinfo) {
+ nbufs = _dwarf_pro_transform_macro_info_to_disk(dbg, error);
+ if (nbufs < 0) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_DEBUGMACINFO_ERROR,
+ DW_DLV_NOCOUNT);
+ }
+ }
+
+ if (dbg->de_dies) {
+ nbufs = _dwarf_pro_generate_debuginfo(dbg, error);
+ if (nbufs < 0) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_DEBUGINFO_ERROR,
+ DW_DLV_NOCOUNT);
+ }
+ }
+
+ if (dbg->de_arange) {
+ nbufs = _dwarf_transform_arange_to_disk(dbg, error);
+ if (nbufs < 0) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_DEBUGINFO_ERROR,
+ DW_DLV_NOCOUNT);
+ }
+ }
+
+ if (dbg->de_simple_name_headers[dwarf_snk_pubname].sn_head) {
+ nbufs = _dwarf_transform_simplename_to_disk(dbg,
+ dwarf_snk_pubname,
+ DEBUG_PUBNAMES,
+ error);
+
+
+ if (nbufs < 0) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_DEBUGINFO_ERROR,
+ DW_DLV_NOCOUNT);
+ }
+ }
+
+ if (dbg->de_simple_name_headers[dwarf_snk_funcname].sn_head) {
+ nbufs = _dwarf_transform_simplename_to_disk(dbg,
+ dwarf_snk_funcname,
+ DEBUG_FUNCNAMES,
+ error);
+ if (nbufs < 0) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_DEBUGINFO_ERROR,
+ DW_DLV_NOCOUNT);
+ }
+ }
+
+ if (dbg->de_simple_name_headers[dwarf_snk_typename].sn_head) {
+ nbufs = _dwarf_transform_simplename_to_disk(dbg,
+ dwarf_snk_typename,
+ DEBUG_TYPENAMES,
+ error);
+ if (nbufs < 0) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_DEBUGINFO_ERROR,
+ DW_DLV_NOCOUNT);
+ }
+ }
+
+ if (dbg->de_simple_name_headers[dwarf_snk_varname].sn_head) {
+ nbufs = _dwarf_transform_simplename_to_disk(dbg,
+ dwarf_snk_varname,
+ DEBUG_VARNAMES,
+ error);
+
+ if (nbufs < 0) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_DEBUGINFO_ERROR,
+ DW_DLV_NOCOUNT);
+ }
+ }
+
+ if (dbg->de_simple_name_headers[dwarf_snk_weakname].sn_head) {
+ nbufs = _dwarf_transform_simplename_to_disk(dbg,
+ dwarf_snk_weakname, DEBUG_WEAKNAMES, error);
+ if (nbufs < 0) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_DEBUGINFO_ERROR,
+ DW_DLV_NOCOUNT);
+ }
+ }
+
+ {
+ Dwarf_Signed new_secs = 0;
+ int res = 0;
+
+ res = dbg->de_transform_relocs_to_disk(dbg, &new_secs);
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_DEBUGINFO_ERROR,
+ DW_DLV_NOCOUNT);
+ }
+ nbufs += new_secs;
+ }
+ return nbufs;
+}
+
+
+/*---------------------------------------------------------------
+ Generate debug_line section
+---------------------------------------------------------------*/
+static int
+_dwarf_pro_generate_debugline(Dwarf_P_Debug dbg, Dwarf_Error * error)
+{
+ Dwarf_P_Inc_Dir curdir = 0;
+ Dwarf_P_F_Entry curentry = 0;
+ Dwarf_P_Line curline = 0;
+ Dwarf_P_Line prevline = 0;
+
+ /* all data named cur* are used to loop thru linked lists */
+
+ int sum_bytes = 0;
+ int prolog_size = 0;
+ unsigned char *data = 0; /* holds disk form data */
+ int elfsectno = 0;
+ unsigned char *start_line_sec = 0; /* pointer to the buffer at
+ section start */
+ /* temps for memcpy */
+ Dwarf_Unsigned du = 0;
+ Dwarf_Ubyte db = 0;
+ Dwarf_Half dh = 0;
+ int res = 0;
+ int uwordb_size = dbg->de_offset_size;
+ int extension_size = dbg->de_64bit_extension ? 4 : 0;
+ int upointer_size = dbg->de_pointer_size;
+ char buff1[ENCODE_SPACE_NEEDED];
+
+
+
+ sum_bytes = 0;
+
+ elfsectno = dbg->de_elf_sects[DEBUG_LINE];
+
+ /* include directories */
+ curdir = dbg->de_inc_dirs;
+ while (curdir) {
+ prolog_size += strlen(curdir->did_name) + 1;
+ curdir = curdir->did_next;
+ }
+ prolog_size++; /* last null following last directory
+ entry. */
+
+ /* file entries */
+ curentry = dbg->de_file_entries;
+ while (curentry) {
+ prolog_size +=
+ strlen(curentry->dfe_name) + 1 + curentry->dfe_nbytes;
+ curentry = curentry->dfe_next;
+ }
+ prolog_size++; /* last null byte */
+
+
+ prolog_size += BEGIN_LEN_SIZE + sizeof_uhalf(dbg) + /* version # */
+ uwordb_size + /* header length */
+ sizeof_ubyte(dbg) + /* min_instr length */
+ sizeof_ubyte(dbg) + /* default is_stmt */
+ sizeof_ubyte(dbg) + /* linebase */
+ sizeof_ubyte(dbg) + /* linerange */
+ sizeof_ubyte(dbg); /* opcode base */
+
+ /* length of table specifying # of opnds */
+ prolog_size += sizeof(std_opcode_len);
+
+ GET_CHUNK(dbg, elfsectno, data, prolog_size, error);
+ start_line_sec = data;
+
+ /* copy over the data */
+ /* total_length */
+ du = 0;
+ if (extension_size) {
+ Dwarf_Word x = DISTINGUISHED_VALUE;
+
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &x,
+ sizeof(x), extension_size);
+ data += extension_size;
+ }
+
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &du,
+ sizeof(du), uwordb_size);
+ data += uwordb_size;
+
+ dh = VERSION;
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &dh,
+ sizeof(dh), sizeof(Dwarf_Half));
+ data += sizeof(Dwarf_Half);
+
+ /* header length */
+ du = prolog_size - (BEGIN_LEN_SIZE + sizeof(Dwarf_Half) +
+ uwordb_size);
+ {
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &du,
+ sizeof(du), uwordb_size);
+ data += uwordb_size;
+ }
+ db = MIN_INST_LENGTH;
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+ db = DEFAULT_IS_STMT;
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+ db = (Dwarf_Ubyte) LINE_BASE;
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+ db = LINE_RANGE;
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+ db = OPCODE_BASE;
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) std_opcode_len,
+ sizeof(std_opcode_len), sizeof(std_opcode_len));
+ data += sizeof(std_opcode_len);
+
+ /* copy over include directories */
+ curdir = dbg->de_inc_dirs;
+ while (curdir) {
+ strcpy((char *) data, curdir->did_name);
+ data += strlen(curdir->did_name) + 1;
+ curdir = curdir->did_next;
+ }
+ *data = '\0'; /* last null */
+ data++;
+
+ /* copy file entries */
+ curentry = dbg->de_file_entries;
+ while (curentry) {
+ strcpy((char *) data, curentry->dfe_name);
+ data += strlen(curentry->dfe_name) + 1;
+ /* copies of leb numbers, no endian issues */
+ memcpy((void *) data,
+ (const void *) curentry->dfe_args, curentry->dfe_nbytes);
+ data += curentry->dfe_nbytes;
+ curentry = curentry->dfe_next;
+ }
+ *data = '\0';
+ data++;
+
+ sum_bytes += prolog_size;
+
+ curline = dbg->de_lines;
+ prevline = (Dwarf_P_Line)
+ _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Line_s));
+ if (prevline == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_LINE_ALLOC, -1);
+ }
+ _dwarf_pro_reg_init(prevline);
+ /* generate opcodes for line numbers */
+ while (curline) {
+ int nbytes;
+ char *arg;
+ int opc;
+ int no_lns_copy; /* if lns copy opcode doesnt need to be
+ generated, if special opcode or end
+ sequence */
+ Dwarf_Unsigned addr_adv;
+ int line_adv; /* supposed to be a reasonably small
+ number, so the size should not be a
+ problem. ? */
+
+ no_lns_copy = 0;
+ if (curline->dpl_opc != 0) {
+ int inst_bytes; /* no of bytes in extended opcode */
+ char *str; /* hold leb encoded inst_bytes */
+ int str_nbytes; /* no of bytes in str */
+
+ switch (curline->dpl_opc) {
+ case DW_LNE_end_sequence:
+
+ /* Advance pc to end of text section. */
+ addr_adv = curline->dpl_address - prevline->dpl_address;
+ if (addr_adv > 0) {
+ db = DW_LNS_advance_pc;
+ res =
+ _dwarf_pro_encode_leb128_nm(addr_adv /
+ MIN_INST_LENGTH,
+ &nbytes, buff1,
+ sizeof(buff1));
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_CHUNK_ALLOC, -1);
+ }
+ GET_CHUNK(dbg, elfsectno, data,
+ nbytes + sizeof(Dwarf_Ubyte), error);
+ WRITE_UNALIGNED(dbg, (void *) data,
+ (const void *) &db, sizeof(db),
+ sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+ /* leb, no endianness issue */
+ memcpy((void *) data, (const void *) buff1, nbytes);
+ data += nbytes + sizeof(Dwarf_Ubyte);
+ sum_bytes += nbytes + sizeof(Dwarf_Ubyte);
+ prevline->dpl_address = curline->dpl_address;
+ }
+
+ /* first null byte */
+ db = 0;
+ GET_CHUNK(dbg, elfsectno, data, sizeof(Dwarf_Ubyte),
+ error);
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+ sum_bytes += sizeof(Dwarf_Ubyte);
+
+ /* write length of extended opcode */
+ inst_bytes = sizeof(Dwarf_Ubyte);
+ res =
+ _dwarf_pro_encode_leb128_nm(inst_bytes, &str_nbytes,
+ buff1, sizeof(buff1));
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_CHUNK_ALLOC, -1);
+ }
+ GET_CHUNK(dbg, elfsectno, data, str_nbytes, error);
+ memcpy((void *) data, (const void *) buff1, str_nbytes);
+ data += str_nbytes;
+ sum_bytes += str_nbytes;
+
+ /* write extended opcode */
+ db = DW_LNE_end_sequence;
+ GET_CHUNK(dbg, elfsectno, data, sizeof(Dwarf_Ubyte),
+ error);
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+ sum_bytes += sizeof(Dwarf_Ubyte);
+ /* reset value to original values */
+ _dwarf_pro_reg_init(prevline);
+ no_lns_copy = 1;
+ /* this is set only for end_sequence, so that a
+ dw_lns_copy is not generated */
+ break;
+
+ case DW_LNE_set_address:
+
+ /* first null byte */
+ db = 0;
+ GET_CHUNK(dbg, elfsectno, data, sizeof(Dwarf_Ubyte),
+ error);
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+ sum_bytes += sizeof(Dwarf_Ubyte);
+
+ /* write length of extended opcode */
+ inst_bytes = sizeof(Dwarf_Ubyte) + upointer_size;
+ res =
+ _dwarf_pro_encode_leb128_nm(inst_bytes, &str_nbytes,
+ buff1, sizeof(buff1));
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_CHUNK_ALLOC, -1);
+ }
+ GET_CHUNK(dbg, elfsectno, data, str_nbytes, error);
+ str = buff1;
+ /* leb number, no endian issue */
+ memcpy((void *) data, (const void *) str, str_nbytes);
+ data += str_nbytes;
+ sum_bytes += str_nbytes;
+
+ /* write extended opcode */
+ db = DW_LNE_set_address;
+ GET_CHUNK(dbg, elfsectno, data, upointer_size +
+ sizeof(Dwarf_Ubyte), error);
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+ sum_bytes += sizeof(Dwarf_Ubyte);
+
+ /* reloc for address */
+ res = dbg->de_reloc_name(dbg, DEBUG_LINE,
+ sum_bytes, /* r_offset */
+ curline->dpl_r_symidx,
+ dwarf_drt_data_reloc,
+ uwordb_size);
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_CHUNK_ALLOC, -1);
+ }
+
+ /* write offset (address) */
+ du = curline->dpl_address;
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &du,
+ sizeof(du), upointer_size);
+ data += upointer_size;
+ sum_bytes += upointer_size;
+ prevline->dpl_address = curline->dpl_address;
+ no_lns_copy = 1;
+ break;
+ }
+ } else {
+ if (curline->dpl_file != prevline->dpl_file) {
+ db = DW_LNS_set_file;
+ res =
+ _dwarf_pro_encode_leb128_nm(curline->dpl_file,
+ &nbytes, buff1,
+ sizeof(buff1));
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_CHUNK_ALLOC, -1);
+ }
+ arg = buff1;
+ GET_CHUNK(dbg, elfsectno, data,
+ nbytes + sizeof(Dwarf_Ubyte), error);
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+ memcpy((void *) data, (const void *) arg, nbytes);
+ data += nbytes;
+ sum_bytes += nbytes + sizeof(Dwarf_Ubyte);
+ prevline->dpl_file = curline->dpl_file;
+ }
+ if (curline->dpl_column != prevline->dpl_column) {
+ db = DW_LNS_set_column;
+ res = _dwarf_pro_encode_leb128_nm(curline->dpl_column,
+ &nbytes,
+ buff1, sizeof(buff1));
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_CHUNK_ALLOC, -1);
+ }
+
+ arg = buff1;
+ GET_CHUNK(dbg, elfsectno, data,
+ nbytes + sizeof(Dwarf_Ubyte), error);
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+ memcpy((void *) data, (const void *) arg, nbytes);
+ data += nbytes;
+ sum_bytes += nbytes + sizeof(Dwarf_Ubyte);
+ prevline->dpl_column = curline->dpl_column;
+ }
+ if (curline->dpl_is_stmt != prevline->dpl_is_stmt) {
+ db = DW_LNS_negate_stmt;
+ GET_CHUNK(dbg, elfsectno, data, sizeof(Dwarf_Ubyte),
+ error);
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+ sum_bytes += sizeof(Dwarf_Ubyte);
+ prevline->dpl_is_stmt = curline->dpl_is_stmt;
+ }
+ if (curline->dpl_basic_block == true &&
+ prevline->dpl_basic_block == false) {
+ db = DW_LNS_set_basic_block;
+ GET_CHUNK(dbg, elfsectno, data, sizeof(Dwarf_Ubyte),
+ error);
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+ sum_bytes += sizeof(Dwarf_Ubyte);
+ prevline->dpl_basic_block = curline->dpl_basic_block;
+ }
+ addr_adv = curline->dpl_address - prevline->dpl_address;
+
+ line_adv = (int) (curline->dpl_line - prevline->dpl_line);
+ if ((addr_adv % MIN_INST_LENGTH) != 0) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_WRONG_ADDRESS, -1);
+ }
+ if ((opc = _dwarf_pro_get_opc(addr_adv, line_adv)) > 0) {
+ no_lns_copy = 1;
+ db = opc;
+ GET_CHUNK(dbg, elfsectno, data, sizeof(Dwarf_Ubyte),
+ error);
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+ sum_bytes += sizeof(Dwarf_Ubyte);
+ prevline->dpl_basic_block = false;
+ prevline->dpl_address = curline->dpl_address;
+ prevline->dpl_line = curline->dpl_line;
+ } else {
+ if (addr_adv > 0) {
+ db = DW_LNS_advance_pc;
+ res =
+ _dwarf_pro_encode_leb128_nm(addr_adv /
+ MIN_INST_LENGTH,
+ &nbytes, buff1,
+ sizeof(buff1));
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_CHUNK_ALLOC, -1);
+ }
+
+ arg = buff1;
+ GET_CHUNK(dbg, elfsectno, data,
+ nbytes + sizeof(Dwarf_Ubyte), error);
+ WRITE_UNALIGNED(dbg, (void *) data,
+ (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+ memcpy((void *) data, (const void *) arg, nbytes);
+ data += nbytes + sizeof(Dwarf_Ubyte);
+ sum_bytes += nbytes + sizeof(Dwarf_Ubyte);
+ prevline->dpl_basic_block = false;
+ prevline->dpl_address = curline->dpl_address;
+ }
+ if (line_adv != 0) {
+ db = DW_LNS_advance_line;
+ res = _dwarf_pro_encode_signed_leb128_nm(line_adv,
+ &nbytes,
+ buff1,
+ sizeof
+ (buff1));
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_CHUNK_ALLOC, -1);
+ }
+
+ arg = buff1;
+ GET_CHUNK(dbg, elfsectno, data,
+ nbytes + sizeof(Dwarf_Ubyte), error);
+ WRITE_UNALIGNED(dbg, (void *) data,
+ (const void *) &db, sizeof(db),
+ sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+ memcpy((void *) data, (const void *) arg, nbytes);
+ data += nbytes + sizeof(Dwarf_Ubyte);
+ sum_bytes += nbytes + sizeof(Dwarf_Ubyte);
+ prevline->dpl_basic_block = false;
+ prevline->dpl_line = curline->dpl_line;
+ }
+ }
+ } /* ends else for opc != 0 */
+ if (no_lns_copy == 0) { /* if not a special or dw_lne_end_seq
+ generate a matrix line */
+ db = DW_LNS_copy;
+ GET_CHUNK(dbg, elfsectno, data, sizeof(Dwarf_Ubyte), error);
+ WRITE_UNALIGNED(dbg, (void *) data,
+ (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+ sum_bytes += sizeof(Dwarf_Ubyte);
+ prevline->dpl_basic_block = false;
+ }
+ curline = curline->dpl_next;
+ }
+
+ /* write total length field */
+ du = sum_bytes - BEGIN_LEN_SIZE;
+ {
+ start_line_sec += extension_size;
+ WRITE_UNALIGNED(dbg, (void *) start_line_sec,
+ (const void *) &du, sizeof(du), uwordb_size);
+ }
+
+ return (int) dbg->de_n_debug_sect;
+}
+
+/*---------------------------------------------------------------
+ Generate debug_frame section
+---------------------------------------------------------------*/
+static int
+_dwarf_pro_generate_debugframe(Dwarf_P_Debug dbg, Dwarf_Error * error)
+{
+ int elfsectno = 0;
+ int i = 0;
+ int firsttime = 1;
+ int pad = 0; /* Pad for padding to align cies and fdes */
+ Dwarf_P_Cie curcie = 0;
+ Dwarf_P_Fde curfde = 0;
+ unsigned char *data = 0;
+ Dwarf_sfixed dsw = 0;
+ Dwarf_Unsigned du = 0;
+ Dwarf_Ubyte db = 0;
+ long *cie_offs = 0; /* Holds byte offsets for links to fde's */
+ unsigned long cie_length = 0;
+ int cie_no = 0;
+ int uwordb_size = dbg->de_offset_size;
+ int extension_size = dbg->de_64bit_extension ? 4 : 0;
+ int upointer_size = dbg->de_pointer_size;
+ Dwarf_Unsigned cur_off = 0; /* current offset of written data, held
+ for relocation info */
+
+ elfsectno = dbg->de_elf_sects[DEBUG_FRAME];
+
+ curcie = dbg->de_frame_cies;
+ cie_length = 0;
+ cur_off = 0;
+ cie_offs = (long *)
+ _dwarf_p_get_alloc(dbg, sizeof(long) * dbg->de_n_cie);
+ if (cie_offs == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_CIE_OFFS_ALLOC, -1);
+ }
+ /* Generate cie number as we go along. This writes
+ all CIEs first before any FDEs, which is rather
+ different from the order a compiler might like (which
+ might be each CIE followed by its FDEs then the next CIE, and
+ so on). */
+ cie_no = 1;
+ while (curcie) {
+ char *code_al = 0;
+ int c_bytes = 0;
+ char *data_al = 0;
+ int d_bytes = 0;
+ int res = 0;
+ char buff1[ENCODE_SPACE_NEEDED];
+ char buff2[ENCODE_SPACE_NEEDED];
+ char buff3[ENCODE_SPACE_NEEDED];
+ char *augmentation = 0;
+ char *augmented_al = 0;
+ long augmented_fields_length = 0;
+ int a_bytes = 0;
+
+ res = _dwarf_pro_encode_leb128_nm(curcie->cie_code_align,
+ &c_bytes,
+ buff1, sizeof(buff1));
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_CIE_OFFS_ALLOC, -1);
+ }
+ /* Before April 1999, the following was using an unsigned
+ encode. That worked ok even though the decoder used the
+ correct signed leb read, but doing the encode correctly
+ (according to the dwarf spec) saves space in the output file
+ and is completely compatible.
+
+ Note the actual stored amount on MIPS was 10 bytes (!) to
+ store the value -4. (hex)fc ffffffff ffffffff 01 The
+ libdwarf consumer consumed all 10 bytes too!
+
+ old version res =
+ _dwarf_pro_encode_leb128_nm(curcie->cie_data_align,
+
+ below is corrected signed version. */
+ res = _dwarf_pro_encode_signed_leb128_nm(curcie->cie_data_align,
+ &d_bytes,
+ buff2, sizeof(buff2));
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_CIE_OFFS_ALLOC, -1);
+ }
+ code_al = buff1;
+ data_al = buff2;
+
+ /* get the correct offset */
+ if (firsttime) {
+ cie_offs[cie_no - 1] = 0;
+ firsttime = 0;
+ } else {
+ cie_offs[cie_no - 1] = cie_offs[cie_no - 2] +
+ (long) cie_length + BEGIN_LEN_SIZE;
+ }
+ cie_no++;
+ augmentation = curcie->cie_aug;
+ if (strcmp(augmentation, DW_CIE_AUGMENTER_STRING_V0) == 0) {
+ augmented_fields_length = 0;
+ res = _dwarf_pro_encode_leb128_nm(augmented_fields_length,
+ &a_bytes, buff3,
+ sizeof(buff3));
+ augmented_al = buff3;
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_CIE_OFFS_ALLOC, -1);
+ }
+ cie_length = uwordb_size + /* cie_id */
+ sizeof(Dwarf_Ubyte) + /* cie version */
+ strlen(curcie->cie_aug) + 1 + /* augmentation */
+ c_bytes + /* code alignment factor */
+ d_bytes + /* data alignment factor */
+ sizeof(Dwarf_Ubyte) + /* return reg address */
+ a_bytes + /* augmentation length */
+ curcie->cie_inst_bytes;
+ } else {
+ cie_length = uwordb_size + /* cie_id */
+ sizeof(Dwarf_Ubyte) + /* cie version */
+ strlen(curcie->cie_aug) + 1 + /* augmentation */
+ c_bytes + d_bytes + sizeof(Dwarf_Ubyte) + /* return
+ reg
+ address
+ */
+ curcie->cie_inst_bytes;
+ }
+ pad = (int) PADDING(cie_length, upointer_size);
+ cie_length += pad;
+ GET_CHUNK(dbg, elfsectno, data, cie_length +
+ BEGIN_LEN_SIZE, error);
+ if (extension_size) {
+ Dwarf_Unsigned x = DISTINGUISHED_VALUE;
+
+ WRITE_UNALIGNED(dbg, (void *) data,
+ (const void *) &x,
+ sizeof(x), extension_size);
+ data += extension_size;
+
+ }
+ du = cie_length;
+ /* total length of cie */
+ WRITE_UNALIGNED(dbg, (void *) data,
+ (const void *) &du, sizeof(du), uwordb_size);
+ data += uwordb_size;
+
+ /* cie-id is a special value. */
+ du = DW_CIE_ID;
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &du,
+ sizeof(du), uwordb_size);
+ data += uwordb_size;
+
+ db = curcie->cie_version;
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+ strcpy((char *) data, curcie->cie_aug);
+ data += strlen(curcie->cie_aug) + 1;
+ memcpy((void *) data, (const void *) code_al, c_bytes);
+ data += c_bytes;
+ memcpy((void *) data, (const void *) data_al, d_bytes);
+ data += d_bytes;
+ db = curcie->cie_ret_reg;
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+
+ if (strcmp(augmentation, DW_CIE_AUGMENTER_STRING_V0) == 0) {
+ memcpy((void *) data, (const void *) augmented_al, a_bytes);
+ data += a_bytes;
+ }
+ memcpy((void *) data, (const void *) curcie->cie_inst,
+ curcie->cie_inst_bytes);
+ data += curcie->cie_inst_bytes;
+ for (i = 0; i < pad; i++) {
+ *data = DW_CFA_nop;
+ data++;
+ }
+ curcie = curcie->cie_next;
+ }
+ /* calculate current offset */
+ cur_off = cie_offs[cie_no - 2] + cie_length + BEGIN_LEN_SIZE;
+
+ /* write out fde's */
+ curfde = dbg->de_frame_fdes;
+ while (curfde) {
+ Dwarf_P_Frame_Pgm curinst = 0;
+ long fde_length = 0;
+ int pad = 0;
+ Dwarf_P_Cie cie_ptr = 0;
+ Dwarf_Word cie_index = 0;
+ Dwarf_Word index = 0;
+ int oet_length = 0;
+ int afl_length = 0;
+ int res = 0;
+ int v0_augmentation = 0;
+#if 0
+ unsigned char *fde_start_point = 0;
+#endif
+ char afl_buff[ENCODE_SPACE_NEEDED];
+
+ /* Find the CIE associated with this fde. */
+ cie_ptr = dbg->de_frame_cies;
+ cie_index = curfde->fde_cie;
+ index = 1; /* The cie_index of the first cie is 1,
+ not 0. */
+ while (cie_ptr && index < cie_index) {
+ cie_ptr = cie_ptr->cie_next;
+ index++;
+ }
+ if (cie_ptr == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_CIE_NULL, -1);
+ }
+
+ if (strcmp(cie_ptr->cie_aug, DW_CIE_AUGMENTER_STRING_V0) == 0) {
+ v0_augmentation = 1;
+ oet_length = sizeof(Dwarf_sfixed);
+ /* encode the length of augmented fields. */
+ res = _dwarf_pro_encode_leb128_nm(oet_length,
+ &afl_length, afl_buff,
+ sizeof(afl_buff));
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_CIE_OFFS_ALLOC, -1);
+ }
+
+ fde_length = curfde->fde_n_bytes + BEGIN_LEN_SIZE + /* cie
+ pointer
+ */
+ upointer_size + /* initial loc */
+ upointer_size + /* address range */
+ afl_length + /* augmented field length */
+ oet_length; /* exception_table offset */
+ } else {
+ fde_length = curfde->fde_n_bytes + BEGIN_LEN_SIZE + /* cie
+ pointer
+ */
+ upointer_size + /* initial loc */
+ upointer_size; /* address range */
+ }
+
+
+ if (curfde->fde_die) {
+ /* IRIX/MIPS extension:
+ Using fde offset, generate DW_AT_MIPS_fde attribute for the
+ die corresponding to this fde. */
+ if(_dwarf_pro_add_AT_fde(dbg, curfde->fde_die, cur_off,
+ error) < 0) {
+ return -1;
+ }
+ }
+
+ /* store relocation for cie pointer */
+ res = dbg->de_reloc_name(dbg, DEBUG_FRAME, cur_off +
+ BEGIN_LEN_SIZE /* r_offset */,
+ dbg->de_sect_name_idx[DEBUG_FRAME],
+ dwarf_drt_data_reloc, uwordb_size);
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_CHUNK_ALLOC, -1);
+ }
+
+ /* store relocation information for initial location */
+ res = dbg->de_reloc_name(dbg, DEBUG_FRAME,
+ cur_off + BEGIN_LEN_SIZE +
+ upointer_size /* r_offset */,
+ curfde->fde_r_symidx,
+ dwarf_drt_data_reloc, upointer_size);
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_CHUNK_ALLOC, -1);
+ }
+ /* Store the relocation information for the
+ offset_into_exception_info field, if the offset is valid (0
+ is a valid offset). */
+ if (v0_augmentation &&
+ curfde->fde_offset_into_exception_tables >= 0) {
+
+ res = dbg->de_reloc_name(dbg, DEBUG_FRAME,
+ /* r_offset, where in cie this
+ field starts */
+ cur_off + BEGIN_LEN_SIZE +
+ uwordb_size + 2 * upointer_size +
+ afl_length,
+ curfde->fde_exception_table_symbol,
+ dwarf_drt_segment_rel,
+ sizeof(Dwarf_sfixed));
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_CHUNK_ALLOC, -1);
+ }
+ }
+
+ /* adjust for padding */
+ pad = (int) PADDING(fde_length, upointer_size);
+ fde_length += pad;
+
+
+ /* write out fde */
+ GET_CHUNK(dbg, elfsectno, data, fde_length + BEGIN_LEN_SIZE,
+ error);
+#if 0
+ fde_start_point = data;
+#endif
+ du = fde_length;
+ {
+ if (extension_size) {
+ Dwarf_Word x = DISTINGUISHED_VALUE;
+
+ WRITE_UNALIGNED(dbg, (void *) data,
+ (const void *) &x,
+ sizeof(x), extension_size);
+ data += extension_size;
+ }
+ /* length */
+ WRITE_UNALIGNED(dbg, (void *) data,
+ (const void *) &du,
+ sizeof(du), uwordb_size);
+ data += uwordb_size;
+
+ /* offset to cie */
+ du = cie_offs[curfde->fde_cie - 1];
+ WRITE_UNALIGNED(dbg, (void *) data,
+ (const void *) &du,
+ sizeof(du), uwordb_size);
+ data += uwordb_size;
+
+ du = curfde->fde_initloc;
+ WRITE_UNALIGNED(dbg, (void *) data,
+ (const void *) &du,
+ sizeof(du), upointer_size);
+ data += upointer_size;
+
+ if (dbg->de_reloc_pair &&
+ curfde->fde_end_symbol != 0 &&
+ curfde->fde_addr_range == 0) {
+ /* symbolic reloc, need reloc for length What if we
+ really know the length? If so, should use the other
+ part of 'if'. */
+ Dwarf_Unsigned val;
+
+ res = dbg->de_reloc_pair(dbg,
+ /* DEBUG_ARANGES, */
+ DEBUG_FRAME, cur_off + 2 * uwordb_size + upointer_size, /* r_offset
+ */
+ curfde->fde_r_symidx,
+ curfde->fde_end_symbol,
+ dwarf_drt_first_of_length_pair,
+ upointer_size);
+ if (res != DW_DLV_OK) {
+ {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (0);
+ }
+ }
+
+ /* arrange pre-calc so assem text can do .word end -
+ begin + val (gets val from stream) */
+ val = curfde->fde_end_symbol_offset -
+ curfde->fde_initloc;
+ WRITE_UNALIGNED(dbg, data,
+ (const void *) &val,
+ sizeof(val), upointer_size);
+ data += upointer_size;
+ } else {
+
+ du = curfde->fde_addr_range;
+ WRITE_UNALIGNED(dbg, (void *) data,
+ (const void *) &du,
+ sizeof(du), upointer_size);
+ data += upointer_size;
+ }
+ }
+
+ if (v0_augmentation) {
+ /* write the encoded augmented field length. */
+ memcpy((void *) data, (const void *) afl_buff, afl_length);
+ data += afl_length;
+ /* write the offset_into_exception_tables field. */
+ dsw =
+ (Dwarf_sfixed) curfde->fde_offset_into_exception_tables;
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &dsw,
+ sizeof(dsw), sizeof(Dwarf_sfixed));
+ data += sizeof(Dwarf_sfixed);
+ }
+
+ curinst = curfde->fde_inst;
+ if(curfde->fde_block) {
+ unsigned long size = curfde->fde_inst_block_size;
+ memcpy((void *) data, (const void *) curfde->fde_block, size);
+ data += size;
+ } else {
+ while (curinst) {
+ db = curinst->dfp_opcode;
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ data += sizeof(Dwarf_Ubyte);
+#if 0
+ if (curinst->dfp_sym_index) {
+ int res = dbg->de_reloc_name(dbg,
+ DEBUG_FRAME,
+ /* r_offset = */
+ (data - fde_start_point) + cur_off + uwordb_size,
+ curinst->dfp_sym_index,
+ dwarf_drt_data_reloc,
+ upointer_size);
+ if (res != DW_DLV_OK) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (0);
+ }
+ }
+#endif
+ memcpy((void *) data,
+ (const void *) curinst->dfp_args,
+ curinst->dfp_nbytes);
+ data += curinst->dfp_nbytes;
+ curinst = curinst->dfp_next;
+ }
+ }
+ /* padding */
+ for (i = 0; i < pad; i++) {
+ *data = DW_CFA_nop;
+ data++;
+ }
+ cur_off += fde_length + uwordb_size;
+ curfde = curfde->fde_next;
+ }
+
+
+ return (int) dbg->de_n_debug_sect;
+}
+
+/*
+ These functions remember all the markers we see along
+ with the right offset in the .debug_info section so that
+ we can dump them all back to the user with the section info.
+*/
+
+static int
+marker_init(Dwarf_P_Debug dbg,
+ unsigned count)
+{
+ dbg->de_marker_n_alloc = count;
+ dbg->de_markers = NULL;
+ if (count > 0) {
+ dbg->de_markers = _dwarf_p_get_alloc(dbg, sizeof(struct Dwarf_P_Marker_s) *
+ dbg->de_marker_n_alloc);
+ if (dbg->de_markers == NULL) {
+ dbg->de_marker_n_alloc = 0;
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int
+marker_add(Dwarf_P_Debug dbg,
+ Dwarf_Unsigned offset,
+ Dwarf_Unsigned marker)
+{
+ if (dbg->de_marker_n_alloc >= (dbg->de_marker_n_used + 1)) {
+ unsigned n = dbg->de_marker_n_used++;
+ dbg->de_markers[n].ma_offset = offset;
+ dbg->de_markers[n].ma_marker = marker;
+ return 0;
+ }
+
+ return -1;
+}
+
+Dwarf_Signed
+dwarf_get_die_markers(Dwarf_P_Debug dbg,
+ Dwarf_P_Marker * marker_list, /* pointer to a pointer */
+ Dwarf_Unsigned * marker_count,
+ Dwarf_Error * error)
+{
+ if (marker_list == NULL || marker_count == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_IA, DW_DLV_BADADDR);
+ }
+ if (dbg->de_marker_n_used != dbg->de_marker_n_alloc) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_MAF, DW_DLV_BADADDR);
+ }
+
+ *marker_list = dbg->de_markers;
+ *marker_count = dbg->de_marker_n_used;
+ return DW_DLV_OK;
+}
+
+/* These functions provide the offsets of DW_FORM_string
+ attributes in the section section_index. These information
+ will enable a producer app that is generating assembly
+ text output to easily emit those attributes in ascii form
+ without having to decode the byte stream.
+ */
+static int
+string_attr_init (Dwarf_P_Debug dbg,
+ Dwarf_Signed section_index,
+ unsigned count)
+{
+ Dwarf_P_Per_Sect_String_Attrs sect_sa = &dbg->de_sect_string_attr[section_index];
+
+ sect_sa->sect_sa_n_alloc = count;
+ sect_sa->sect_sa_list = NULL;
+ if (count > 0) {
+ sect_sa->sect_sa_section_number = section_index;
+ sect_sa->sect_sa_list = _dwarf_p_get_alloc(dbg,
+ sizeof(struct Dwarf_P_String_Attr_s)
+ * sect_sa->sect_sa_n_alloc);
+ if (sect_sa->sect_sa_list == NULL) {
+ sect_sa->sect_sa_n_alloc = 0;
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int
+string_attr_add (Dwarf_P_Debug dbg,
+ Dwarf_Signed section_index,
+ Dwarf_Unsigned offset,
+ Dwarf_P_Attribute attr)
+{
+ Dwarf_P_Per_Sect_String_Attrs sect_sa = &dbg->de_sect_string_attr[section_index];
+ if (sect_sa->sect_sa_n_alloc >= (sect_sa->sect_sa_n_used + 1)) {
+ unsigned n = sect_sa->sect_sa_n_used++;
+ sect_sa->sect_sa_list[n].sa_offset = offset;
+ sect_sa->sect_sa_list[n].sa_nbytes = attr->ar_nbytes;
+ return 0;
+ }
+
+ return -1;
+}
+
+int
+dwarf_get_string_attributes_count(Dwarf_P_Debug dbg,
+ Dwarf_Unsigned *
+ count_of_sa_sections,
+ int *drd_buffer_version,
+ Dwarf_Error *error)
+{
+ int i;
+ unsigned int count = 0;
+
+ for (i = 0; i < NUM_DEBUG_SECTIONS; ++i) {
+ if (dbg->de_sect_string_attr[i].sect_sa_n_used > 0) {
+ ++count;
+ }
+ }
+ *count_of_sa_sections = (Dwarf_Unsigned) count;
+ *drd_buffer_version = DWARF_DRD_BUFFER_VERSION;
+
+ return DW_DLV_OK;
+}
+
+int
+dwarf_get_string_attributes_info(Dwarf_P_Debug dbg,
+ Dwarf_Signed *elf_section_index,
+ Dwarf_Unsigned *sect_sa_buffer_count,
+ Dwarf_P_String_Attr *sect_sa_buffer,
+ Dwarf_Error *error)
+{
+ int i;
+ int next = dbg->de_sect_sa_next_to_return;
+
+ for (i = next; i < NUM_DEBUG_SECTIONS; ++i) {
+ Dwarf_P_Per_Sect_String_Attrs sect_sa = &dbg->de_sect_string_attr[i];
+ if (sect_sa->sect_sa_n_used > 0) {
+ dbg->de_sect_sa_next_to_return = i + 1;
+ *elf_section_index = sect_sa->sect_sa_section_number;
+ *sect_sa_buffer_count = sect_sa->sect_sa_n_used;
+ *sect_sa_buffer = sect_sa->sect_sa_list;
+ return DW_DLV_OK;
+ }
+ }
+ return DW_DLV_NO_ENTRY;
+}
+
+
+
+/*---------------------------------------------------------------
+ Generate debug_info and debug_abbrev sections
+---------------------------------------------------------------*/
+static int
+_dwarf_pro_generate_debuginfo(Dwarf_P_Debug dbg, Dwarf_Error * error)
+{
+ int elfsectno_of_debug_info = 0;
+ int abbrevsectno = 0;
+ unsigned char *data = 0;
+ int cu_header_size = 0;
+ Dwarf_P_Abbrev curabbrev = 0;
+ Dwarf_P_Abbrev abbrev_head = 0;
+ Dwarf_P_Abbrev abbrev_tail = 0;
+ Dwarf_P_Die curdie = 0;
+ Dwarf_P_Die first_child = 0;
+ Dwarf_Word dw = 0;
+ Dwarf_Unsigned du = 0;
+ Dwarf_Half dh = 0;
+ Dwarf_Ubyte db = 0;
+ Dwarf_Half version = 0; /* Need 2 byte quantity. */
+ Dwarf_Unsigned die_off = 0; /* Offset of die in debug_info. */
+ int n_abbrevs = 0;
+ int res = 0;
+ unsigned marker_count = 0;
+ unsigned string_attr_count = 0;
+ unsigned string_attr_offset = 0;
+
+ Dwarf_Small *start_info_sec = 0;
+
+ int uwordb_size = dbg->de_offset_size;
+ int extension_size = dbg->de_64bit_extension ? 4 : 0;
+
+ abbrev_head = abbrev_tail = NULL;
+ elfsectno_of_debug_info = dbg->de_elf_sects[DEBUG_INFO];
+
+ /* write cu header */
+ cu_header_size = BEGIN_LEN_SIZE + sizeof(Dwarf_Half) + /* version
+ stamp
+ */
+ uwordb_size + /* offset into abbrev table */
+ sizeof(Dwarf_Ubyte); /* size of target address */
+ GET_CHUNK(dbg, elfsectno_of_debug_info, data, cu_header_size,
+ error);
+ start_info_sec = data;
+ if (extension_size) {
+ du = DISTINGUISHED_VALUE;
+ WRITE_UNALIGNED(dbg, (void *) data,
+ (const void *) &du, sizeof(du), extension_size);
+ data += extension_size;
+ }
+ du = 0; /* length of debug_info, not counting
+ this field itself (unknown at this
+ point). */
+ WRITE_UNALIGNED(dbg, (void *) data,
+ (const void *) &du, sizeof(du), uwordb_size);
+ data += uwordb_size;
+
+ version = CURRENT_VERSION_STAMP; /* assume this length will not
+ change */
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &version,
+ sizeof(version), sizeof(Dwarf_Half));
+ data += sizeof(Dwarf_Half);
+
+ du = 0; /* offset into abbrev table, not yet
+ known. */
+ WRITE_UNALIGNED(dbg, (void *) data,
+ (const void *) &du, sizeof(du), uwordb_size);
+ data += uwordb_size;
+
+
+ db = dbg->de_pointer_size;
+
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db,
+ sizeof(db), 1);
+
+ /* We have filled the chunk we got with GET_CHUNK. At this point we
+ no longer dare use "data" or "start_info_sec" as a pointer any
+ longer except to refer to that first small chunk for the cu
+ header. */
+
+ curdie = dbg->de_dies;
+
+ /* create AT_macro_info if appropriate */
+ if (dbg->de_first_macinfo != NULL) {
+ if (_dwarf_pro_add_AT_macro_info(dbg, curdie, 0, error) < 0)
+ return -1;
+ }
+
+ /* create AT_stmt_list attribute if necessary */
+ if (dwarf_need_debug_line_section(dbg) == TRUE)
+ if (_dwarf_pro_add_AT_stmt_list(dbg, curdie, error) < 0)
+ return -1;
+
+ die_off = cu_header_size;
+
+ /*
+ Relocation for abbrev offset in cu header store relocation
+ record in linked list */
+ res = dbg->de_reloc_name(dbg, DEBUG_INFO, BEGIN_LEN_SIZE +
+ sizeof(Dwarf_Half),
+ /* r_offset */
+ dbg->de_sect_name_idx[DEBUG_ABBREV],
+ dwarf_drt_data_reloc, uwordb_size);
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_REL_ALLOC, -1);
+ }
+
+ /* pass 0: only top level dies, add at_sibling attribute to those
+ dies with children */
+ first_child = curdie->di_child;
+ while (first_child && first_child->di_right) {
+ if (first_child->di_child)
+ dwarf_add_AT_reference(dbg,
+ first_child,
+ DW_AT_sibling,
+ first_child->di_right, error);
+ first_child = first_child->di_right;
+ }
+
+ /* pass 1: create abbrev info, get die offsets, calc relocations */
+ marker_count = 0;
+ string_attr_count = 0;
+ while (curdie != NULL) {
+ int nbytes = 0;
+ Dwarf_P_Attribute curattr;
+ Dwarf_P_Attribute new_first_attr;
+ Dwarf_P_Attribute new_last_attr;
+ char *space = 0;
+ int res = 0;
+ char buff1[ENCODE_SPACE_NEEDED];
+ int i = 0;
+
+ curdie->di_offset = die_off;
+
+ if (curdie->di_marker != 0)
+ marker_count++;
+
+ curabbrev = _dwarf_pro_getabbrev(curdie, abbrev_head);
+ if (curabbrev == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_ABBREV_ALLOC, -1);
+ }
+ if (abbrev_head == NULL) {
+ n_abbrevs = 1;
+ curabbrev->abb_idx = n_abbrevs;
+ abbrev_tail = abbrev_head = curabbrev;
+ } else {
+ /* check if its a new abbreviation, if yes, add to tail */
+ if (curabbrev->abb_idx == 0) {
+ n_abbrevs++;
+ curabbrev->abb_idx = n_abbrevs;
+ abbrev_tail->abb_next = curabbrev;
+ abbrev_tail = curabbrev;
+ }
+ }
+ res = _dwarf_pro_encode_leb128_nm(curabbrev->abb_idx,
+ &nbytes,
+ buff1, sizeof(buff1));
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_ABBREV_ALLOC, -1);
+ }
+ space = _dwarf_p_get_alloc(dbg, nbytes);
+ if (space == NULL) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_ABBREV_ALLOC, -1);
+ }
+ memcpy(space, buff1, nbytes);
+ curdie->di_abbrev = space;
+ curdie->di_abbrev_nbytes = nbytes;
+ die_off += nbytes;
+
+ /* Resorting the attributes!! */
+ new_first_attr = new_last_attr = NULL;
+ curattr = curdie->di_attrs;
+ for (i = 0; i < (int)curabbrev->abb_n_attr; i++) {
+ Dwarf_P_Attribute ca;
+ Dwarf_P_Attribute cl;
+
+ /* The following should always find an attribute! */
+ for (ca = cl = curattr;
+ ca && curabbrev->abb_attrs[i] != ca->ar_attribute;
+ cl = ca, ca = ca->ar_next)
+ {
+ }
+
+ if (!ca) {
+ DWARF_P_DBG_ERROR(dbg,DW_DLE_ABBREV_ALLOC, -1);
+ }
+
+ /* Remove the attribute from the old list. */
+ if (ca == curattr) {
+ curattr = ca->ar_next;
+ } else {
+ cl->ar_next = ca->ar_next;
+ }
+
+ ca->ar_next = NULL;
+
+ /* Add the attribute to the new list. */
+ if (new_first_attr == NULL) {
+ new_first_attr = new_last_attr = ca;
+ } else {
+ new_last_attr->ar_next = ca;
+ new_last_attr = ca;
+ }
+ }
+
+ curdie->di_attrs = new_first_attr;
+
+ curattr = curdie->di_attrs;
+
+ while (curattr) {
+ if (curattr->ar_rel_type != R_MIPS_NONE) {
+ switch (curattr->ar_attribute) {
+ case DW_AT_stmt_list:
+ curattr->ar_rel_symidx =
+ dbg->de_sect_name_idx[DEBUG_LINE];
+ break;
+ case DW_AT_MIPS_fde:
+ curattr->ar_rel_symidx =
+ dbg->de_sect_name_idx[DEBUG_FRAME];
+ break;
+ case DW_AT_macro_info:
+ curattr->ar_rel_symidx =
+ dbg->de_sect_name_idx[DEBUG_MACINFO];
+ break;
+ default:
+ break;
+ }
+ res = dbg->de_reloc_name(dbg, DEBUG_INFO, die_off + curattr->ar_rel_offset, /* r_offset
+ */
+ curattr->ar_rel_symidx,
+ dwarf_drt_data_reloc,
+ curattr->ar_reloc_len);
+
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_REL_ALLOC, -1);
+ }
+
+ }
+ if (curattr->ar_attribute_form == DW_FORM_string) {
+ string_attr_count++;
+ }
+ die_off += curattr->ar_nbytes;
+ curattr = curattr->ar_next;
+ }
+
+ /* depth first search */
+ if (curdie->di_child)
+ curdie = curdie->di_child;
+ else {
+ while (curdie != NULL && curdie->di_right == NULL) {
+ curdie = curdie->di_parent;
+ die_off++; /* since we are writing a null die at
+ the end of each sibling chain */
+ }
+ if (curdie != NULL)
+ curdie = curdie->di_right;
+ }
+
+ } /* end while (curdie != NULL) */
+
+ res = marker_init(dbg, marker_count);
+ if (res == -1) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_REL_ALLOC, -1);
+ }
+ res = string_attr_init(dbg, DEBUG_INFO, string_attr_count);
+ if (res == -1) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_REL_ALLOC, -1);
+ }
+
+ /* Pass 2: Write out the die information Here 'data' is a
+ temporary, one block for each GET_CHUNK. 'data' is overused. */
+ curdie = dbg->de_dies;
+ while (curdie != NULL) {
+ Dwarf_P_Attribute curattr;
+
+ if (curdie->di_marker != 0) {
+ res = marker_add(dbg, curdie->di_offset, curdie->di_marker);
+ if (res == -1) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_REL_ALLOC, -1);
+ }
+ }
+
+ /* index to abbreviation table */
+ GET_CHUNK(dbg, elfsectno_of_debug_info,
+ data, curdie->di_abbrev_nbytes, error);
+
+ memcpy((void *) data,
+ (const void *) curdie->di_abbrev,
+ curdie->di_abbrev_nbytes);
+
+ /* Attribute values - need to fill in all form attributes */
+ curattr = curdie->di_attrs;
+ string_attr_offset = curdie->di_offset + curdie->di_abbrev_nbytes;
+
+ while (curattr) {
+ GET_CHUNK(dbg, elfsectno_of_debug_info, data,
+ (unsigned long) curattr->ar_nbytes, error);
+ switch (curattr->ar_attribute_form) {
+ case DW_FORM_ref1:
+ {
+ if (curattr->ar_ref_die->di_offset >
+ (unsigned) 0xff) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_OFFSET_UFLW, -1);
+ }
+ db = curattr->ar_ref_die->di_offset;
+ WRITE_UNALIGNED(dbg, (void *) data,
+ (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+ break;
+ }
+ case DW_FORM_ref2:
+ {
+ if (curattr->ar_ref_die->di_offset >
+ (unsigned) 0xffff) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_OFFSET_UFLW, -1);
+ }
+ dh = curattr->ar_ref_die->di_offset;
+ WRITE_UNALIGNED(dbg, (void *) data,
+ (const void *) &dh,
+ sizeof(dh), sizeof(Dwarf_Half));
+ break;
+ }
+ case DW_FORM_ref_addr:
+ {
+ /* curattr->ar_ref_die == NULL!
+ *
+ * ref_addr doesn't take a CU-offset.
+ * This is different than other refs.
+ * This value will be set by the user of the
+ * producer library using a relocation.
+ * No need to set a value here.
+ */
+#if 0
+ du = curattr->ar_ref_die->di_offset;
+ {
+ /* ref to offset of die */
+ WRITE_UNALIGNED(dbg, (void *) data,
+ (const void *) &du,
+ sizeof(du), uwordb_size);
+ }
+#endif
+ break;
+
+ }
+ case DW_FORM_ref4:
+ {
+ if (curattr->ar_ref_die->di_offset >
+ (unsigned) 0xffffffff) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_OFFSET_UFLW, -1);
+ }
+ dw = (Dwarf_Word) curattr->ar_ref_die->di_offset;
+ WRITE_UNALIGNED(dbg, (void *) data,
+ (const void *) &dw,
+ sizeof(dw), sizeof(Dwarf_ufixed));
+ break;
+ }
+ case DW_FORM_ref8:
+ du = curattr->ar_ref_die->di_offset;
+ WRITE_UNALIGNED(dbg, (void *) data,
+ (const void *) &du,
+ sizeof(du), sizeof(Dwarf_Unsigned));
+ break;
+ case DW_FORM_ref_udata:
+ { /* unsigned leb128 offset */
+
+ int nbytes;
+ char buff1[ENCODE_SPACE_NEEDED];
+
+ res =
+ _dwarf_pro_encode_leb128_nm(curattr->
+ ar_ref_die->
+ di_offset, &nbytes,
+ buff1,
+ sizeof(buff1));
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_ABBREV_ALLOC, -1);
+ }
+
+ memcpy(data, buff1, nbytes);
+ break;
+ }
+ default:
+ memcpy((void *) data,
+ (const void *) curattr->ar_data,
+ curattr->ar_nbytes);
+ break;
+ }
+ if (curattr->ar_attribute_form == DW_FORM_string) {
+ string_attr_add(dbg, DEBUG_INFO, string_attr_offset, curattr);
+ }
+ string_attr_offset += curattr->ar_nbytes;
+ curattr = curattr->ar_next;
+ }
+
+ /* depth first search */
+ if (curdie->di_child)
+ curdie = curdie->di_child;
+ else {
+ while (curdie != NULL && curdie->di_right == NULL) {
+ GET_CHUNK(dbg, elfsectno_of_debug_info, data, 1, error);
+ *data = '\0';
+ curdie = curdie->di_parent;
+ }
+ if (curdie != NULL)
+ curdie = curdie->di_right;
+ }
+ } /* end while (curdir != NULL) */
+
+ /* Write out debug_info size */
+ /* Dont include length field or extension bytes */
+ du = die_off - BEGIN_LEN_SIZE;
+ WRITE_UNALIGNED(dbg, (void *) (start_info_sec + extension_size),
+ (const void *) &du, sizeof(du), uwordb_size);
+
+
+ data = 0; /* Emphasise not usable now */
+
+ /* Write out debug_abbrev section */
+ abbrevsectno = dbg->de_elf_sects[DEBUG_ABBREV];
+
+ curabbrev = abbrev_head;
+ while (curabbrev) {
+ char *val;
+ int nbytes;
+ int idx;
+ int res;
+ char buff1[ENCODE_SPACE_NEEDED];
+
+ res = _dwarf_pro_encode_leb128_nm(curabbrev->abb_idx, &nbytes,
+ buff1, sizeof(buff1));
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_ABBREV_ALLOC, -1);
+ }
+
+ GET_CHUNK(dbg, abbrevsectno, data, nbytes, error);
+ val = buff1;
+ memcpy((void *) data, (const void *) val, nbytes);
+ res = _dwarf_pro_encode_leb128_nm(curabbrev->abb_tag, &nbytes,
+ buff1, sizeof(buff1));
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_ABBREV_ALLOC, -1);
+ }
+ val = buff1;
+ GET_CHUNK(dbg, abbrevsectno, data, nbytes, error);
+ memcpy((void *) data, (const void *) val, nbytes);
+ db = curabbrev->abb_children;
+ GET_CHUNK(dbg, abbrevsectno, data, sizeof(Dwarf_Ubyte), error);
+ WRITE_UNALIGNED(dbg, (void *) data, (const void *) &db,
+ sizeof(db), sizeof(Dwarf_Ubyte));
+
+ /* add attributes and forms */
+ for (idx = 0; idx < curabbrev->abb_n_attr; idx++) {
+ res = _dwarf_pro_encode_leb128_nm(curabbrev->abb_attrs[idx],
+ &nbytes,
+ buff1, sizeof(buff1));
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_ABBREV_ALLOC, -1);
+ }
+ val = buff1;
+ GET_CHUNK(dbg, abbrevsectno, data, nbytes, error);
+ memcpy((void *) data, (const void *) val, nbytes);
+ res = _dwarf_pro_encode_leb128_nm(curabbrev->abb_forms[idx],
+ &nbytes,
+ buff1, sizeof(buff1));
+ if (res != DW_DLV_OK) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_ABBREV_ALLOC, -1);
+ }
+ val = buff1;
+ GET_CHUNK(dbg, abbrevsectno, data, nbytes, error);
+ memcpy((void *) data, (const void *) val, nbytes);
+ }
+ GET_CHUNK(dbg, abbrevsectno, data, 2, error); /* two zeros,
+ for last
+ entry, see
+ dwarf2 sec
+ 7.5.3 */
+ *data = 0;
+ data++;
+ *data = 0;
+
+ curabbrev = curabbrev->abb_next;
+ }
+
+ GET_CHUNK(dbg, abbrevsectno, data, 1, error); /* one zero,
+ for end of
+ cu, see
+ dwarf2 sec
+ 7.5.3 */
+ *data = 0;
+
+
+ return (int) dbg->de_n_debug_sect;
+}
+
+
+/*---------------------------------------------------------------------
+ Get a buffer of section data.
+ section_idx is the elf-section number that this data applies to.
+ length shows length of returned data
+----------------------------------------------------------------------*/
+ /*ARGSUSED*/ /* pretend all args used */
+ Dwarf_Ptr
+dwarf_get_section_bytes(Dwarf_P_Debug dbg,
+ Dwarf_Signed dwarf_section,
+ Dwarf_Signed * section_idx,
+ Dwarf_Unsigned * length, Dwarf_Error * error)
+{
+ Dwarf_Ptr buf;
+
+ if (dbg->de_version_magic_number != PRO_VERSION_MAGIC) {
+ DWARF_P_DBG_ERROR(dbg, DW_DLE_IA, NULL);
+ }
+
+ if (dbg->de_debug_sects == 0) {
+ /* no more data !! */
+ return NULL;
+ }
+ if (dbg->de_debug_sects->ds_elf_sect_no == MAGIC_SECT_NO) {
+ /* no data ever entered !! */
+ return NULL;
+ }
+ *section_idx = dbg->de_debug_sects->ds_elf_sect_no;
+ *length = dbg->de_debug_sects->ds_nbytes;
+
+ buf = (Dwarf_Ptr *) dbg->de_debug_sects->ds_data;
+
+ dbg->de_debug_sects = dbg->de_debug_sects->ds_next;
+
+ /* We may want to call the section stuff more than once: see
+ dwarf_reset_section_bytes() do not do: dbg->de_n_debug_sect--; */
+
+ return buf;
+}
+
+/*
+ No errors possible.
+*/
+void
+dwarf_reset_section_bytes(Dwarf_P_Debug dbg)
+{
+ dbg->de_debug_sects = dbg->de_first_debug_sect;
+ /* No need to reset; commented out decrement. dbg->de_n_debug_sect
+ = ???; */
+ dbg->de_reloc_next_to_return = 0;
+ dbg->de_sect_sa_next_to_return = 0;
+}
+
+/*
+ Storage handler. Gets either a new chunk of memory, or
+ a pointer in existing memory, from the linked list attached
+ to dbg at de_debug_sects, depending on size of nbytes
+
+ Assume dbg not null, checked in top level routine
+
+ Returns a pointer to the allocated buffer space for the
+ lib to fill in, predincrements next-to-use count so the
+ space requested is already counted 'used'
+ when this returns (ie, reserved).
+
+*/
+Dwarf_Small *
+_dwarf_pro_buffer(Dwarf_P_Debug dbg,
+ int elfsectno, unsigned long nbytes)
+{
+ Dwarf_P_Section_Data cursect;
+
+
+ cursect = dbg->de_current_active_section;
+ /* By using MAGIC_SECT_NO we allow the following MAGIC_SECT_NO must
+ not match any legit section number. test to have just two
+ clauses (no NULL pointer test) See dwarf_producer_init(). */
+ if ((cursect->ds_elf_sect_no != elfsectno) ||
+ ((cursect->ds_nbytes + nbytes) > cursect->ds_orig_alloc)
+ ) {
+
+ /* Either the elf section has changed or there is not enough
+ space in the current section.
+
+ Create a new Dwarf_P_Section_Data_s for the chunk. and have
+ space 'on the end' for the buffer itself so we just do one
+ malloc (not two).
+
+ */
+ unsigned long space = nbytes;
+
+ if (nbytes < CHUNK_SIZE)
+ space = CHUNK_SIZE;
+
+ cursect = (Dwarf_P_Section_Data)
+ _dwarf_p_get_alloc(dbg,
+ sizeof(struct Dwarf_P_Section_Data_s)
+ + space);
+
+
+ if (cursect == NULL)
+ return (NULL);
+
+ /* _dwarf_p_get_alloc zeroes the space... */
+
+ cursect->ds_data = (char *) cursect +
+ sizeof(struct Dwarf_P_Section_Data_s);
+ cursect->ds_orig_alloc = space;
+ cursect->ds_elf_sect_no = elfsectno;
+ cursect->ds_nbytes = nbytes; /* reserve this number of bytes
+ of space for caller to fill
+ in */
+
+ /* Now link on the end of the list, and mark this one as the
+ current one */
+
+ if (dbg->de_debug_sects->ds_elf_sect_no == MAGIC_SECT_NO) {
+ /* the only entry is the special one for 'no entry' so
+ delete that phony one while adding this initial real
+ one. */
+ dbg->de_debug_sects = cursect;
+ dbg->de_current_active_section = cursect;
+ dbg->de_first_debug_sect = cursect;
+ } else {
+ dbg->de_current_active_section->ds_next = cursect;
+ dbg->de_current_active_section = cursect;
+ }
+ dbg->de_n_debug_sect++;
+
+ return ((Dwarf_Small *) cursect->ds_data);
+ }
+
+ /* There is enough space in the current buffer */
+ {
+ Dwarf_Small *space_for_caller = (Dwarf_Small *)
+ (cursect->ds_data + cursect->ds_nbytes);
+
+ cursect->ds_nbytes += nbytes;
+ return space_for_caller;
+ }
+}
+
+
+/*------------------------------------------------------------
+ Given address advance and line advance, it gives
+ either special opcode, or a number < 0
+------------------------------------------------------------*/
+static int
+_dwarf_pro_get_opc(Dwarf_Unsigned addr_adv, int line_adv)
+{
+ int opc;
+
+ addr_adv = addr_adv / MIN_INST_LENGTH;
+ if (line_adv == 0 && addr_adv == 0)
+ return OPC_INCS_ZERO;
+ if (line_adv >= LINE_BASE && line_adv < LINE_BASE + LINE_RANGE) {
+ opc =
+ (line_adv - LINE_BASE) + (addr_adv * LINE_RANGE) +
+ OPCODE_BASE;
+ if (opc > 255)
+ return OPC_OUT_OF_RANGE;
+ return opc;
+ } else
+ return LINE_OUT_OF_RANGE;
+}
+
+/*-----------------------------------------------------------------------
+ Handles abbreviations. It takes a die, searches through
+ current list of abbreviations for matching one. If it
+ finds one, it returns a pointer to it, and if it doesnt,
+ it returns a new one. Upto the user of this function to
+ link it up to the abbreviation head. If its a new one,
+ abb_idx has 0.
+-----------------------------------------------------------------------*/
+static Dwarf_P_Abbrev
+_dwarf_pro_getabbrev(Dwarf_P_Die die, Dwarf_P_Abbrev head)
+{
+ Dwarf_P_Abbrev curabbrev;
+ Dwarf_P_Attribute curattr;
+ int res1;
+ int nattrs;
+ int match;
+ Dwarf_ufixed *forms = 0;
+ Dwarf_ufixed *attrs = 0;
+
+ curabbrev = head;
+ while (curabbrev) {
+ if ((die->di_tag == curabbrev->abb_tag) &&
+ ((die->di_child != NULL &&
+ curabbrev->abb_children == DW_CHILDREN_yes) ||
+ (die->di_child == NULL &&
+ curabbrev->abb_children == DW_CHILDREN_no)) &&
+ (die->di_n_attr == curabbrev->abb_n_attr)) {
+
+ /* There is a chance of a match. */
+ curattr = die->di_attrs;
+ match = 1; /* Assume match found. */
+ while (match && curattr) {
+ res1 = _dwarf_pro_match_attr(curattr,
+ curabbrev,
+ (int) curabbrev->
+ abb_n_attr);
+ if (res1 == 0)
+ match = 0;
+ curattr = curattr->ar_next;
+ }
+ if (match == 1)
+ return curabbrev;
+ }
+ curabbrev = curabbrev->abb_next;
+ }
+
+ /* no match, create new abbreviation */
+ if (die->di_n_attr != 0) {
+ forms = (Dwarf_ufixed *)
+ _dwarf_p_get_alloc(die->di_dbg,
+ sizeof(Dwarf_ufixed) * die->di_n_attr);
+ if (forms == NULL)
+ return NULL;
+ attrs = (Dwarf_ufixed *)
+ _dwarf_p_get_alloc(die->di_dbg,
+ sizeof(Dwarf_ufixed) * die->di_n_attr);
+ if (attrs == NULL)
+ return NULL;
+ }
+ nattrs = 0;
+ curattr = die->di_attrs;
+ while (curattr) {
+ attrs[nattrs] = curattr->ar_attribute;
+ forms[nattrs] = curattr->ar_attribute_form;
+ nattrs++;
+ curattr = curattr->ar_next;
+ }
+
+ curabbrev = (Dwarf_P_Abbrev)
+ _dwarf_p_get_alloc(die->di_dbg, sizeof(struct Dwarf_P_Abbrev_s));
+ if (curabbrev == NULL)
+ return NULL;
+
+ if (die->di_child == NULL)
+ curabbrev->abb_children = DW_CHILDREN_no;
+ else
+ curabbrev->abb_children = DW_CHILDREN_yes;
+ curabbrev->abb_tag = die->di_tag;
+ curabbrev->abb_attrs = attrs;
+ curabbrev->abb_forms = forms;
+ curabbrev->abb_n_attr = die->di_n_attr;
+ curabbrev->abb_idx = 0;
+ curabbrev->abb_next = NULL;
+
+ return curabbrev;
+}
+
+/*------------------------------------------------------------------
+ Tries to see if given attribute and form combination
+ exists in the given abbreviation
+-------------------------------------------------------------------*/
+static int
+_dwarf_pro_match_attr(Dwarf_P_Attribute attr,
+ Dwarf_P_Abbrev abbrev, int no_attr)
+{
+ int i;
+ int found = 0;
+
+ for (i = 0; i < no_attr; i++) {
+ if (attr->ar_attribute == abbrev->abb_attrs[i] &&
+ attr->ar_attribute_form == abbrev->abb_forms[i]) {
+ found = 1;
+ break;
+ }
+ }
+ return found;
+}
diff --git a/usr/src/lib/libdwarf/common/pro_section.h b/usr/src/lib/libdwarf/common/pro_section.h
new file mode 100644
index 0000000000..b37ade44dc
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_section.h
@@ -0,0 +1,112 @@
+/*
+
+ Copyright (C) 2000,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
+
+*/
+
+
+
+
+
+/* relocation section names */
+extern char *_dwarf_rel_section_names[];
+
+/* section names */
+extern char *_dwarf_sectnames[];
+
+/* struct to hold relocation entries. Its mantained as a linked
+ list of relocation structs, and will then be written at as a
+ whole into the relocation section. Whether its 32 bit or
+ 64 bit will be obtained from Dwarf_Debug pointer.
+*/
+
+
+
+
+
+/*
+ struct stores a chunk of data pertaining to a section
+*/
+struct Dwarf_P_Section_Data_s {
+ int ds_elf_sect_no; /* elf section number */
+ char *ds_data; /* data contained in section */
+ unsigned long ds_nbytes; /* bytes of data used so far */
+ unsigned long ds_orig_alloc; /* bytes allocated originally */
+ Dwarf_P_Section_Data ds_next; /* next on the list */
+};
+
+/* Used to allow a dummy initial struct (which we
+ drop before it gets used
+ This must not match any legitimate 'section' number.
+*/
+#define MAGIC_SECT_NO -3
+
+/* Size of chunk of data allocated in one alloc
+ Not clear if this is the best size.
+ Used to be just 4096 for user data, the section data struct
+ was a separate malloc.
+*/
+#define CHUNK_SIZE (4096 - sizeof (struct Dwarf_P_Section_Data_s))
+
+/*
+ chunk alloc routine -
+ if chunk->ds_data is nil, it will alloc CHUNK_SIZE bytes,
+ and return pointer to the beginning. If chunk is not nil,
+ it will see if there's enoungh space for nbytes in current
+ chunk, if not, add new chunk to linked list, and return
+ a char * pointer to it. Return null if unsuccessful.
+*/
+Dwarf_Small *_dwarf_pro_buffer(Dwarf_P_Debug dbg, int sectno,
+ unsigned long nbytes);
+
+#define GET_CHUNK(dbg,sectno,ptr,nbytes,error) \
+ { \
+ (ptr) = _dwarf_pro_buffer((dbg),(sectno),(nbytes)); \
+ if ((ptr) == NULL) { \
+ DWARF_P_DBG_ERROR(dbg,DW_DLE_CHUNK_ALLOC,-1); \
+ } \
+ }
+
+
+
+int
+ _dwarf_transform_arange_to_disk(Dwarf_P_Debug dbg,
+ Dwarf_Error * error);
+
+/* These are for creating ELF section type codes.
+*/
+#if defined(linux) || defined(__BEOS__) || !defined(SHT_MIPS_DWARF)
+/* Intel's SoftSdv accepts only this */
+#define SECTION_TYPE SHT_PROGBITS
+#else
+#define SECTION_TYPE SHT_MIPS_DWARF
+#endif
diff --git a/usr/src/lib/libdwarf/common/pro_types.c b/usr/src/lib/libdwarf/common/pro_types.c
new file mode 100644
index 0000000000..1f3f93280c
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_types.c
@@ -0,0 +1,296 @@
+/*
+
+ Copyright (C) 2000,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
+
+*/
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_ELFACCESS_H
+#include <elfaccess.h>
+#endif
+#include "pro_incl.h"
+#include "pro_section.h"
+
+
+/*
+ This function adds another type name to the
+ list of type names for the given Dwarf_P_Debug.
+ It returns 0 on error, and 1 otherwise.
+*/
+Dwarf_Unsigned
+dwarf_add_typename(Dwarf_P_Debug dbg,
+ Dwarf_P_Die die,
+ char *type_name, Dwarf_Error * error)
+{
+ return
+ _dwarf_add_simple_name_entry(dbg, die, type_name,
+ dwarf_snk_typename, error);
+}
+
+/*
+ The following is the generic 'add a simple name entry'
+ for any of the simple name sections.
+
+ See enum dwarf_sn_kind in pro_opaque.h
+
+*/
+Dwarf_Unsigned
+_dwarf_add_simple_name_entry(Dwarf_P_Debug dbg,
+ Dwarf_P_Die die,
+ char *entry_name,
+ enum dwarf_sn_kind entrykind,
+ Dwarf_Error * error)
+{
+ Dwarf_P_Simple_nameentry nameentry;
+ Dwarf_P_Simple_name_header hdr;
+ char *name;
+ int uword_size;
+
+ if (dbg == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DBG_NULL);
+ return (0);
+ }
+
+ if (die == NULL) {
+ _dwarf_p_error(NULL, error, DW_DLE_DIE_NULL);
+ return (0);
+ }
+
+
+ nameentry = (Dwarf_P_Simple_nameentry)
+ _dwarf_p_get_alloc(dbg,
+ sizeof(struct Dwarf_P_Simple_nameentry_s));
+ if (nameentry == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (0);
+ }
+
+ name = _dwarf_p_get_alloc(dbg, strlen(entry_name) + 1);
+ if (name == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (0);
+ }
+ strcpy(name, entry_name);
+
+ nameentry->sne_die = die;
+ nameentry->sne_name = name;
+ nameentry->sne_name_len = strlen(name);
+ uword_size = dbg->de_offset_size;
+
+ hdr = &dbg->de_simple_name_headers[entrykind];
+ if (hdr->sn_head == NULL)
+ hdr->sn_head = hdr->sn_tail = nameentry;
+ else {
+ hdr->sn_tail->sne_next = nameentry;
+ hdr->sn_tail = nameentry;
+ }
+ hdr->sn_count++;
+ hdr->sn_net_len += uword_size + nameentry->sne_name_len + 1;
+
+ return (1);
+}
+
+
+
+/*
+ _dwarf_transform_simplename_to_disk writes
+ ".rel.debug_pubnames",
+ ".rel.debug_funcnames", sgi extension
+ ".rel.debug_typenames", sgi extension
+ ".rel.debug_varnames", sgi extension
+ ".rel.debug_weaknames", sgi extension
+ to disk.
+ section_index indexes one of those sections.
+ entrykind is one of those 'kind's.
+
+*/
+int
+_dwarf_transform_simplename_to_disk(Dwarf_P_Debug dbg, enum dwarf_sn_kind entrykind, int section_index, /* in
+ de_elf_sects
+ etc
+ */
+ Dwarf_Error * error)
+{
+
+
+ /* Used to fill in 0. */
+ const Dwarf_Signed big_zero = 0;
+
+ /* Used to scan the section data buffers. */
+ Dwarf_P_Section_Data debug_sect;
+
+ Dwarf_Signed debug_info_size;
+
+ Dwarf_P_Simple_nameentry nameentry_original;
+ Dwarf_P_Simple_nameentry nameentry;
+ Dwarf_Small *stream_bytes;
+ Dwarf_Small *cur_stream_bytes_ptr;
+ Dwarf_Unsigned stream_bytes_count;
+ Dwarf_Unsigned adjusted_length; /* count excluding length field
+ */
+
+
+ int uword_size = dbg->de_offset_size;
+ int extension_size = dbg->de_64bit_extension ? 4 : 0;
+
+ Dwarf_P_Simple_name_header hdr;
+
+
+ /* ***** BEGIN CODE ***** */
+
+ debug_info_size = 0;
+ for (debug_sect = dbg->de_debug_sects; debug_sect != NULL;
+ debug_sect = debug_sect->ds_next) {
+ /* We want the size of the .debug_info section for this CU
+ because the dwarf spec requires us to output it below so we
+ look for it specifically. */
+ if (debug_sect->ds_elf_sect_no == dbg->de_elf_sects[DEBUG_INFO]) {
+ debug_info_size += debug_sect->ds_nbytes;
+ }
+ }
+
+ hdr = &dbg->de_simple_name_headers[entrykind];
+ /* Size of the .debug_typenames (or similar) section header. */
+ stream_bytes_count = extension_size + uword_size + /* Size of
+ length
+ field. */
+ sizeof(Dwarf_Half) + /* Size of version field. */
+ uword_size + /* Size of .debug_info offset. */
+ uword_size; /* Size of .debug_names. */
+
+
+
+ nameentry_original = hdr->sn_head;
+ nameentry = nameentry_original;
+ /* add in the content size */
+ stream_bytes_count += hdr->sn_net_len;
+
+ /* Size of the last 0 offset. */
+ stream_bytes_count += uword_size;
+
+ /* Now we know how long the entire section is */
+ GET_CHUNK(dbg, dbg->de_elf_sects[section_index],
+ stream_bytes, (unsigned long) stream_bytes_count, error);
+ if (stream_bytes == NULL) {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (0);
+ }
+ cur_stream_bytes_ptr = stream_bytes;
+
+ if (extension_size) {
+ Dwarf_Unsigned x = DISTINGUISHED_VALUE;
+
+ WRITE_UNALIGNED(dbg, cur_stream_bytes_ptr,
+ (const void *) &x, sizeof(x), extension_size);
+ cur_stream_bytes_ptr += extension_size;
+
+ }
+ /* Write the adjusted length of .debug_*names section. */
+ adjusted_length = stream_bytes_count - uword_size - extension_size;
+ WRITE_UNALIGNED(dbg, cur_stream_bytes_ptr,
+ (const void *) &adjusted_length,
+ sizeof(adjusted_length), uword_size);
+ cur_stream_bytes_ptr += uword_size;
+
+ /* Write the version as 2 bytes. */
+ {
+ Dwarf_Half verstamp = CURRENT_VERSION_STAMP;
+
+ WRITE_UNALIGNED(dbg, cur_stream_bytes_ptr,
+ (const void *) &verstamp,
+ sizeof(verstamp), sizeof(Dwarf_Half));
+ cur_stream_bytes_ptr += sizeof(Dwarf_Half);
+ }
+
+ /* Write the offset of the compile-unit. */
+ WRITE_UNALIGNED(dbg, cur_stream_bytes_ptr,
+ (const void *) &big_zero,
+ sizeof(big_zero), uword_size);
+ cur_stream_bytes_ptr += uword_size;
+
+ /* now create the relocation for the compile_unit offset */
+ {
+ int res = dbg->de_reloc_name(dbg,
+ section_index,
+ extension_size + uword_size +
+ sizeof(Dwarf_Half)
+ /* r_offset */
+ ,
+ /* debug_info section name symbol */
+ dbg->de_sect_name_idx[DEBUG_INFO],
+ dwarf_drt_data_reloc,
+ uword_size);
+
+ if (res != DW_DLV_OK) {
+ {
+ _dwarf_p_error(dbg, error, DW_DLE_ALLOC_FAIL);
+ return (0);
+ }
+ }
+ }
+
+ /* Write the size of .debug_info section. */
+ WRITE_UNALIGNED(dbg, cur_stream_bytes_ptr,
+ (const void *) &debug_info_size,
+ sizeof(debug_info_size), uword_size);
+ cur_stream_bytes_ptr += uword_size;
+
+
+ for (nameentry = nameentry_original;
+ nameentry != NULL; nameentry = nameentry->sne_next) {
+
+ /* Copy offset of die from start of compile-unit. */
+ WRITE_UNALIGNED(dbg, cur_stream_bytes_ptr,
+ (const void *) &nameentry->sne_die->di_offset,
+ sizeof(nameentry->sne_die->di_offset),
+ uword_size);
+ cur_stream_bytes_ptr += uword_size;
+
+ /* Copy the type name. */
+ strcpy((char *) cur_stream_bytes_ptr, nameentry->sne_name);
+ cur_stream_bytes_ptr += nameentry->sne_name_len + 1;
+ }
+
+ WRITE_UNALIGNED(dbg, cur_stream_bytes_ptr,
+ (const void *) &big_zero,
+ sizeof(big_zero), uword_size);
+
+
+
+
+ return (int) dbg->de_n_debug_sect;
+}
diff --git a/usr/src/lib/libdwarf/common/pro_types.h b/usr/src/lib/libdwarf/common/pro_types.h
new file mode 100644
index 0000000000..817609215b
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_types.h
@@ -0,0 +1,44 @@
+/*
+
+ Copyright (C) 2000,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
+
+*/
+
+
+/* pro_types.h */
+
+
+int _dwarf_transform_simplename_to_disk(Dwarf_P_Debug dbg, enum dwarf_sn_kind entrykind, int section_index, /* in
+ de_elf_sects
+ etc
+ */
+ Dwarf_Error * error);
diff --git a/usr/src/lib/libdwarf/common/pro_util.h b/usr/src/lib/libdwarf/common/pro_util.h
new file mode 100644
index 0000000000..56bde8bda6
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_util.h
@@ -0,0 +1,148 @@
+/*
+
+ Copyright (C) 2000,2004 Silicon Graphics, Inc. All Rights Reserved.
+ Portions Copyright 2002-2010 Sun Microsystems, 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
+
+*/
+
+
+
+
+#define IS_64BIT(dbg) ((dbg)->de_flags & DW_DLC_SIZE_64 ? 1 : 0)
+#define ISA_IA64(dbg) ((dbg)->de_flags & DW_DLC_ISA_IA64 ? 1 : 0)
+
+/* definition of sizes of types, given target machine */
+#define sizeof_sbyte(dbg) sizeof(Dwarf_Sbyte)
+#define sizeof_ubyte(dbg) sizeof(Dwarf_Ubyte)
+#define sizeof_uhalf(dbg) sizeof(Dwarf_Half)
+/* certain sizes not defined here, but set in dbg record.
+ See pro_init.c
+*/
+
+/* Computes amount of padding necessary to align n to a k-boundary. */
+/* Important: Assumes n, k both GREATER than zero. */
+#define PADDING(n, k) ( (k)-1 - ((n)-1)%(k) )
+
+/* The following defines are only important for users of the
+** producer part of libdwarf, and such should have these
+** defined correctly (as necessary)
+** by the #include <elf.h> done in pro_incl.h
+** before the #include "pro_util.h".
+** For others producer macros do not matter so 0 is a usable value, and
+** zero values let compilation succeed on more non-MIPS architectures.
+** A better approach would be welcome.
+*/
+/* R_MIPS* are #define so #ifndef works */
+/* R_IA_64* are not necessarily #define (might be enum) so #ifndef
+ is useless, we use the configure script generating
+ HAVE_R_IA_64_DIR32LSB and HAVE_R_IA64_DIR32LSB.
+*/
+#ifndef R_MIPS_64
+#define R_MIPS_64 0
+#endif
+#ifndef R_MIPS_32
+#define R_MIPS_32 0
+#endif
+#ifndef R_MIPS_SCN_DISP
+#define R_MIPS_SCN_DISP 0
+#endif
+
+/* R_IA_64_DIR32LSB came before the now-standard R_IA64_DIR32LSB
+ (etc) was defined. This now deals with either form,
+ preferring the new form if available. */
+#ifdef HAVE_R_IA64_DIR32LSB
+#define DWARF_PRO_R_IA64_DIR32LSB R_IA64_DIR32LSB
+#define DWARF_PRO_R_IA64_DIR64LSB R_IA64_DIR64LSB
+#define DWARF_PRO_R_IA64_SEGREL64LSB R_IA64_SEGREL64LSB
+#define DWARF_PRO_R_IA64_SEGREL32LSB R_IA64_SEGREL32LSB
+#endif
+#if defined(HAVE_R_IA_64_DIR32LSB) && !defined(HAVE_R_IA64_DIR32LSB)
+#define DWARF_PRO_R_IA64_DIR32LSB R_IA_64_DIR32LSB
+#define DWARF_PRO_R_IA64_DIR64LSB R_IA_64_DIR64LSB
+#define DWARF_PRO_R_IA64_SEGREL64LSB R_IA_64_SEGREL64LSB
+#define DWARF_PRO_R_IA64_SEGREL32LSB R_IA_64_SEGREL32LSB
+#endif
+#if !defined(HAVE_R_IA_64_DIR32LSB) && !defined(HAVE_R_IA64_DIR32LSB)
+#define DWARF_PRO_R_IA64_DIR32LSB 0
+#define DWARF_PRO_R_IA64_DIR64LSB 0
+#define DWARF_PRO_R_IA64_SEGREL64LSB 0
+#define DWARF_PRO_R_IA64_SEGREL32LSB 0
+#endif
+
+/*
+ * The default "I don't know" value can't be zero.
+ * Because that's the sentinel value that means "no relocation".
+ * In order to use this library in 'symbolic relocation mode we
+ * don't care if this value is the right relocation value,
+ * only that it's non-NULL. So at the end, we define it
+ * to something sensible.
+ */
+
+
+
+#if defined(sun)
+#if defined(sparc)
+#define Get_REL64_isa(dbg) (R_SPARC_UA64)
+#define Get_REL32_isa(dbg) (R_SPARC_UA32)
+#define Get_REL_SEGREL_isa(dbg) (R_SPARC_NONE) /* I don't know! */
+#else /* i386 */
+#define Get_REL64_isa(dbg) (R_386_32) /* Any non-zero value is ok */
+#define Get_REL32_isa(dbg) (R_386_32)
+#define Get_REL_SEGREL_isa(dbg) (R_386_NONE) /* I don't know! */
+#endif /* sparc || i386 */
+#else /* !sun */
+#ifdef HAVE_SYS_IA64_ELF_H
+#define Get_REL64_isa(dbg) (ISA_IA64(dbg) ? \
+ DWARF_PRO_R_IA64_DIR64LSB : R_MIPS_64)
+#define Get_REL32_isa(dbg) (ISA_IA64(dbg) ? \
+ DWARF_PRO_R_IA64_DIR32LSB : R_MIPS_32)
+
+
+/* ia64 uses 32bit dwarf offsets for sections */
+#define Get_REL_SEGREL_isa(dbg) (ISA_IA64(dbg) ? \
+ DWARF_PRO_R_IA64_SEGREL32LSB : R_MIPS_SCN_DISP)
+#else /* HAVE_SYS_IA64_ELF_H */
+
+#if !defined(linux) && !defined(__BEOS__)
+#define Get_REL64_isa(dbg) (R_MIPS_64)
+#define Get_REL32_isa(dbg) (R_MIPS_32)
+#define Get_REL_SEGREL_isa(dbg) (R_MIPS_SCN_DISP)
+#else
+#define Get_REL64_isa(dbg) (1)
+#define Get_REL32_isa(dbg) (1) /* these are used on linux */
+#define Get_REL_SEGREL_isa(dbg) (1) /* non zero values, see comments above */
+#endif
+
+#endif /* HAVE_SYS_IA64_ELF_H */
+#endif /* !sun */
+
+
diff --git a/usr/src/lib/libdwarf/common/pro_vars.c b/usr/src/lib/libdwarf/common/pro_vars.c
new file mode 100644
index 0000000000..3e75a9d9af
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_vars.c
@@ -0,0 +1,62 @@
+/*
+
+ Copyright (C) 2000,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
+
+*/
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_ELFACCESS_H
+#include <elfaccess.h>
+#endif
+#include "pro_incl.h"
+#include "pro_section.h"
+
+/*
+ This function adds another variable name to the
+ list of variable names for the given Dwarf_P_Debug.
+ It returns 0 on error, and 1 otherwise.
+*/
+Dwarf_Unsigned
+dwarf_add_varname(Dwarf_P_Debug dbg,
+ Dwarf_P_Die die, char *var_name, Dwarf_Error * error)
+{
+ return
+ _dwarf_add_simple_name_entry(dbg, die, var_name,
+ dwarf_snk_varname, error);
+
+
+}
diff --git a/usr/src/lib/libdwarf/common/pro_weaks.c b/usr/src/lib/libdwarf/common/pro_weaks.c
new file mode 100644
index 0000000000..8c74bf08ca
--- /dev/null
+++ b/usr/src/lib/libdwarf/common/pro_weaks.c
@@ -0,0 +1,61 @@
+/*
+
+ Copyright (C) 2000,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
+
+*/
+
+
+
+#include "config.h"
+#include "libdwarfdefs.h"
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_ELFACCESS_H
+#include <elfaccess.h>
+#endif
+#include "pro_incl.h"
+#include "pro_section.h"
+
+/*
+ This function adds another weak name to the
+ list of weak names for the given Dwarf_P_Debug.
+ It returns 0 on error, and 1 otherwise.
+*/
+Dwarf_Unsigned
+dwarf_add_weakname(Dwarf_P_Debug dbg,
+ Dwarf_P_Die die,
+ char *weak_name, Dwarf_Error * error)
+{
+ return
+ _dwarf_add_simple_name_entry(dbg, die, weak_name,
+ dwarf_snk_weakname, error);
+}
diff --git a/usr/src/lib/libdwarf/i386/Makefile b/usr/src/lib/libdwarf/i386/Makefile
new file mode 100644
index 0000000000..4398507523
--- /dev/null
+++ b/usr/src/lib/libdwarf/i386/Makefile
@@ -0,0 +1,18 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS)
diff --git a/usr/src/lib/libdwarf/sparc/Makefile b/usr/src/lib/libdwarf/sparc/Makefile
new file mode 100644
index 0000000000..4398507523
--- /dev/null
+++ b/usr/src/lib/libdwarf/sparc/Makefile
@@ -0,0 +1,18 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS)
diff --git a/usr/src/lib/libdwarf/sparcv9/Makefile b/usr/src/lib/libdwarf/sparcv9/Makefile
new file mode 100644
index 0000000000..4e7833710f
--- /dev/null
+++ b/usr/src/lib/libdwarf/sparcv9/Makefile
@@ -0,0 +1,19 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
diff --git a/usr/src/lib/mergeq/mergeq.c b/usr/src/lib/mergeq/mergeq.c
new file mode 100644
index 0000000000..fd9a9c32ea
--- /dev/null
+++ b/usr/src/lib/mergeq/mergeq.c
@@ -0,0 +1,606 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+/*
+ * Merge queue
+ *
+ * A multi-threaded merging queue.
+ *
+ * The general constraint of the merge queue is that if a set of items are
+ * inserted into the queue in the same order, then no matter how many threads
+ * are on the scene, we will always process the items in the same order. The
+ * secondary constraint is that to support environments that must be
+ * single-threaded, we explicitly *must not* create a thread in the case where
+ * the number of requested threads is just one.
+ *
+ * To that end, we've designed our queue as a circular buffer. We will grow that
+ * buffer to contain enough space for all the input items, after which we'll
+ * then treat it as a circular buffer.
+ *
+ * Items will be issued to a processing function two at a time, until there is
+ * only one item remaining in the queue, at which point we will be doing doing
+ * any merging work.
+ *
+ * A given queue has three different entries that we care about tracking:
+ *
+ * o mq_nproc - What is the slot of the next item to process for something
+ * looking for work.
+ *
+ * o mq_next - What is the slot of the next item that should be inserted into
+ * the queue.
+ *
+ * o mq_ncommit - What is the slot of the next item that should be committed.
+ *
+ * When a thread comes and looks for work, we pop entries off of the queue based
+ * on the index provided by mq_nproc. At the same time, it also gets the slot
+ * that it should place the result in, which is mq_next. However, because we
+ * have multiple threads that are operating on the system, we want to make sure
+ * that we push things onto the queue in order. We do that by allocating a slot
+ * to each task and when it completes, it waits for its slot to be ready based
+ * on it being the value of mq_ncommit.
+ *
+ * In addition, we keep track of the number of items in the queue as well as the
+ * number of active workers. There's also a generation count that is used to
+ * figure out when the various values might lap one another.
+ *
+ * The following images show what happens when we have a queue with six items
+ * and whose capacity has been shrunk to six, to better fit in the screen.
+ *
+ *
+ * 1) This is the initial configuration of the queue right before any processing
+ * is done in the context of mergeq_merge(). Every box has an initial item for
+ * merging in it (represented by an 'x'). Here, the mq_nproc, mq_next, and
+ * mq_ncommit will all point at the initial entry. However, the mq_next has
+ * already lapped around the array and thus has a generation count of one.
+ *
+ * The '+' characters indicate which bucket the corresponding value of mq_nproc,
+ * mq_ncommit, and mq_nproc.
+ *
+ * +---++---++---++---++---++---+
+ * | X || X || X || X || X || X |
+ * +---++---++---++---++---++---+
+ * mq_next (g1) +
+ * mq_ncommit (g0) +
+ * mq_nproc (g0) +
+ *
+ * 2) This shows the state right as the first thread begins to process an entry.
+ * Note in this example we will have two threads processing this queue. Note,
+ * mq_ncommit has not advanced. This is because the first thread has started
+ * processing entries, but it has not finished, and thus we can't commit it.
+ * We've incremented mq_next by one because it has gone ahead and assigned a
+ * single entry. We've incremented mq_nproc by two, because we have removed two
+ * entries and thus will have another set available.
+ *
+ * +---++---++---++---++---++---+ t1 - slot 0
+ * | || || X || X || X || X | t2 - idle
+ * +---++---++---++---++---++---+
+ * mq_next (g1) +
+ * mq_ncommit (g0) +
+ * mq_nproc (g0) +
+ *
+ *
+ * 3) This shows the state right after the second thread begins to process an
+ * entry, note that the first thread has not finished. The changes are very
+ * similar to the previous state, we've advanced, mq_nproc and mq_next, but not
+ * mq_ncommit.
+ *
+ * +---++---++---++---++---++---+ t1 - slot 0
+ * | || || || || X || X | t2 - slot 1
+ * +---++---++---++---++---++---+
+ * mq_next (g1) +
+ * mq_ncommit (g0) +
+ * mq_nproc (g0) +
+ *
+ * 4) This shows the state after thread one has finished processing an item, but
+ * before it does anything else. Note that even if thread two finishes early, it
+ * cannot commit its item until thread one finishes. Here 'Y' refers to the
+ * result of merging the first two 'X's.
+ *
+ * +---++---++---++---++---++---+ t1 - idle
+ * | Y || || || || X || X | t2 - slot 1
+ * +---++---++---++---++---++---+
+ * mq_next (g1) +
+ * mq_ncommit (g0) +
+ * mq_nproc (g0) +
+ *
+ * 5) This shows the state after thread one has begun to process the next round
+ * and after thread two has committed, but before it begins processing the next
+ * item. Note that mq_nproc has wrapped around and we've bumped its generation
+ * counter.
+ *
+ * +---++---++---++---++---++---+ t1 - slot 2
+ * | Y || Y || || || || | t2 - idle
+ * +---++---++---++---++---++---+
+ * mq_next (g1) +
+ * mq_ncommit (g0) +
+ * mq_nproc (g0) +
+ *
+ * 6) Here, thread two, will take the next two Y values and thread 1 will commit
+ * its 'Y'. Thread one now must wait until thread two finishes such that it can
+ * do additional work.
+ *
+ * +---++---++---++---++---++---+ t1 - waiting
+ * | || || Y || || || | t2 - slot 3
+ * +---++---++---++---++---++---+
+ * mq_next (g1) +
+ * mq_ncommit (g0) +
+ * mq_nproc (g0) +
+ *
+ * 7) Here, thread two has committed and thread one is about to go process the
+ * final entry. The character 'Z' represents the results of merging two 'Y's.
+ *
+ * +---++---++---++---++---++---+ t1 - idle
+ * | || || Y || Z || || | t2 - idle
+ * +---++---++---++---++---++---+
+ * mq_next (g1) +
+ * mq_ncommit (g0) +
+ * mq_nproc (g0) +
+ *
+ * 8) Here, thread one is processing the final item. Thread two is waiting in
+ * mergeq_pop() for enough items to be available. In this case, it will never
+ * happen; however, once all threads have finished it will break out.
+ *
+ * +---++---++---++---++---++---+ t1 - slot 4
+ * | || || || || || | t2 - idle
+ * +---++---++---++---++---++---+
+ * mq_next (g1) +
+ * mq_ncommit (g0) +
+ * mq_nproc (g0) +
+ *
+ * 9) This is the final state of the queue, it has a single '*' item which is
+ * the final merge result. At this point, both thread one and thread two would
+ * stop processing and we'll return the result to the user.
+ *
+ * +---++---++---++---++---++---+ t1 - slot 4
+ * | || || || || * || | t2 - idle
+ * +---++---++---++---++---++---+
+ * mq_next (g1) +
+ * mq_ncommit (g0) +
+ * mq_nproc (g0) +
+ *
+ *
+ * Note, that if at any point in time the processing function fails, then all
+ * the merges will quiesce and that error will be propagated back to the user.
+ */
+
+#include <strings.h>
+#include <sys/debug.h>
+#include <thread.h>
+#include <synch.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#include "mergeq.h"
+
+struct mergeq {
+ mutex_t mq_lock; /* Protects items below */
+ cond_t mq_cond; /* Condition variable */
+ void **mq_items; /* Array of items to process */
+ size_t mq_nitems; /* Number of items in the queue */
+ size_t mq_cap; /* Capacity of the items */
+ size_t mq_next; /* Place to put next entry */
+ size_t mq_gnext; /* Generation for next */
+ size_t mq_nproc; /* Index of next thing to process */
+ size_t mq_gnproc; /* Generation for next proc */
+ size_t mq_ncommit; /* Index of the next thing to commit */
+ size_t mq_gncommit; /* Commit generation */
+ uint_t mq_nactthrs; /* Number of active threads */
+ uint_t mq_ndthreads; /* Desired number of threads */
+ thread_t *mq_thrs; /* Actual threads */
+ mergeq_proc_f *mq_func; /* Processing function */
+ void *mq_arg; /* Argument for processing */
+ boolean_t mq_working; /* Are we working on processing */
+ boolean_t mq_iserror; /* Have we encountered an error? */
+ int mq_error;
+};
+
+#define MERGEQ_DEFAULT_CAP 64
+
+static int
+mergeq_error(int err)
+{
+ errno = err;
+ return (MERGEQ_ERROR);
+}
+
+void
+mergeq_fini(mergeq_t *mqp)
+{
+ if (mqp == NULL)
+ return;
+
+ VERIFY(mqp->mq_working != B_TRUE);
+
+ if (mqp->mq_items != NULL)
+ mergeq_free(mqp->mq_items, sizeof (void *) * mqp->mq_cap);
+ if (mqp->mq_ndthreads > 0) {
+ mergeq_free(mqp->mq_thrs, sizeof (thread_t) *
+ mqp->mq_ndthreads);
+ }
+ VERIFY0(cond_destroy(&mqp->mq_cond));
+ VERIFY0(mutex_destroy(&mqp->mq_lock));
+ mergeq_free(mqp, sizeof (mergeq_t));
+}
+
+int
+mergeq_init(mergeq_t **outp, uint_t nthrs)
+{
+ int ret;
+ mergeq_t *mqp;
+
+ mqp = mergeq_alloc(sizeof (mergeq_t));
+ if (mqp == NULL)
+ return (mergeq_error(ENOMEM));
+
+ bzero(mqp, sizeof (mergeq_t));
+ mqp->mq_items = mergeq_alloc(sizeof (void *) * MERGEQ_DEFAULT_CAP);
+ if (mqp->mq_items == NULL) {
+ mergeq_free(mqp, sizeof (mergeq_t));
+ return (mergeq_error(ENOMEM));
+ }
+ bzero(mqp->mq_items, sizeof (void *) * MERGEQ_DEFAULT_CAP);
+
+ mqp->mq_ndthreads = nthrs - 1;
+ if (mqp->mq_ndthreads > 0) {
+ mqp->mq_thrs = mergeq_alloc(sizeof (thread_t) *
+ mqp->mq_ndthreads);
+ if (mqp->mq_thrs == NULL) {
+ mergeq_free(mqp->mq_items, sizeof (void *) *
+ MERGEQ_DEFAULT_CAP);
+ mergeq_free(mqp, sizeof (mergeq_t));
+ return (mergeq_error(ENOMEM));
+ }
+ }
+
+ if ((ret = mutex_init(&mqp->mq_lock, USYNC_THREAD | LOCK_ERRORCHECK,
+ NULL)) != 0) {
+ if (mqp->mq_ndthreads > 0) {
+ mergeq_free(mqp->mq_thrs,
+ sizeof (thread_t) * mqp->mq_ndthreads);
+ }
+ mergeq_free(mqp->mq_items, sizeof (void *) *
+ MERGEQ_DEFAULT_CAP);
+ mergeq_free(mqp, sizeof (mergeq_t));
+ return (mergeq_error(ret));
+ }
+
+ if ((ret = cond_init(&mqp->mq_cond, USYNC_THREAD, NULL)) != 0) {
+ VERIFY0(mutex_destroy(&mqp->mq_lock));
+ if (mqp->mq_ndthreads > 0) {
+ mergeq_free(mqp->mq_thrs,
+ sizeof (thread_t) * mqp->mq_ndthreads);
+ }
+ mergeq_free(mqp->mq_items, sizeof (void *) *
+ MERGEQ_DEFAULT_CAP);
+ mergeq_free(mqp, sizeof (mergeq_t));
+ return (mergeq_error(ret));
+ }
+
+ mqp->mq_cap = MERGEQ_DEFAULT_CAP;
+ *outp = mqp;
+ return (0);
+}
+
+static void
+mergeq_reset(mergeq_t *mqp)
+{
+ VERIFY(MUTEX_HELD(&mqp->mq_lock));
+ VERIFY(mqp->mq_working == B_FALSE);
+ if (mqp->mq_cap != 0)
+ bzero(mqp->mq_items, sizeof (void *) * mqp->mq_cap);
+ mqp->mq_nitems = 0;
+ mqp->mq_next = 0;
+ mqp->mq_gnext = 0;
+ mqp->mq_nproc = 0;
+ mqp->mq_gnproc = 0;
+ mqp->mq_ncommit = 0;
+ mqp->mq_gncommit = 0;
+ mqp->mq_func = NULL;
+ mqp->mq_arg = NULL;
+ mqp->mq_iserror = B_FALSE;
+ mqp->mq_error = 0;
+}
+
+static int
+mergeq_grow(mergeq_t *mqp)
+{
+ size_t ncap;
+ void **items;
+
+ VERIFY(MUTEX_HELD(&mqp->mq_lock));
+ VERIFY(mqp->mq_working == B_FALSE);
+
+ if (SIZE_MAX - mqp->mq_cap < MERGEQ_DEFAULT_CAP)
+ return (ENOSPC);
+
+ ncap = mqp->mq_cap + MERGEQ_DEFAULT_CAP;
+ items = mergeq_alloc(ncap * sizeof (void *));
+ if (items == NULL)
+ return (ENOMEM);
+
+ bzero(items, ncap * sizeof (void *));
+ bcopy(mqp->mq_items, items, mqp->mq_cap * sizeof (void *));
+ mergeq_free(mqp->mq_items, sizeof (mqp->mq_cap) * sizeof (void *));
+ mqp->mq_items = items;
+ mqp->mq_cap = ncap;
+ return (0);
+}
+
+int
+mergeq_add(mergeq_t *mqp, void *item)
+{
+ VERIFY0(mutex_lock(&mqp->mq_lock));
+ if (mqp->mq_working == B_TRUE) {
+ VERIFY0(mutex_unlock(&mqp->mq_lock));
+ return (mergeq_error(ENXIO));
+ }
+
+ if (mqp->mq_next == mqp->mq_cap) {
+ int ret;
+
+ if ((ret = mergeq_grow(mqp)) != 0) {
+ VERIFY0(mutex_unlock(&mqp->mq_lock));
+ return (mergeq_error(ret));
+ }
+ }
+ mqp->mq_items[mqp->mq_next] = item;
+ mqp->mq_next++;
+ mqp->mq_nitems++;
+
+ VERIFY0(mutex_unlock(&mqp->mq_lock));
+ return (0);
+}
+
+static size_t
+mergeq_slot(mergeq_t *mqp)
+{
+ size_t s;
+
+ VERIFY(MUTEX_HELD(&mqp->mq_lock));
+ VERIFY(mqp->mq_next < mqp->mq_cap);
+
+ /*
+ * This probably should be a cv / wait thing.
+ */
+ VERIFY(mqp->mq_nproc != (mqp->mq_next + 1) % mqp->mq_cap);
+
+ s = mqp->mq_next;
+ mqp->mq_next++;
+ if (mqp->mq_next == mqp->mq_cap) {
+ mqp->mq_next %= mqp->mq_cap;
+ mqp->mq_gnext++;
+ }
+
+ return (s);
+}
+
+/*
+ * Internal function to push items onto the queue which is now a circular
+ * buffer. This should only be used once we begin working on the queue.
+ */
+static void
+mergeq_push(mergeq_t *mqp, size_t slot, void *item)
+{
+ VERIFY(MUTEX_HELD(&mqp->mq_lock));
+ VERIFY(slot < mqp->mq_cap);
+
+ /*
+ * We need to verify that we don't push over something that exists.
+ * Based on the design, this should never happen. However, in the face
+ * of bugs, anything is possible.
+ */
+ while (mqp->mq_ncommit != slot && mqp->mq_iserror == B_FALSE)
+ (void) cond_wait(&mqp->mq_cond, &mqp->mq_lock);
+
+ if (mqp->mq_iserror == B_TRUE)
+ return;
+
+ mqp->mq_items[slot] = item;
+ mqp->mq_nitems++;
+ mqp->mq_ncommit++;
+ if (mqp->mq_ncommit == mqp->mq_cap) {
+ mqp->mq_ncommit %= mqp->mq_cap;
+ mqp->mq_gncommit++;
+ }
+ cond_broadcast(&mqp->mq_cond);
+}
+
+static void *
+mergeq_pop_one(mergeq_t *mqp)
+{
+ void *out;
+
+ /*
+ * We can't move mq_nproc beyond mq_next if they're on the same
+ * generation.
+ */
+ VERIFY(mqp->mq_gnext != mqp->mq_gnproc ||
+ mqp->mq_nproc != mqp->mq_next);
+
+ out = mqp->mq_items[mqp->mq_nproc];
+
+ mqp->mq_items[mqp->mq_nproc] = NULL;
+ mqp->mq_nproc++;
+ if (mqp->mq_nproc == mqp->mq_cap) {
+ mqp->mq_nproc %= mqp->mq_cap;
+ mqp->mq_gnproc++;
+ }
+ mqp->mq_nitems--;
+
+ return (out);
+}
+
+/*
+ * Pop a set of two entries from the queue. We may not have anything to process
+ * at the moment, eg. be waiting for someone to add something. In which case,
+ * we'll be sitting and waiting.
+ */
+static boolean_t
+mergeq_pop(mergeq_t *mqp, void **first, void **second)
+{
+ VERIFY(MUTEX_HELD(&mqp->mq_lock));
+ VERIFY(mqp->mq_nproc < mqp->mq_cap);
+
+ while (mqp->mq_nitems < 2 && mqp->mq_nactthrs > 0 &&
+ mqp->mq_iserror == B_FALSE)
+ (void) cond_wait(&mqp->mq_cond, &mqp->mq_lock);
+
+ if (mqp->mq_iserror == B_TRUE)
+ return (B_FALSE);
+
+ if (mqp->mq_nitems < 2 && mqp->mq_nactthrs == 0) {
+ VERIFY(mqp->mq_iserror == B_TRUE || mqp->mq_nitems == 1);
+ return (B_FALSE);
+ }
+ VERIFY(mqp->mq_nitems >= 2);
+
+ *first = mergeq_pop_one(mqp);
+ *second = mergeq_pop_one(mqp);
+
+ return (B_TRUE);
+}
+
+static void *
+mergeq_thr_merge(void *arg)
+{
+ mergeq_t *mqp = arg;
+
+ VERIFY0(mutex_lock(&mqp->mq_lock));
+
+ /*
+ * Check to make sure creation worked and if not, fail fast.
+ */
+ if (mqp->mq_iserror == B_TRUE) {
+ VERIFY0(mutex_unlock(&mqp->mq_lock));
+ return (NULL);
+ }
+
+ for (;;) {
+ void *first, *second, *out;
+ int ret;
+ size_t slot;
+
+ if (mqp->mq_nitems == 1 && mqp->mq_nactthrs == 0) {
+ VERIFY0(mutex_unlock(&mqp->mq_lock));
+ return (NULL);
+ }
+
+ if (mergeq_pop(mqp, &first, &second) == B_FALSE) {
+ VERIFY0(mutex_unlock(&mqp->mq_lock));
+ return (NULL);
+ }
+ slot = mergeq_slot(mqp);
+
+ mqp->mq_nactthrs++;
+
+ VERIFY0(mutex_unlock(&mqp->mq_lock));
+ ret = mqp->mq_func(first, second, &out, mqp->mq_arg);
+ VERIFY0(mutex_lock(&mqp->mq_lock));
+
+ if (ret != 0) {
+ if (mqp->mq_iserror == B_FALSE) {
+ mqp->mq_iserror = B_TRUE;
+ mqp->mq_error = ret;
+ cond_broadcast(&mqp->mq_cond);
+ }
+ mqp->mq_nactthrs--;
+ VERIFY0(mutex_unlock(&mqp->mq_lock));
+ return (NULL);
+ }
+ mergeq_push(mqp, slot, out);
+ mqp->mq_nactthrs--;
+ }
+}
+
+int
+mergeq_merge(mergeq_t *mqp, mergeq_proc_f *func, void *arg, void **outp,
+ int *errp)
+{
+ int ret, i;
+ boolean_t seterr = B_FALSE;
+
+ if (mqp == NULL || func == NULL || outp == NULL) {
+ return (mergeq_error(EINVAL));
+ }
+
+ VERIFY0(mutex_lock(&mqp->mq_lock));
+ if (mqp->mq_working == B_TRUE) {
+ VERIFY0(mutex_unlock(&mqp->mq_lock));
+ return (mergeq_error(EBUSY));
+ }
+
+ if (mqp->mq_nitems == 0) {
+ *outp = NULL;
+ mergeq_reset(mqp);
+ VERIFY0(mutex_unlock(&mqp->mq_lock));
+ return (0);
+ }
+
+ /*
+ * Now that we've finished adding items to the queue, turn it into a
+ * circular buffer.
+ */
+ mqp->mq_func = func;
+ mqp->mq_arg = arg;
+ mqp->mq_nproc = 0;
+ mqp->mq_working = B_TRUE;
+ if (mqp->mq_next == mqp->mq_cap) {
+ mqp->mq_next %= mqp->mq_cap;
+ mqp->mq_gnext++;
+ }
+ mqp->mq_ncommit = mqp->mq_next;
+
+ ret = 0;
+ for (i = 0; i < mqp->mq_ndthreads; i++) {
+ ret = thr_create(NULL, 0, mergeq_thr_merge, mqp, 0,
+ &mqp->mq_thrs[i]);
+ if (ret != 0) {
+ mqp->mq_iserror = B_TRUE;
+ break;
+ }
+ }
+
+ VERIFY0(mutex_unlock(&mqp->mq_lock));
+ if (ret == 0)
+ (void) mergeq_thr_merge(mqp);
+
+ for (i = 0; i < mqp->mq_ndthreads; i++) {
+ VERIFY0(thr_join(mqp->mq_thrs[i], NULL, NULL));
+ }
+
+ VERIFY0(mutex_lock(&mqp->mq_lock));
+
+ VERIFY(mqp->mq_nactthrs == 0);
+ mqp->mq_working = B_FALSE;
+ if (ret == 0 && mqp->mq_iserror == B_FALSE) {
+ VERIFY(mqp->mq_nitems == 1);
+ *outp = mergeq_pop_one(mqp);
+ } else if (ret == 0 && mqp->mq_iserror == B_TRUE) {
+ ret = MERGEQ_UERROR;
+ if (errp != NULL)
+ *errp = mqp->mq_error;
+ } else {
+ seterr = B_TRUE;
+ }
+
+ mergeq_reset(mqp);
+ VERIFY0(mutex_unlock(&mqp->mq_lock));
+
+ if (seterr == B_TRUE)
+ return (mergeq_error(ret));
+
+ return (ret);
+}
diff --git a/usr/src/lib/mergeq/mergeq.h b/usr/src/lib/mergeq/mergeq.h
new file mode 100644
index 0000000000..4c1a21d696
--- /dev/null
+++ b/usr/src/lib/mergeq/mergeq.h
@@ -0,0 +1,52 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+#ifndef _MERGEQ_H
+#define _MERGEQ_H
+
+/*
+ * mergeq library routines
+ */
+
+#include <sys/types.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct mergeq mergeq_t;
+typedef int (mergeq_proc_f)(void *, void *, void **, void *);
+
+extern int mergeq_init(mergeq_t **, uint_t);
+extern void mergeq_fini(mergeq_t *);
+
+extern int mergeq_add(mergeq_t *, void *);
+
+#define MERGEQ_ERROR -1
+#define MERGEQ_UERROR -2
+extern int mergeq_merge(mergeq_t *, mergeq_proc_f *, void *, void **, int *);
+
+/*
+ * Routines consumers need to implement
+ */
+extern void *mergeq_alloc(size_t);
+extern void mergeq_free(void *, size_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MERGEQ_H */
diff --git a/usr/src/lib/mergeq/workq.c b/usr/src/lib/mergeq/workq.c
new file mode 100644
index 0000000000..b9f1f2aa1c
--- /dev/null
+++ b/usr/src/lib/mergeq/workq.c
@@ -0,0 +1,311 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+/*
+ * Work queue
+ *
+ * A multi-threaded work queue.
+ *
+ * The general design of this is to add a fixed number of items to the queue and
+ * then drain them with the specified number of threads.
+ */
+
+#include <strings.h>
+#include <sys/debug.h>
+#include <thread.h>
+#include <synch.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#include "workq.h"
+
+struct workq {
+ mutex_t wq_lock; /* Protects below items */
+ cond_t wq_cond; /* Condition variable */
+ void **wq_items; /* Array of items to process */
+ size_t wq_nitems; /* Number of items in queue */
+ size_t wq_cap; /* Queue capacity */
+ size_t wq_next; /* Next item to process */
+ uint_t wq_ndthreads; /* Desired number of threads */
+ thread_t *wq_thrs; /* Actual threads */
+ workq_proc_f *wq_func; /* Processing function */
+ void *wq_arg; /* Argument for processing */
+ boolean_t wq_working; /* Are we actively using it? */
+ boolean_t wq_iserror; /* Have we encountered an error? */
+ int wq_error; /* Error value, if any */
+};
+
+#define WORKQ_DEFAULT_CAP 64
+
+static int
+workq_error(int err)
+{
+ VERIFY(err != 0);
+ errno = err;
+ return (WORKQ_ERROR);
+}
+
+void
+workq_fini(workq_t *wqp)
+{
+ if (wqp == NULL)
+ return;
+
+ VERIFY(wqp->wq_working != B_TRUE);
+ VERIFY0(mutex_destroy(&wqp->wq_lock));
+ VERIFY0(cond_destroy(&wqp->wq_cond));
+ if (wqp->wq_cap > 0)
+ workq_free(wqp->wq_items, sizeof (void *) * wqp->wq_cap);
+ if (wqp->wq_ndthreads > 0)
+ workq_free(wqp->wq_thrs, sizeof (thread_t) * wqp->wq_ndthreads);
+ workq_free(wqp, sizeof (workq_t));
+}
+
+int
+workq_init(workq_t **outp, uint_t nthrs)
+{
+ int ret;
+ workq_t *wqp;
+
+ wqp = workq_alloc(sizeof (workq_t));
+ if (wqp == NULL)
+ return (workq_error(ENOMEM));
+
+ bzero(wqp, sizeof (workq_t));
+ wqp->wq_items = workq_alloc(sizeof (void *) * WORKQ_DEFAULT_CAP);
+ if (wqp->wq_items == NULL) {
+ workq_free(wqp, sizeof (workq_t));
+ return (workq_error(ENOMEM));
+ }
+ bzero(wqp->wq_items, sizeof (void *) * WORKQ_DEFAULT_CAP);
+
+ wqp->wq_ndthreads = nthrs - 1;
+ if (wqp->wq_ndthreads > 0) {
+ wqp->wq_thrs = workq_alloc(sizeof (thread_t) *
+ wqp->wq_ndthreads);
+ if (wqp->wq_thrs == NULL) {
+ workq_free(wqp->wq_items, sizeof (void *) *
+ WORKQ_DEFAULT_CAP);
+ workq_free(wqp, sizeof (workq_t));
+ return (workq_error(ENOMEM));
+ }
+ }
+
+ if ((ret = mutex_init(&wqp->wq_lock, USYNC_THREAD | LOCK_ERRORCHECK,
+ NULL)) != 0) {
+ if (wqp->wq_ndthreads > 0) {
+ workq_free(wqp->wq_thrs,
+ sizeof (thread_t) * wqp->wq_ndthreads);
+ }
+ workq_free(wqp->wq_items, sizeof (void *) * WORKQ_DEFAULT_CAP);
+ workq_free(wqp, sizeof (workq_t));
+ return (workq_error(ret));
+ }
+
+ if ((ret = cond_init(&wqp->wq_cond, USYNC_THREAD, NULL)) != 0) {
+ VERIFY0(mutex_destroy(&wqp->wq_lock));
+ if (wqp->wq_ndthreads > 0) {
+ workq_free(wqp->wq_thrs,
+ sizeof (thread_t) * wqp->wq_ndthreads);
+ }
+ workq_free(wqp->wq_items, sizeof (void *) * WORKQ_DEFAULT_CAP);
+ workq_free(wqp, sizeof (workq_t));
+ return (workq_error(ret));
+ }
+
+ wqp->wq_cap = WORKQ_DEFAULT_CAP;
+ *outp = wqp;
+ return (0);
+}
+
+static void
+workq_reset(workq_t *wqp)
+{
+ VERIFY(MUTEX_HELD(&wqp->wq_lock));
+ VERIFY(wqp->wq_working == B_FALSE);
+ if (wqp->wq_cap > 0)
+ bzero(wqp->wq_items, sizeof (void *) * wqp->wq_cap);
+ wqp->wq_nitems = 0;
+ wqp->wq_next = 0;
+ wqp->wq_func = NULL;
+ wqp->wq_arg = NULL;
+ wqp->wq_iserror = B_FALSE;
+ wqp->wq_error = 0;
+}
+
+static int
+workq_grow(workq_t *wqp)
+{
+ size_t ncap;
+ void **items;
+
+ VERIFY(MUTEX_HELD(&wqp->wq_lock));
+ VERIFY(wqp->wq_working == B_FALSE);
+
+ if (SIZE_MAX - wqp->wq_cap < WORKQ_DEFAULT_CAP)
+ return (ENOSPC);
+
+ ncap = wqp->wq_cap + WORKQ_DEFAULT_CAP;
+ items = workq_alloc(ncap * sizeof (void *));
+ if (items == NULL)
+ return (ENOMEM);
+
+ bzero(items, ncap * sizeof (void *));
+ bcopy(wqp->wq_items, items, wqp->wq_cap * sizeof (void *));
+ workq_free(wqp->wq_items, sizeof (void *) * wqp->wq_cap);
+ wqp->wq_items = items;
+ wqp->wq_cap = ncap;
+ return (0);
+}
+
+int
+workq_add(workq_t *wqp, void *item)
+{
+ VERIFY0(mutex_lock(&wqp->wq_lock));
+ if (wqp->wq_working == B_TRUE) {
+ VERIFY0(mutex_unlock(&wqp->wq_lock));
+ return (workq_error(ENXIO));
+ }
+
+ if (wqp->wq_nitems == wqp->wq_cap) {
+ int ret;
+
+ if ((ret = workq_grow(wqp)) != 0) {
+ VERIFY0(mutex_unlock(&wqp->wq_lock));
+ return (workq_error(ret));
+ }
+ }
+
+ wqp->wq_items[wqp->wq_nitems] = item;
+ wqp->wq_nitems++;
+
+ VERIFY0(mutex_unlock(&wqp->wq_lock));
+
+ return (0);
+}
+
+static void *
+workq_pop(workq_t *wqp)
+{
+ void *out;
+
+ VERIFY(MUTEX_HELD(&wqp->wq_lock));
+ VERIFY(wqp->wq_next < wqp->wq_nitems);
+
+ out = wqp->wq_items[wqp->wq_next];
+ wqp->wq_items[wqp->wq_next] = NULL;
+ wqp->wq_next++;
+
+ return (out);
+}
+
+static void *
+workq_thr_work(void *arg)
+{
+ workq_t *wqp = arg;
+
+ VERIFY0(mutex_lock(&wqp->wq_lock));
+ VERIFY(wqp->wq_working == B_TRUE);
+
+ for (;;) {
+ int ret;
+ void *item;
+
+ if (wqp->wq_iserror == B_TRUE ||
+ wqp->wq_next == wqp->wq_nitems) {
+ VERIFY0(mutex_unlock(&wqp->wq_lock));
+ return (NULL);
+ }
+
+ item = workq_pop(wqp);
+
+ VERIFY0(mutex_unlock(&wqp->wq_lock));
+ ret = wqp->wq_func(item, wqp->wq_arg);
+ VERIFY0(mutex_lock(&wqp->wq_lock));
+
+ if (ret != 0) {
+ if (wqp->wq_iserror == B_FALSE) {
+ wqp->wq_iserror = B_TRUE;
+ wqp->wq_error = ret;
+ }
+ VERIFY0(mutex_unlock(&wqp->wq_lock));
+ return (NULL);
+ }
+ }
+}
+
+int
+workq_work(workq_t *wqp, workq_proc_f *func, void *arg, int *errp)
+{
+ int i, ret;
+ boolean_t seterr = B_FALSE;
+
+ if (wqp == NULL || func == NULL)
+ return (workq_error(EINVAL));
+
+ VERIFY0(mutex_lock(&wqp->wq_lock));
+ if (wqp->wq_working == B_TRUE) {
+ VERIFY0(mutex_unlock(&wqp->wq_lock));
+ return (workq_error(EBUSY));
+ }
+
+ if (wqp->wq_nitems == 0) {
+ workq_reset(wqp);
+ VERIFY0(mutex_unlock(&wqp->wq_lock));
+ return (0);
+ }
+
+ wqp->wq_func = func;
+ wqp->wq_arg = arg;
+ wqp->wq_next = 0;
+ wqp->wq_working = B_TRUE;
+
+ ret = 0;
+ for (i = 0; i < wqp->wq_ndthreads; i++) {
+ ret = thr_create(NULL, 0, workq_thr_work, wqp, 0,
+ &wqp->wq_thrs[i]);
+ if (ret != 0) {
+ wqp->wq_iserror = B_TRUE;
+ }
+ }
+
+ VERIFY0(mutex_unlock(&wqp->wq_lock));
+ if (ret == 0)
+ (void) workq_thr_work(wqp);
+
+ for (i = 0; i < wqp->wq_ndthreads; i++) {
+ VERIFY0(thr_join(wqp->wq_thrs[i], NULL, NULL));
+ }
+
+ VERIFY0(mutex_lock(&wqp->wq_lock));
+ wqp->wq_working = B_FALSE;
+ if (ret == 0 && wqp->wq_iserror == B_TRUE) {
+ ret = WORKQ_UERROR;
+ if (errp != NULL)
+ *errp = wqp->wq_error;
+ } else if (ret != 0) {
+ VERIFY(wqp->wq_iserror == B_FALSE);
+ seterr = B_TRUE;
+ }
+
+ workq_reset(wqp);
+ VERIFY0(mutex_unlock(&wqp->wq_lock));
+
+ if (seterr == B_TRUE)
+ return (workq_error(ret));
+
+ return (ret);
+}
diff --git a/usr/src/lib/mergeq/workq.h b/usr/src/lib/mergeq/workq.h
new file mode 100644
index 0000000000..20cfec4a95
--- /dev/null
+++ b/usr/src/lib/mergeq/workq.h
@@ -0,0 +1,52 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+#ifndef _WORKQ_H
+#define _WORKQ_H
+
+/*
+ * workq library routines
+ */
+
+#include <sys/types.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct workq workq_t;
+typedef int (workq_proc_f)(void *, void *);
+
+extern int workq_init(workq_t **, uint_t);
+extern void workq_fini(workq_t *);
+
+extern int workq_add(workq_t *, void *);
+
+#define WORKQ_ERROR (-1)
+#define WORKQ_UERROR (-2)
+extern int workq_work(workq_t *, workq_proc_f *, void *, int *);
+
+/*
+ * Routines consumers need to implement
+ */
+extern void *workq_alloc(size_t);
+extern void workq_free(void *, size_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _WORKQ_H */