summaryrefslogtreecommitdiffstats
path: root/rtemstoolkit/elftoolchain/libdwarf/libdwarf_attr.c
diff options
context:
space:
mode:
Diffstat (limited to 'rtemstoolkit/elftoolchain/libdwarf/libdwarf_attr.c')
-rw-r--r--rtemstoolkit/elftoolchain/libdwarf/libdwarf_attr.c459
1 files changed, 459 insertions, 0 deletions
diff --git a/rtemstoolkit/elftoolchain/libdwarf/libdwarf_attr.c b/rtemstoolkit/elftoolchain/libdwarf/libdwarf_attr.c
new file mode 100644
index 0000000..dfbbc48
--- /dev/null
+++ b/rtemstoolkit/elftoolchain/libdwarf/libdwarf_attr.c
@@ -0,0 +1,459 @@
+/*-
+ * Copyright (c) 2007 John Birrell (jb@freebsd.org)
+ * Copyright (c) 2009-2011 Kai Wang
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "_libdwarf.h"
+
+ELFTC_VCSID("$Id: libdwarf_attr.c 3064 2014-06-06 19:35:55Z kaiwang27 $");
+
+int
+_dwarf_attr_alloc(Dwarf_Die die, Dwarf_Attribute *atp, Dwarf_Error *error)
+{
+ Dwarf_Attribute at;
+
+ assert(die != NULL);
+ assert(atp != NULL);
+
+ if ((at = calloc(1, sizeof(struct _Dwarf_Attribute))) == NULL) {
+ DWARF_SET_ERROR(die->die_dbg, error, DW_DLE_MEMORY);
+ return (DW_DLE_MEMORY);
+ }
+
+ *atp = at;
+
+ return (DW_DLE_NONE);
+}
+
+static int
+_dwarf_attr_add(Dwarf_Die die, Dwarf_Attribute atref, Dwarf_Attribute *atp,
+ Dwarf_Error *error)
+{
+ Dwarf_Attribute at;
+ int ret;
+
+ if ((ret = _dwarf_attr_alloc(die, &at, error)) != DW_DLE_NONE)
+ return (ret);
+
+ memcpy(at, atref, sizeof(struct _Dwarf_Attribute));
+
+ STAILQ_INSERT_TAIL(&die->die_attr, at, at_next);
+
+ /* Save a pointer to the attribute name if this is one. */
+ if (at->at_attrib == DW_AT_name) {
+ switch (at->at_form) {
+ case DW_FORM_strp:
+ die->die_name = at->u[1].s;
+ break;
+ case DW_FORM_string:
+ die->die_name = at->u[0].s;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (atp != NULL)
+ *atp = at;
+
+ return (DW_DLE_NONE);
+}
+
+Dwarf_Attribute
+_dwarf_attr_find(Dwarf_Die die, Dwarf_Half attr)
+{
+ Dwarf_Attribute at;
+
+ STAILQ_FOREACH(at, &die->die_attr, at_next) {
+ if (at->at_attrib == attr)
+ break;
+ }
+
+ return (at);
+}
+
+int
+_dwarf_attr_init(Dwarf_Debug dbg, Dwarf_Section *ds, uint64_t *offsetp,
+ int dwarf_size, Dwarf_CU cu, Dwarf_Die die, Dwarf_AttrDef ad,
+ uint64_t form, int indirect, Dwarf_Error *error)
+{
+ struct _Dwarf_Attribute atref;
+ Dwarf_Section *str;
+ int ret;
+
+ ret = DW_DLE_NONE;
+ memset(&atref, 0, sizeof(atref));
+ atref.at_die = die;
+ atref.at_offset = *offsetp;
+ atref.at_attrib = ad->ad_attrib;
+ atref.at_form = indirect ? form : ad->ad_form;
+ atref.at_indirect = indirect;
+ atref.at_ld = NULL;
+
+ switch (form) {
+ case DW_FORM_addr:
+ atref.u[0].u64 = dbg->read(ds->ds_data, offsetp,
+ cu->cu_pointer_size);
+ break;
+ case DW_FORM_block:
+ case DW_FORM_exprloc:
+ atref.u[0].u64 = _dwarf_read_uleb128(ds->ds_data, offsetp);
+ atref.u[1].u8p = _dwarf_read_block(ds->ds_data, offsetp,
+ atref.u[0].u64);
+ break;
+ case DW_FORM_block1:
+ atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 1);
+ atref.u[1].u8p = _dwarf_read_block(ds->ds_data, offsetp,
+ atref.u[0].u64);
+ break;
+ case DW_FORM_block2:
+ atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 2);
+ atref.u[1].u8p = _dwarf_read_block(ds->ds_data, offsetp,
+ atref.u[0].u64);
+ break;
+ case DW_FORM_block4:
+ atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 4);
+ atref.u[1].u8p = _dwarf_read_block(ds->ds_data, offsetp,
+ atref.u[0].u64);
+ break;
+ case DW_FORM_data1:
+ case DW_FORM_flag:
+ case DW_FORM_ref1:
+ atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 1);
+ break;
+ case DW_FORM_data2:
+ case DW_FORM_ref2:
+ atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 2);
+ break;
+ case DW_FORM_data4:
+ case DW_FORM_ref4:
+ atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 4);
+ break;
+ case DW_FORM_data8:
+ case DW_FORM_ref8:
+ atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, 8);
+ break;
+ case DW_FORM_indirect:
+ form = _dwarf_read_uleb128(ds->ds_data, offsetp);
+ return (_dwarf_attr_init(dbg, ds, offsetp, dwarf_size, cu, die,
+ ad, form, 1, error));
+ case DW_FORM_ref_addr:
+ if (cu->cu_version == 2)
+ atref.u[0].u64 = dbg->read(ds->ds_data, offsetp,
+ cu->cu_pointer_size);
+ else
+ atref.u[0].u64 = dbg->read(ds->ds_data, offsetp,
+ dwarf_size);
+ break;
+ case DW_FORM_ref_udata:
+ case DW_FORM_udata:
+ atref.u[0].u64 = _dwarf_read_uleb128(ds->ds_data, offsetp);
+ break;
+ case DW_FORM_sdata:
+ atref.u[0].s64 = _dwarf_read_sleb128(ds->ds_data, offsetp);
+ break;
+ case DW_FORM_sec_offset:
+ atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, dwarf_size);
+ break;
+ case DW_FORM_string:
+ atref.u[0].s = _dwarf_read_string(ds->ds_data, ds->ds_size,
+ offsetp);
+ break;
+ case DW_FORM_strp:
+ atref.u[0].u64 = dbg->read(ds->ds_data, offsetp, dwarf_size);
+ str = _dwarf_find_section(dbg, ".debug_str");
+ assert(str != NULL);
+ atref.u[1].s = (char *) str->ds_data + atref.u[0].u64;
+ break;
+ case DW_FORM_ref_sig8:
+ atref.u[0].u64 = 8;
+ atref.u[1].u8p = _dwarf_read_block(ds->ds_data, offsetp,
+ atref.u[0].u64);
+ break;
+ case DW_FORM_flag_present:
+ /* This form has no value encoded in the DIE. */
+ atref.u[0].u64 = 1;
+ break;
+ default:
+ DWARF_SET_ERROR(dbg, error, DW_DLE_ATTR_FORM_BAD);
+ ret = DW_DLE_ATTR_FORM_BAD;
+ break;
+ }
+
+ if (ret == DW_DLE_NONE) {
+ if (form == DW_FORM_block || form == DW_FORM_block1 ||
+ form == DW_FORM_block2 || form == DW_FORM_block4) {
+ atref.at_block.bl_len = atref.u[0].u64;
+ atref.at_block.bl_data = atref.u[1].u8p;
+ }
+ ret = _dwarf_attr_add(die, &atref, NULL, error);
+ }
+
+ return (ret);
+}
+
+static int
+_dwarf_attr_write(Dwarf_P_Debug dbg, Dwarf_P_Section ds, Dwarf_Rel_Section drs,
+ Dwarf_CU cu, Dwarf_Attribute at, int pass2, Dwarf_Error *error)
+{
+ struct _Dwarf_P_Expr_Entry *ee;
+ uint64_t value, offset, bs;
+ int ret;
+
+ assert(dbg != NULL && ds != NULL && cu != NULL && at != NULL);
+
+ /* Fill in reference to other DIE in the second pass. */
+ if (pass2) {
+ if (at->at_form != DW_FORM_ref4 && at->at_form != DW_FORM_ref8)
+ return (DW_DLE_NONE);
+ if (at->at_refdie == NULL || at->at_offset == 0)
+ return (DW_DLE_NONE);
+ offset = at->at_offset;
+ dbg->write(ds->ds_data, &offset, at->at_refdie->die_offset,
+ at->at_form == DW_FORM_ref4 ? 4 : 8);
+ return (DW_DLE_NONE);
+ }
+
+ switch (at->at_form) {
+ case DW_FORM_addr:
+ if (at->at_relsym)
+ ret = _dwarf_reloc_entry_add(dbg, drs, ds,
+ dwarf_drt_data_reloc, cu->cu_pointer_size,
+ ds->ds_size, at->at_relsym, at->u[0].u64, NULL,
+ error);
+ else
+ ret = WRITE_VALUE(at->u[0].u64, cu->cu_pointer_size);
+ break;
+ case DW_FORM_block:
+ case DW_FORM_block1:
+ case DW_FORM_block2:
+ case DW_FORM_block4:
+ /* Write block size. */
+ if (at->at_form == DW_FORM_block) {
+ ret = _dwarf_write_uleb128_alloc(&ds->ds_data,
+ &ds->ds_cap, &ds->ds_size, at->u[0].u64, error);
+ if (ret != DW_DLE_NONE)
+ break;
+ } else {
+ if (at->at_form == DW_FORM_block1)
+ bs = 1;
+ else if (at->at_form == DW_FORM_block2)
+ bs = 2;
+ else
+ bs = 4;
+ ret = WRITE_VALUE(at->u[0].u64, bs);
+ if (ret != DW_DLE_NONE)
+ break;
+ }
+
+ /* Keep block data offset for later use. */
+ offset = ds->ds_size;
+
+ /* Write block data. */
+ ret = WRITE_BLOCK(at->u[1].u8p, at->u[0].u64);
+ if (ret != DW_DLE_NONE)
+ break;
+ if (at->at_expr == NULL)
+ break;
+
+ /* Generate relocation entry for DW_OP_addr expressions. */
+ STAILQ_FOREACH(ee, &at->at_expr->pe_eelist, ee_next) {
+ if (ee->ee_loc.lr_atom != DW_OP_addr || ee->ee_sym == 0)
+ continue;
+ ret = _dwarf_reloc_entry_add(dbg, drs, ds,
+ dwarf_drt_data_reloc, dbg->dbg_pointer_size,
+ offset + ee->ee_loc.lr_offset + 1, ee->ee_sym,
+ ee->ee_loc.lr_number, NULL, error);
+ if (ret != DW_DLE_NONE)
+ break;
+ }
+ break;
+ case DW_FORM_data1:
+ case DW_FORM_flag:
+ case DW_FORM_ref1:
+ ret = WRITE_VALUE(at->u[0].u64, 1);
+ break;
+ case DW_FORM_data2:
+ case DW_FORM_ref2:
+ ret = WRITE_VALUE(at->u[0].u64, 2);
+ break;
+ case DW_FORM_data4:
+ if (at->at_relsym || at->at_relsec != NULL)
+ ret = _dwarf_reloc_entry_add(dbg, drs, ds,
+ dwarf_drt_data_reloc, 4, ds->ds_size, at->at_relsym,
+ at->u[0].u64, at->at_relsec, error);
+ else
+ ret = WRITE_VALUE(at->u[0].u64, 4);
+ break;
+ case DW_FORM_data8:
+ if (at->at_relsym || at->at_relsec != NULL)
+ ret = _dwarf_reloc_entry_add(dbg, drs, ds,
+ dwarf_drt_data_reloc, 8, ds->ds_size, at->at_relsym,
+ at->u[0].u64, at->at_relsec, error);
+ else
+ ret = WRITE_VALUE(at->u[0].u64, 8);
+ break;
+ case DW_FORM_ref4:
+ case DW_FORM_ref8:
+ /*
+ * The value of ref4 and ref8 could be a reference to another
+ * DIE within the CU. And if we don't know the ref DIE's
+ * offset at the moement, then we remember at_offset and fill
+ * it in the second pass.
+ */
+ if (at->at_refdie) {
+ value = at->at_refdie->die_offset;
+ if (value == 0) {
+ cu->cu_pass2 = 1;
+ at->at_offset = ds->ds_size;
+ }
+ } else
+ value = at->u[0].u64;
+ ret = WRITE_VALUE(value, at->at_form == DW_FORM_ref4 ? 4 : 8);
+ break;
+ case DW_FORM_indirect:
+ /* TODO. */
+ DWARF_SET_ERROR(dbg, error, DW_DLE_ATTR_FORM_BAD);
+ ret = DW_DLE_ATTR_FORM_BAD;
+ break;
+ case DW_FORM_ref_addr:
+ /* DWARF2 format. */
+ if (at->at_relsym)
+ ret = _dwarf_reloc_entry_add(dbg, drs, ds,
+ dwarf_drt_data_reloc, cu->cu_pointer_size,
+ ds->ds_size, at->at_relsym, at->u[0].u64, NULL,
+ error);
+ else
+ ret = WRITE_VALUE(at->u[0].u64, cu->cu_pointer_size);
+ break;
+ case DW_FORM_ref_udata:
+ case DW_FORM_udata:
+ ret = WRITE_ULEB128(at->u[0].u64);
+ break;
+ case DW_FORM_sdata:
+ ret = WRITE_SLEB128(at->u[0].s64);
+ break;
+ case DW_FORM_string:
+ assert(at->u[0].s != NULL);
+ ret = WRITE_STRING(at->u[0].s);
+ break;
+ case DW_FORM_strp:
+ ret = _dwarf_reloc_entry_add(dbg, drs, ds, dwarf_drt_data_reloc,
+ 4, ds->ds_size, 0, at->u[0].u64, ".debug_str", error);
+ break;
+ default:
+ DWARF_SET_ERROR(dbg, error, DW_DLE_ATTR_FORM_BAD);
+ ret = DW_DLE_ATTR_FORM_BAD;
+ break;
+ }
+
+ return (ret);
+}
+
+int
+_dwarf_add_AT_dataref(Dwarf_P_Debug dbg, Dwarf_P_Die die, Dwarf_Half attr,
+ Dwarf_Unsigned pc_value, Dwarf_Unsigned sym_index, const char *secname,
+ Dwarf_P_Attribute *atp, Dwarf_Error *error)
+{
+ Dwarf_Attribute at;
+ int ret;
+
+ assert(dbg != NULL && die != NULL);
+
+ if ((ret = _dwarf_attr_alloc(die, &at, error)) != DW_DLE_NONE)
+ return (ret);
+
+ at->at_die = die;
+ at->at_attrib = attr;
+ if (dbg->dbg_pointer_size == 4)
+ at->at_form = DW_FORM_data4;
+ else
+ at->at_form = DW_FORM_data8;
+ at->at_relsym = sym_index;
+ at->at_relsec = secname;
+ at->u[0].u64 = pc_value;
+
+ STAILQ_INSERT_TAIL(&die->die_attr, at, at_next);
+
+ if (atp)
+ *atp = at;
+
+ return (DW_DLE_NONE);
+}
+
+int
+_dwarf_add_string_attr(Dwarf_P_Die die, Dwarf_P_Attribute *atp, Dwarf_Half attr,
+ char *string, Dwarf_Error *error)
+{
+ Dwarf_Attribute at;
+ Dwarf_Debug dbg;
+ int ret;
+
+ dbg = die != NULL ? die->die_dbg : NULL;
+
+ assert(atp != NULL);
+
+ if (die == NULL || string == NULL) {
+ DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
+ return (DW_DLE_ARGUMENT);
+ }
+
+ if ((ret = _dwarf_attr_alloc(die, &at, error)) != DW_DLE_NONE)
+ return (ret);
+
+ at->at_die = die;
+ at->at_attrib = attr;
+ at->at_form = DW_FORM_strp;
+ if ((ret = _dwarf_strtab_add(dbg, string, &at->u[0].u64,
+ error)) != DW_DLE_NONE) {
+ free(at);
+ return (ret);
+ }
+ at->u[1].s = _dwarf_strtab_get_table(dbg) + at->u[0].u64;
+
+ *atp = at;
+
+ STAILQ_INSERT_TAIL(&die->die_attr, at, at_next);
+
+ return (DW_DLE_NONE);
+}
+
+int
+_dwarf_attr_gen(Dwarf_P_Debug dbg, Dwarf_P_Section ds, Dwarf_Rel_Section drs,
+ Dwarf_CU cu, Dwarf_Die die, int pass2, Dwarf_Error *error)
+{
+ Dwarf_Attribute at;
+ int ret;
+
+ assert(dbg != NULL && ds != NULL && cu != NULL && die != NULL);
+
+ STAILQ_FOREACH(at, &die->die_attr, at_next) {
+ ret = _dwarf_attr_write(dbg, ds, drs, cu, at, pass2, error);
+ if (ret != DW_DLE_NONE)
+ return (ret);
+ }
+
+ return (DW_DLE_NONE);
+}