diff options
Diffstat (limited to 'usr/src/lib')
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, <ag, &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 = ®_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 = ®_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 = ®_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, + §ion->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 */ |