static int get_member_offset(Dwarf_Die *memdie, Dwarf_Word *off_out) { Dwarf_Attribute loc_attr; Dwarf_Block block; if (dwarf_attr_integrate(memdie, DW_AT_data_member_location, &loc_attr) == NULL) dwarf_err(EX_DATAERR, "dwarf_attr_integrate(%s/loc)", dwarf_diename(memdie)); switch (dwarf_whatform(&loc_attr)) { case DW_FORM_block: case DW_FORM_block1: case DW_FORM_block2: case DW_FORM_block4: if (dwarf_formblock(&loc_attr, &block)) dwarf_err(EX_DATAERR, "dwarf_formblock(%s)", dwarf_diename(memdie)); assert(block.data[0] == DW_OP_plus_uconst || block.data[0] == DW_OP_constu); get_uleb128(off_out, &block.data[1]); return (0); default: printf("ZZZ!\n"); return (-1); } }
/* 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; }
static VALUE rd_attr_form(VALUE self) { rd_attr_t *attr = GetAttr(self); Dwarf_Half form_type; Dwarf_Error err; chkerr1(dwarf_whatform(attr->attr, &form_type, &err), &err, self); return rb_hash_aref(rdwarf_form2name, INT2FIX(form_type)); }
/** \brief Initialize the location of a member of a type * (DW_AT_data_member_location of a DW_TAG_member). * * \param type a type (struct, class) * \param member the member of the type * \param child DIE of the member (DW_TAG_member) */ static void MC_dwarf_fill_member_location( simgrid::mc::Type* type, simgrid::mc::Member* member, Dwarf_Die * child) { if (dwarf_hasattr(child, DW_AT_data_bit_offset)) xbt_die("Can't groke DW_AT_data_bit_offset."); if (not dwarf_hasattr_integrate(child, DW_AT_data_member_location)) { if (type->type == DW_TAG_union_type) return; xbt_die ("Missing DW_AT_data_member_location field in DW_TAG_member %s of type <%" PRIx64 ">%s", member->name.c_str(), (uint64_t) type->id, type->name.c_str()); } Dwarf_Attribute attr; dwarf_attr_integrate(child, DW_AT_data_member_location, &attr); int form = dwarf_whatform(&attr); simgrid::dwarf::FormClass form_class = simgrid::dwarf::classify_form(form); switch (form_class) { case simgrid::dwarf::FormClass::ExprLoc: case simgrid::dwarf::FormClass::Block: // Location expression: { Dwarf_Op *expr; size_t len; if (dwarf_getlocation(&attr, &expr, &len)) xbt_die ("Could not read location expression DW_AT_data_member_location in DW_TAG_member %s of type <%" PRIx64 ">%s", MC_dwarf_attr_integrate_string(child, DW_AT_name), (uint64_t) type->id, type->name.c_str()); member->location_expression = simgrid::dwarf::DwarfExpression(expr, expr+len); break; } case simgrid::dwarf::FormClass::Constant: // Offset from the base address of the object: { Dwarf_Word offset; if (not dwarf_formudata(&attr, &offset)) member->offset(offset); else xbt_die("Cannot get %s location <%" PRIx64 ">%s", MC_dwarf_attr_integrate_string(child, DW_AT_name), (uint64_t) type->id, type->name.c_str()); break; } default: // includes FormClass::LocListPtr (reference to a location list: TODO) and FormClass::Reference (it's supposed to be // possible in DWARF2 but I couldn't find its semantic in the spec) xbt_die("Can't handle form class (%d) / form 0x%x as DW_AT_member_location", (int)form_class, (unsigned)form); } }
/* 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; }
static VALUE rd_attr_inspect(VALUE self) { rd_attr_t *attr = GetAttr(self); Dwarf_Half form; Dwarf_Error err; const char *form_name = "?"; if (dwarf_whatform(attr->attr, &form, &err) == DW_DLV_OK) { dwarf_get_FORM_name(form, &form_name); } return rb_sprintf("#<%s: %s>", rb_obj_classname(self), form_name); }
static Dwarf_Half die_attr_form(dwarf_t *dw, Dwarf_Attribute attr) { Dwarf_Half form; if (dwarf_whatform(attr, &form, &dw->dw_err) == DW_DLV_OK) return (form); terminate("failed to get attribute form for type: %s\n", dwarf_errmsg(dw->dw_err)); /*NOTREACHED*/ return (0); }
/* 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); }
Dwarf_Off DieHolder::get_ref_from_attr(int attr) { Dwarf_Off offset = 0; Dwarf_Half form = 0; Dwarf_Error err = NULL; Dwarf_Attribute attrib = get_attr(attr); CHECK_DWERR2(attrib == NULL, NULL, "cannot find DIE attribute %d\n", attr); CHECK_DWERR(dwarf_whatform(attrib, &form, &err), err, "cannot get form of the DIE attribute %d", attr); switch(form) { case DW_FORM_ref_addr: CHECK_DWERR(dwarf_global_formref(attrib, &offset, &err), err, "cannot get global reference address"); break; case DW_FORM_ref1: case DW_FORM_ref2: case DW_FORM_ref4: case DW_FORM_ref8: case DW_FORM_ref_udata: { Dwarf_Off cu_offset = 0; Dwarf_Off cu_length = 0; CHECK_DWERR(dwarf_formref(attrib, &offset, &err), err, "cannot get reference address"); cu_offset = get_CU_offset_range(&cu_length); offset += cu_offset; } break; default: THROW_DWERR("unknown reference form=%d\n", form); break; } return offset; }
/* * Handle DWARF 4 'offset from' DW_AT_high_pc. Although we don't * fully support DWARF 4, some compilers (like FreeBSD Clang 3.5.1) * generate DW_AT_high_pc as an offset from DW_AT_low_pc. * * "If the value of the DW_AT_high_pc is of class address, it is the * relocated address of the first location past the last instruction * associated with the entity; if it is of class constant, the value * is an unsigned integer offset which when added to the low PC gives * the address of the first location past the last instruction * associated with the entity." * * DWARF4 spec, section 2.17.2. */ static int handle_high_pc(Dwarf_Die die, Dwarf_Unsigned lopc, Dwarf_Unsigned *hipc) { Dwarf_Error de; Dwarf_Half form; Dwarf_Attribute at; int ret; ret = dwarf_attr(die, DW_AT_high_pc, &at, &de); if (ret == DW_DLV_ERROR) { warnx("dwarf_attr failed: %s", dwarf_errmsg(de)); return (ret); } ret = dwarf_whatform(at, &form, &de); if (ret == DW_DLV_ERROR) { warnx("dwarf_whatform failed: %s", dwarf_errmsg(de)); return (ret); } if (dwarf_get_form_class(2, 0, 0, form) == DW_FORM_CLASS_CONSTANT) *hipc += lopc; return (DW_DLV_OK); }
static void MC_dwarf_handle_scope_die(simgrid::mc::ObjectInformation* info, Dwarf_Die * die, Dwarf_Die * unit, simgrid::mc::Frame* parent_frame, const char *ns) { // TODO, handle DW_TAG_type/DW_TAG_location for DW_TAG_with_stmt int tag = dwarf_tag(die); simgrid::dwarf::TagClass klass = simgrid::dwarf::classify_tag(tag); // (Template) Subprogram declaration: if (klass == simgrid::dwarf::TagClass::Subprogram && MC_dwarf_attr_flag(die, DW_AT_declaration, false)) return; if (klass == simgrid::dwarf::TagClass::Scope) xbt_assert(parent_frame, "No parent scope for this scope"); simgrid::mc::Frame frame; frame.tag = tag; frame.id = dwarf_dieoffset(die); frame.object_info = info; if (klass == simgrid::dwarf::TagClass::Subprogram) { const char *name = MC_dwarf_attr_integrate_string(die, DW_AT_name); if (name && ns) frame.name = std::string(ns) + "::" + name; else if (name) frame.name = name; } frame.abstract_origin_id = MC_dwarf_attr_dieoffset(die, DW_AT_abstract_origin); // This is the base address for DWARF addresses. // Relocated addresses are offset from this base address. // See DWARF4 spec 7.5 std::uint64_t base = (std::uint64_t) info->base_address(); // TODO, support DW_AT_ranges uint64_t low_pc = MC_dwarf_attr_integrate_addr(die, DW_AT_low_pc); frame.range.begin() = low_pc ? (std::uint64_t) base + low_pc : 0; if (low_pc) { // DW_AT_high_pc: Dwarf_Attribute attr; if (not dwarf_attr_integrate(die, DW_AT_high_pc, &attr)) xbt_die("Missing DW_AT_high_pc matching with DW_AT_low_pc"); Dwarf_Sword offset; Dwarf_Addr high_pc; switch (simgrid::dwarf::classify_form(dwarf_whatform(&attr))) { // DW_AT_high_pc if an offset from the low_pc: case simgrid::dwarf::FormClass::Constant: if (dwarf_formsdata(&attr, &offset) != 0) xbt_die("Could not read constant"); frame.range.end() = frame.range.begin() + offset; break; // DW_AT_high_pc is a relocatable address: case simgrid::dwarf::FormClass::Address: if (dwarf_formaddr(&attr, &high_pc) != 0) xbt_die("Could not read address"); frame.range.end() = base + high_pc; break; default: xbt_die("Unexpected class for DW_AT_high_pc"); } } if (klass == simgrid::dwarf::TagClass::Subprogram) { Dwarf_Attribute attr_frame_base; if (dwarf_attr_integrate(die, DW_AT_frame_base, &attr_frame_base)) frame.frame_base_location = simgrid::dwarf::location_list(*info, attr_frame_base); } // Handle children: MC_dwarf_handle_children(info, die, unit, &frame, ns); // We sort them in order to have an (somewhat) efficient by name // lookup: boost::range::sort(frame.variables, MC_compare_variable); // Register it: if (klass == simgrid::dwarf::TagClass::Subprogram) info->subprograms[frame.id] = std::move(frame); else if (klass == simgrid::dwarf::TagClass::Scope) parent_frame->scopes.push_back(std::move(frame)); }
static std::unique_ptr<simgrid::mc::Variable> MC_die_to_variable( simgrid::mc::ObjectInformation* info, Dwarf_Die * die, Dwarf_Die * unit, simgrid::mc::Frame* frame, const char *ns) { // Skip declarations: if (MC_dwarf_attr_flag(die, DW_AT_declaration, false)) return nullptr; // Skip compile time constants: if (dwarf_hasattr(die, DW_AT_const_value)) return nullptr; Dwarf_Attribute attr_location; if (dwarf_attr(die, DW_AT_location, &attr_location) == nullptr) // No location: do not add it ? return nullptr; std::unique_ptr<simgrid::mc::Variable> variable = std::unique_ptr<simgrid::mc::Variable>(new simgrid::mc::Variable()); variable->id = dwarf_dieoffset(die); variable->global = frame == nullptr; // Can be override base on DW_AT_location variable->object_info = info; const char *name = MC_dwarf_attr_integrate_string(die, DW_AT_name); if (name) variable->name = name; variable->type_id = MC_dwarf_at_type(die); int form = dwarf_whatform(&attr_location); simgrid::dwarf::FormClass form_class; if (form == DW_FORM_sec_offset) form_class = simgrid::dwarf::FormClass::Constant; else form_class = simgrid::dwarf::classify_form(form); switch (form_class) { case simgrid::dwarf::FormClass::ExprLoc: case simgrid::dwarf::FormClass::Block: // Location expression: { Dwarf_Op *expr; size_t len; if (dwarf_getlocation(&attr_location, &expr, &len)) { xbt_die( "Could not read location expression in DW_AT_location " "of variable <%" PRIx64 ">%s", (uint64_t) variable->id, variable->name.c_str()); } if (len == 1 && expr[0].atom == DW_OP_addr) { variable->global = true; uintptr_t offset = (uintptr_t) expr[0].number; uintptr_t base = (uintptr_t) info->base_address(); variable->address = (void *) (base + offset); } else variable->location_list = { simgrid::dwarf::LocationListEntry(simgrid::dwarf::DwarfExpression(expr, expr + len))}; break; } case simgrid::dwarf::FormClass::LocListPtr: case simgrid::dwarf::FormClass::Constant: // Reference to location list: variable->location_list = simgrid::dwarf::location_list( *info, attr_location); break; default: xbt_die("Unexpected form 0x%x (%i), class 0x%x (%i) list for location in <%" PRIx64 ">%s", (unsigned)form, form, (unsigned)form_class, (int)form_class, (uint64_t)variable->id, variable->name.c_str()); } // Handle start_scope: if (dwarf_hasattr(die, DW_AT_start_scope)) { Dwarf_Attribute attr; dwarf_attr(die, DW_AT_start_scope, &attr); int form = dwarf_whatform(&attr); simgrid::dwarf::FormClass form_class = simgrid::dwarf::classify_form(form); if (form_class == simgrid::dwarf::FormClass::Constant) { Dwarf_Word value; variable->start_scope = dwarf_formudata(&attr, &value) == 0 ? (size_t)value : 0; } else { // TODO: FormClass::RangeListPtr xbt_die("Unhandled form 0x%x, class 0x%X for DW_AT_start_scope of variable %s", (unsigned)form, (unsigned)form_class, name == nullptr ? "?" : name); } } if (ns && variable->global) variable->name = std::string(ns) + "::" + variable->name; // The current code needs a variable name, // generate a fake one: if (variable->name.empty()) { variable->name = "@anonymous#" + std::to_string(mc_anonymous_variable_index); mc_anonymous_variable_index++; } return variable; }
/* 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. */ static 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; /* 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_Sword i=0; Dwarf_Word u=0; /* These variables are used to decode leb128 numbers. Leb128_num holds the decoded number, and leb128_length is its length in bytes. */ Dwarf_Half attrform = 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; Dwarf_Half address_size = 0; Dwarf_Unsigned fission_offset = 0; /* The Dwarf_Debug this die belongs to. */ Dwarf_Debug dbg=0; Dwarf_CU_Context cu_context = 0; Dwarf_Line_Context line_context = 0; int resattr = DW_DLV_ERROR; int lres = DW_DLV_ERROR; int res = DW_DLV_ERROR; Dwarf_Small *line_ptr_actuals = 0; Dwarf_Small *line_ptr_end = 0; Dwarf_Small *section_start = 0; /* ***** BEGIN CODE ***** */ if (error != NULL) { *error = NULL; } CHECK_DIE(die, DW_DLV_ERROR); cu_context = die->di_cu_context; dbg = cu_context->cc_dbg; res = _dwarf_load_section(dbg, &dbg->de_debug_line,error); if (res != DW_DLV_OK) { return res; } if (!dbg->de_debug_line.dss_size) { return (DW_DLV_NO_ENTRY); } 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; } /* 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); } section_start = dbg->de_debug_line.dss_data; { Dwarf_Unsigned fission_size = 0; int resfis = _dwarf_get_fission_addition_die(die, DW_SECT_LINE, &fission_offset,&fission_size,error); if(resfis != DW_DLV_OK) { return resfis; } } orig_line_ptr = section_start + line_offset + fission_offset; line_ptr = orig_line_ptr; 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); } line_context = (Dwarf_Line_Context) _dwarf_get_alloc(dbg, DW_DLA_LINE_CONTEXT, 1); if (line_context == NULL) { _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return (DW_DLV_ERROR); } { Dwarf_Small *newlinep = 0; int dres = _dwarf_read_line_table_header(dbg, cu_context, section_start, line_ptr, dbg->de_debug_line.dss_size, &newlinep, line_context, &bogus_bytes_ptr, &bogus_bytes_count, error, err_count_out); if (dres == DW_DLV_ERROR) { dwarf_srclines_dealloc_b(line_context); return dres; } if (dres == DW_DLV_NO_ENTRY) { dwarf_srclines_dealloc_b(line_context); return dres; } line_ptr_end = line_context->lc_line_ptr_end; line_ptr = newlinep; if (line_context->lc_actuals_table_offset > 0) { line_ptr_actuals = line_context->lc_line_prologue_start + line_context->lc_actuals_table_offset; } } line_context->lc_compilation_directory = comp_dir; if (only_line_header) { /* Just checking for header errors, nothing more here.*/ dwarf_srclines_dealloc_b(line_context); return DW_DLV_OK; } dwarf_printf(dbg, "total line info length %ld bytes," " line offset 0x%" DW_PR_XZEROS DW_PR_DUx " %" DW_PR_DUu "\n", (long) line_context->lc_total_length, line_context->lc_section_offset, line_context->lc_section_offset); if (line_context->lc_version_number <= DW_LINE_VERSION5) { dwarf_printf(dbg, "line table version %d\n",(int) line_context->lc_version_number); } else { dwarf_printf(dbg, "line table version 0x%x\n",(int) line_context->lc_version_number); } dwarf_printf(dbg, "line table length field length %d prologue length %d\n", (int)line_context->lc_length_field_length, (int)line_context->lc_prologue_length); dwarf_printf(dbg, "compilation_directory %s\n", comp_dir ? ((char *) comp_dir) : ""); dwarf_printf(dbg, " min instruction length %d\n", (int) line_context->lc_minimum_instruction_length); if (line_context->lc_version_number == EXPERIMENTAL_LINE_TABLES_VERSION) { dwarf_printf(dbg, " actuals table offset " "0x%" DW_PR_XZEROS DW_PR_DUx " logicals table offset " "0x%" DW_PR_XZEROS DW_PR_DUx "\n", line_context->lc_actuals_table_offset, line_context->lc_logicals_table_offset); } if (line_context->lc_version_number == DW_LINE_VERSION5) { dwarf_printf(dbg, " segment selector size %d\n", (int) line_context->lc_segment_selector_size); dwarf_printf(dbg, " address size %d\n", (int) line_context->lc_address_size); } dwarf_printf(dbg, " default is stmt %d\n",(int)line_context->lc_default_is_stmt); dwarf_printf(dbg, " line base %d\n",(int)line_context->lc_line_base); dwarf_printf(dbg, " line_range %d\n",(int)line_context->lc_line_range); dwarf_printf(dbg, " opcode base %d\n",(int)line_context->lc_opcode_base); dwarf_printf(dbg, " standard opcode count %d\n",(int)line_context->lc_std_op_count); for (i = 1; i < line_context->lc_opcode_base; i++) { dwarf_printf(dbg, " opcode[%2d] length %d\n", (int) i, (int) line_context->lc_opcode_length_table[i - 1]); } dwarf_printf(dbg, " include directories count %d\n", (int) line_context->lc_include_directories_count); for (u = 0; u < line_context->lc_include_directories_count; ++u) { dwarf_printf(dbg, " include dir[%u] %s\n", (int) u, line_context->lc_include_directories[u]); } dwarf_printf(dbg, " files count %d\n", (int) line_context->lc_file_entry_count); if (line_context->lc_file_entry_count) { Dwarf_File_Entry fe = line_context->lc_file_entries; Dwarf_File_Entry fe2 = fe; unsigned fiu = 0; for (fiu = 0 ; fe2 ; fe2 = fe->fi_next,++fiu ) { Dwarf_Unsigned tlm2 = 0; Dwarf_Unsigned di = 0; Dwarf_Unsigned fl = 0; fe = fe2; tlm2 = fe->fi_time_last_mod; di = fe->fi_dir_index; fl = fe->fi_file_length; dwarf_printf(dbg, " file[%u] %s (file-number: %u) \n", (unsigned) fiu, (char *) fe->fi_file_name, (unsigned)(fiu+1)); dwarf_printf(dbg, " dir index %d\n", (int) di); { time_t tt = (time_t) tlm2; /* ctime supplies newline */ dwarf_printf(dbg, " last time 0x%x %s", (unsigned) tlm2, ctime(&tt)); } dwarf_printf(dbg, " file length %ld 0x%lx\n", (long) fl, (unsigned long) fl); } } if (line_context->lc_version_number == EXPERIMENTAL_LINE_TABLES_VERSION) { /* Print the subprograms list. */ Dwarf_Unsigned count = line_context->lc_subprogs_count; Dwarf_Unsigned exu = 0; Dwarf_Subprog_Entry sub = line_context->lc_subprogs; dwarf_printf(dbg," subprograms count" " %" DW_PR_DUu "\n",count); if (count > 0) { dwarf_printf(dbg," indx file line name\n"); } for (exu = 0 ; exu < count ; exu++,sub++) { dwarf_printf(dbg," [%2" DW_PR_DUu "] %4" DW_PR_DUu " %4" DW_PR_DUu " %s\n", exu+1, sub->ds_decl_file, sub->ds_decl_line, sub->ds_subprog_name); } } { Dwarf_Unsigned offset = 0; if (bogus_bytes_count > 0) { Dwarf_Unsigned wcount = bogus_bytes_count; Dwarf_Unsigned boffset = bogus_bytes_ptr - section_start; dwarf_printf(dbg, "*** DWARF CHECK: the line table prologue header_length " " is %" DW_PR_DUu " too high, we pretend it is smaller." "Section offset: 0x%" DW_PR_XZEROS DW_PR_DUx " (%" DW_PR_DUu ") ***\n", wcount, boffset,boffset); *err_count_out += 1; } offset = line_ptr - section_start; dwarf_printf(dbg, " statement prog offset in section: 0x%" DW_PR_XZEROS DW_PR_DUx " (%" DW_PR_DUu ")\n", offset, offset); } { Dwarf_Bool doaddrs = false; Dwarf_Bool dolines = true; _dwarf_print_line_context_record(dbg,line_context); if (!line_ptr_actuals) { /* Normal single level line table. */ Dwarf_Bool is_single_table = true; Dwarf_Bool is_actuals_table = false; print_line_header(dbg, is_single_table, is_actuals_table); res = read_line_table_program(dbg, line_ptr, line_ptr_end, orig_line_ptr, section_start, line_context, address_size, doaddrs, dolines, is_single_table, is_actuals_table, error, err_count_out); if (res != DW_DLV_OK) { dwarf_srclines_dealloc_b(line_context); return res; } } else { Dwarf_Bool is_single_table = false; Dwarf_Bool is_actuals_table = false; if (line_context->lc_version_number != EXPERIMENTAL_LINE_TABLES_VERSION) { dwarf_srclines_dealloc_b(line_context); _dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR); return (DW_DLV_ERROR); } /* Read Logicals */ print_line_header(dbg, is_single_table, is_actuals_table); res = read_line_table_program(dbg, line_ptr, line_ptr_actuals, orig_line_ptr, section_start, line_context, address_size, doaddrs, dolines, is_single_table, is_actuals_table, error,err_count_out); if (res != DW_DLV_OK) { dwarf_srclines_dealloc_b(line_context); return res; } if (line_context->lc_actuals_table_offset > 0) { is_actuals_table = true; /* Read Actuals */ print_line_header(dbg, is_single_table, is_actuals_table); res = read_line_table_program(dbg, line_ptr_actuals, line_ptr_end, orig_line_ptr, section_start, line_context, address_size, doaddrs, dolines, is_single_table, is_actuals_table, error, err_count_out); if (res != DW_DLV_OK) { dwarf_srclines_dealloc_b(line_context); return res; } } } } dwarf_srclines_dealloc_b(line_context); return DW_DLV_OK; }
void handle (Dwarf *dbg, Dwarf_Die *die, int n) { Dwarf_Die child; unsigned int tag; const char *str; char buf[30]; const char *name; Dwarf_Off off; Dwarf_Off cuoff; size_t cnt; Dwarf_Addr addr; int i; tag = dwarf_tag (die); if (tag != DW_TAG_invalid) { if (tag < ntagnames) str = tagnames[tag]; else { snprintf (buf, sizeof buf, "%#x", tag); str = buf; } } else str = "* NO TAG *"; name = dwarf_diename (die); if (name == 0) name = "* NO NAME *"; off = dwarf_dieoffset (die); cuoff = dwarf_cuoffset (die); printf ("%*s%s\n", n * 5, "", str); printf ("%*s Name : %s\n", n * 5, "", name); printf ("%*s Offset : %lld\n", n * 5, "", (long long int) off); printf ("%*s CU offset : %lld\n", n * 5, "", (long long int) cuoff); printf ("%*s Attrs :", n * 5, ""); for (cnt = 0; cnt < nattrs; ++cnt) if (dwarf_hasattr (die, attrs[cnt].code)) printf (" %s", attrs[cnt].name); puts (""); if (dwarf_hasattr (die, DW_AT_low_pc) && dwarf_lowpc (die, &addr) == 0) { Dwarf_Attribute attr; Dwarf_Addr addr2; printf ("%*s low PC : %#llx\n", n * 5, "", (unsigned long long int) addr); if (dwarf_attr (die, DW_AT_low_pc, &attr) == NULL || dwarf_formaddr (&attr, &addr2) != 0 || addr != addr2) puts ("************* DW_AT_low_pc verify failed ************"); else if (! dwarf_hasform (&attr, DW_FORM_addr)) puts ("************* DW_AT_low_pc form failed ************"); else if (dwarf_whatform (&attr) != DW_FORM_addr) puts ("************* DW_AT_low_pc form (2) failed ************"); else if (dwarf_whatattr (&attr) != DW_AT_low_pc) puts ("************* DW_AT_low_pc attr failed ************"); } if (dwarf_hasattr (die, DW_AT_high_pc) && dwarf_highpc (die, &addr) == 0) { Dwarf_Attribute attr; Dwarf_Addr addr2; printf ("%*s high PC : %#llx\n", n * 5, "", (unsigned long long int) addr); if (dwarf_attr (die, DW_AT_high_pc, &attr) == NULL || dwarf_formaddr (&attr, &addr2) != 0 || addr != addr2) puts ("************* DW_AT_high_pc verify failed ************"); else if (! dwarf_hasform (&attr, DW_FORM_addr)) puts ("************* DW_AT_high_pc form failed ************"); else if (dwarf_whatform (&attr) != DW_FORM_addr) puts ("************* DW_AT_high_pc form (2) failed ************"); else if (dwarf_whatattr (&attr) != DW_AT_high_pc) puts ("************* DW_AT_high_pc attr failed ************"); } if (dwarf_hasattr (die, DW_AT_byte_size) && (i = dwarf_bytesize (die)) != -1) { Dwarf_Attribute attr; Dwarf_Word u2; unsigned int u; printf ("%*s byte size : %d\n", n * 5, "", i); if (dwarf_attr (die, DW_AT_byte_size, &attr) == NULL || dwarf_formudata (&attr, &u2) != 0 || i != (int) u2) puts ("************* DW_AT_byte_size verify failed ************"); else if (! dwarf_hasform (&attr, DW_FORM_data1) && ! dwarf_hasform (&attr, DW_FORM_data2) && ! dwarf_hasform (&attr, DW_FORM_data4) && ! dwarf_hasform (&attr, DW_FORM_data8) && ! dwarf_hasform (&attr, DW_FORM_sdata) && ! dwarf_hasform (&attr, DW_FORM_udata)) puts ("************* DW_AT_byte_size form failed ************"); else if ((u = dwarf_whatform (&attr)) == 0 || (u != DW_FORM_data1 && u != DW_FORM_data2 && u != DW_FORM_data4 && u != DW_FORM_data8 && u != DW_FORM_sdata && u != DW_FORM_udata)) puts ("************* DW_AT_byte_size form (2) failed ************"); else if (dwarf_whatattr (&attr) != DW_AT_byte_size) puts ("************* DW_AT_byte_size attr failed ************"); } if (dwarf_hasattr (die, DW_AT_bit_size) && (i = dwarf_bitsize (die)) != -1) { Dwarf_Attribute attr; Dwarf_Word u2; unsigned int u; printf ("%*s bit size : %d\n", n * 5, "", i); if (dwarf_attr (die, DW_AT_bit_size, &attr) == NULL || dwarf_formudata (&attr, &u2) != 0 || i != (int) u2) puts ("************* DW_AT_bit_size test failed ************"); else if (! dwarf_hasform (&attr, DW_FORM_data1) && ! dwarf_hasform (&attr, DW_FORM_data2) && ! dwarf_hasform (&attr, DW_FORM_data4) && ! dwarf_hasform (&attr, DW_FORM_data8) && ! dwarf_hasform (&attr, DW_FORM_sdata) && ! dwarf_hasform (&attr, DW_FORM_udata)) puts ("************* DW_AT_bit_size form failed ************"); else if ((u = dwarf_whatform (&attr)) == 0 || (u != DW_FORM_data1 && u != DW_FORM_data2 && u != DW_FORM_data4 && u != DW_FORM_data8 && u != DW_FORM_sdata && u != DW_FORM_udata)) puts ("************* DW_AT_bit_size form (2) failed ************"); else if (dwarf_whatattr (&attr) != DW_AT_bit_size) puts ("************* DW_AT_bit_size attr failed ************"); } if (dwarf_hasattr (die, DW_AT_bit_offset) && (i = dwarf_bitoffset (die)) != -1) { Dwarf_Attribute attr; Dwarf_Word u2; unsigned int u; printf ("%*s bit offset: %d\n", n * 5, "", i); if (dwarf_attr (die, DW_AT_bit_offset, &attr) == NULL || dwarf_formudata (&attr, &u2) != 0 || i != (int) u2) puts ("************* DW_AT_bit_offset test failed ************"); else if (! dwarf_hasform (&attr, DW_FORM_data1) && ! dwarf_hasform (&attr, DW_FORM_data2) && ! dwarf_hasform (&attr, DW_FORM_data4) && ! dwarf_hasform (&attr, DW_FORM_data8) && ! dwarf_hasform (&attr, DW_FORM_sdata) && ! dwarf_hasform (&attr, DW_FORM_udata)) puts ("************* DW_AT_bit_offset form failed ************"); else if ((u = dwarf_whatform (&attr)) == 0 || (u != DW_FORM_data1 && u != DW_FORM_data2 && u != DW_FORM_data4 && u != DW_FORM_data8 && u != DW_FORM_sdata && u != DW_FORM_udata)) puts ("************* DW_AT_bit_offset form (2) failed ************"); else if (dwarf_whatattr (&attr) != DW_AT_bit_offset) puts ("************* DW_AT_bit_offset attr failed ************"); } if (dwarf_hasattr (die, DW_AT_language) && (i = dwarf_srclang (die)) != -1) { Dwarf_Attribute attr; Dwarf_Word u2; unsigned int u; printf ("%*s language : %d\n", n * 5, "", i); if (dwarf_attr (die, DW_AT_language, &attr) == NULL || dwarf_formudata (&attr, &u2) != 0 || i != (int) u2) puts ("************* DW_AT_language test failed ************"); else if (! dwarf_hasform (&attr, DW_FORM_data1) && ! dwarf_hasform (&attr, DW_FORM_data2) && ! dwarf_hasform (&attr, DW_FORM_data4) && ! dwarf_hasform (&attr, DW_FORM_data8) && ! dwarf_hasform (&attr, DW_FORM_sdata) && ! dwarf_hasform (&attr, DW_FORM_udata)) puts ("************* DW_AT_language form failed ************"); else if ((u = dwarf_whatform (&attr)) == 0 || (u != DW_FORM_data1 && u != DW_FORM_data2 && u != DW_FORM_data4 && u != DW_FORM_data8 && u != DW_FORM_sdata && u != DW_FORM_udata)) puts ("************* DW_AT_language form (2) failed ************"); else if (dwarf_whatattr (&attr) != DW_AT_language) puts ("************* DW_AT_language attr failed ************"); } if (dwarf_hasattr (die, DW_AT_ordering) && (i = dwarf_arrayorder (die)) != -1) { Dwarf_Attribute attr; Dwarf_Word u2; unsigned int u; printf ("%*s ordering : %d\n", n * 5, "", i); if (dwarf_attr (die, DW_AT_ordering, &attr) == NULL || dwarf_formudata (&attr, &u2) != 0 || i != (int) u2) puts ("************* DW_AT_ordering test failed ************"); else if (! dwarf_hasform (&attr, DW_FORM_data1) && ! dwarf_hasform (&attr, DW_FORM_data2) && ! dwarf_hasform (&attr, DW_FORM_data4) && ! dwarf_hasform (&attr, DW_FORM_data8) && ! dwarf_hasform (&attr, DW_FORM_sdata) && ! dwarf_hasform (&attr, DW_FORM_udata)) puts ("************* DW_AT_ordering failed ************"); else if ((u = dwarf_whatform (&attr)) == 0 || (u != DW_FORM_data1 && u != DW_FORM_data2 && u != DW_FORM_data4 && u != DW_FORM_data8 && u != DW_FORM_sdata && u != DW_FORM_udata)) puts ("************* DW_AT_ordering form (2) failed ************"); else if (dwarf_whatattr (&attr) != DW_AT_ordering) puts ("************* DW_AT_ordering attr failed ************"); } if (dwarf_hasattr (die, DW_AT_comp_dir)) { Dwarf_Attribute attr; if (dwarf_attr (die, DW_AT_comp_dir, &attr) == NULL || (name = dwarf_formstring (&attr)) == NULL) puts ("************* DW_AT_comp_dir attr failed ************"); else printf ("%*s directory : %s\n", n * 5, "", name); } if (dwarf_hasattr (die, DW_AT_producer)) { Dwarf_Attribute attr; if (dwarf_attr (die, DW_AT_producer, &attr) == NULL || (name = dwarf_formstring (&attr)) == NULL) puts ("************* DW_AT_comp_dir attr failed ************"); else printf ("%*s producer : %s\n", n * 5, "", name); } if (dwarf_haschildren (die) != 0 && dwarf_child (die, &child) == 0) handle (dbg, &child, n + 1); if (dwarf_siblingof (die, die) == 0) handle (dbg, die, n); }
static void print_expr (Dwarf_Attribute *attr, Dwarf_Op *expr, Dwarf_Addr addr) { uint8_t atom = expr->atom; const char *opname = dwarf_opcode_string (atom); assert (opname != NULL); switch (atom) { case DW_OP_deref: case DW_OP_dup: case DW_OP_drop: case DW_OP_over: case DW_OP_swap: case DW_OP_rot: case DW_OP_xderef: 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: case DW_OP_shl: case DW_OP_shr: case DW_OP_shra: case DW_OP_xor: case DW_OP_eq: case DW_OP_ge: case DW_OP_gt: case DW_OP_le: case DW_OP_lt: case DW_OP_ne: case DW_OP_lit0 ... DW_OP_lit31: case DW_OP_reg0 ... DW_OP_reg31: case DW_OP_nop: case DW_OP_stack_value: /* No arguments. */ printf ("%s", opname); break; case DW_OP_form_tls_address: /* No arguments. Special. Pops an address and pushes the corresponding address in the current thread local storage. Uses the thread local storage block of the defining module (executable, shared library). */ printf ("%s", opname); break; case DW_OP_GNU_push_tls_address: /* No arguments. Special. Not the same as DW_OP_form_tls_address. Pops an offset into the current thread local strorage and pushes back the actual address. */ printf ("%s", opname); break; case DW_OP_call_frame_cfa: /* No arguments. Special. Pushes Call Frame Address as computed by CFI data (dwarf_cfi_addrframe will fetch that info (either from the .eh_frame or .debug_frame CFI) and dwarf_frame_cfa translatesr the CFI instructions into a plain DWARF expression. Never used in CFI itself. */ if (attr == NULL) error (EXIT_FAILURE, 0, "%s used in CFI", opname); printf ("%s ", opname); if (cfi_eh == NULL && cfi_debug == NULL) error (EXIT_FAILURE, 0, "DW_OP_call_frame_cfa used but no cfi found."); Dwarf_Frame *frame; if (dwarf_cfi_addrframe (cfi_eh, addr + cfi_eh_bias, &frame) != 0 && dwarf_cfi_addrframe (cfi_debug, addr, &frame) != 0) error (EXIT_FAILURE, 0, "dwarf_cfi_addrframe 0x%" PRIx64 ": %s", addr, dwarf_errmsg (-1)); Dwarf_Op *cfa_ops; size_t cfa_nops; if (dwarf_frame_cfa (frame, &cfa_ops, &cfa_nops) != 0) error (EXIT_FAILURE, 0, "dwarf_frame_cfa 0x%" PRIx64 ": %s", addr, dwarf_errmsg (-1)); if (cfa_nops < 1) error (EXIT_FAILURE, 0, "dwarf_frame_cfa no ops"); print_expr_block (NULL, cfa_ops, cfa_nops, 0); free (frame); break; case DW_OP_push_object_address: /* No arguments. Special. Pushes object address explicitly. Normally only done implicitly by DW_AT_data_member_location. Never used in CFI. */ if (attr == NULL) error (EXIT_FAILURE, 0, "%s used in CFI", opname); printf ("%s", opname); break; case DW_OP_addr: /* 1 address argument. */ printf ("%s(0x%" PRIx64 ")", opname, (Dwarf_Addr) expr->number); break; case DW_OP_const1u: case DW_OP_const2u: case DW_OP_const4u: case DW_OP_const8u: case DW_OP_constu: case DW_OP_pick: case DW_OP_plus_uconst: case DW_OP_regx: case DW_OP_piece: case DW_OP_deref_size: case DW_OP_xderef_size: /* 1 numeric unsigned argument. */ printf ("%s(%" PRIu64 ")", opname, expr->number); break; case DW_OP_call2: case DW_OP_call4: case DW_OP_call_ref: /* 1 DIE offset argument for more ops in location attribute of DIE. Never used in CFI. */ { if (attr == NULL) error (EXIT_FAILURE, 0, "%s used in CFI", opname); Dwarf_Attribute call_attr; if (dwarf_getlocation_attr (attr, expr, &call_attr) != 0) error (EXIT_FAILURE, 0, "dwarf_getlocation_attr for %s error %s", opname, dwarf_errmsg (-1)); Dwarf_Die call_die; if (dwarf_getlocation_die (attr, expr, &call_die) != 0) error (EXIT_FAILURE, 0, "dwarf_getlocation_die for %s error %s", opname, dwarf_errmsg (-1)); Dwarf_Op *call_ops; size_t call_len; if (dwarf_getlocation (&call_attr, &call_ops, &call_len) != 0) error (EXIT_FAILURE, 0, "dwarf_getlocation for entry: %s", dwarf_errmsg (-1)); printf ("%s([%" PRIx64 "]) ", opname, dwarf_dieoffset (&call_die)); print_expr_block (&call_attr, call_ops, call_len, addr); } break; case DW_OP_const1s: case DW_OP_const2s: case DW_OP_const4s: case DW_OP_const8s: case DW_OP_consts: case DW_OP_skip: case DW_OP_bra: case DW_OP_breg0 ... DW_OP_breg31: /* 1 numeric signed argument. */ printf ("%s(%" PRId64 ")", opname, (Dwarf_Sword) expr->number); break; case DW_OP_fbreg: /* 1 numeric signed argument. Offset from frame base. */ if (attr == NULL) error (EXIT_FAILURE, 0, "%s used in CFI", opname); if (! has_frame_base) error (EXIT_FAILURE, 0, "DW_OP_fbreg used without a frame base"); printf ("%s(%" PRId64 ")", opname, (Dwarf_Sword) expr->number); break; case DW_OP_bregx: /* 2 arguments, unsigned register number, signed offset. */ printf ("%s(%" PRIu64 ",%" PRId64 ")", opname, expr->number, (Dwarf_Sword) expr->number2); break; case DW_OP_bit_piece: /* 2 arguments, unsigned size, unsigned offset. */ printf ("%s(%" PRIu64 ",%" PRIu64 ")", opname, expr->number, expr->number2); break; case DW_OP_implicit_value: /* Special, unsigned size plus block. */ { Dwarf_Attribute const_attr; Dwarf_Block block; if (dwarf_getlocation_attr (attr, expr, &const_attr) != 0) error (EXIT_FAILURE, 0, "dwarf_getlocation_attr: %s", dwarf_errmsg (-1)); if (dwarf_formblock (&const_attr, &block) != 0) error (EXIT_FAILURE, 0, "dwarf_formblock: %s", dwarf_errmsg (-1)); /* This is the "old" way. Check they result in the same. */ Dwarf_Block block_impl; if (dwarf_getlocation_implicit_value (attr, expr, &block_impl) != 0) error (EXIT_FAILURE, 0, "dwarf_getlocation_implicit_value: %s", dwarf_errmsg (-1)); assert (expr->number == block.length); assert (block.length == block_impl.length); printf ("%s(%" PRIu64 "){", opname, block.length); for (size_t i = 0; i < block.length; i++) { printf ("%02x", block.data[i]); assert (block.data[i] == block_impl.data[i]); } printf("}"); } break; case DW_OP_GNU_implicit_pointer: /* Special, DIE offset, signed offset. Referenced DIE has a location or const_value attribute. */ { if (attr == NULL) error (EXIT_FAILURE, 0, "%s used in CFI", opname); Dwarf_Attribute attrval; if (dwarf_getlocation_implicit_pointer (attr, expr, &attrval) != 0) error (EXIT_FAILURE, 0, "dwarf_getlocation_implicit_pointer: %s", dwarf_errmsg (-1)); // Sanity check, results should be the same. Dwarf_Attribute attrval2; if (dwarf_getlocation_attr (attr, expr, &attrval2) != 0) error (EXIT_FAILURE, 0, "dwarf_getlocation_attr: %s", dwarf_errmsg (-1)); assert (dwarf_whatattr (&attrval) == dwarf_whatattr (&attrval2)); assert (dwarf_whatform (&attrval) == dwarf_whatform (&attrval2)); // In theory two different valp pointers could point to the same // value. But here we really expect them to be the equal. assert (attrval.valp == attrval2.valp); Dwarf_Die impl_die; if (dwarf_getlocation_die (attr, expr, &impl_die) != 0) error (EXIT_FAILURE, 0, "dwarf_getlocation_due: %s", dwarf_errmsg (-1)); printf ("%s([%" PRIx64 "],%" PRId64 ") ", opname, dwarf_dieoffset (&impl_die), expr->number2); if (dwarf_whatattr (&attrval) == DW_AT_const_value) printf ("<constant value>"); // Lookup type... else { // Lookup the location description at the current address. Dwarf_Op *exprval; size_t exprval_len; int locs = dwarf_getlocation_addr (&attrval, addr, &exprval, &exprval_len, 1); if (locs == 0) printf ("<no location>"); // This means "optimized out". else if (locs == 1) print_expr_block (&attrval, exprval, exprval_len, addr); else error (EXIT_FAILURE, 0, "dwarf_getlocation_addr attrval at addr 0x%" PRIx64 ", locs (%d): %s", addr, locs, dwarf_errmsg (-1)); } } break; case DW_OP_GNU_entry_value: /* Special, unsigned size plus expression block. All registers inside the block should be interpreted as they had on entering the function. dwarf_getlocation_attr will return an attribute containing the block as locexpr which can be retrieved with dwarf_getlocation. */ { Dwarf_Attribute entry_attr; if (dwarf_getlocation_attr (attr, expr, &entry_attr) != 0) error (EXIT_FAILURE, 0, "dwarf_getlocation_attr: %s", dwarf_errmsg (-1)); Dwarf_Op *entry_ops; size_t entry_len; if (dwarf_getlocation (&entry_attr, &entry_ops, &entry_len) != 0) error (EXIT_FAILURE, 0, "dwarf_getlocation for entry: %s", dwarf_errmsg (-1)); printf ("%s(%zd) ", opname, entry_len); print_expr_block (attr, entry_ops, entry_len, addr); } break; case DW_OP_GNU_parameter_ref: /* Special, unsigned CU relative DIE offset pointing to a DW_TAG_formal_parameter. The value that parameter had at the call site of the current function will be put on the DWARF stack. The value can be retrieved by finding the DW_TAG_GNU_call_site_parameter which has as DW_AT_abstract_origin the same formal parameter DIE. */ { Dwarf_Die param; if (dwarf_getlocation_die (attr, expr, ¶m) != 0) error (EXIT_FAILURE, 0, "dwarf_getlocation_die: %s", dwarf_errmsg (-1)); // XXX actually lookup DW_TAG_GNU_call_site_parameter printf ("%s[%" PRIx64 "]", opname, dwarf_dieoffset (¶m)); assert (expr->number == dwarf_cuoffset (¶m)); assert (dwarf_tag (¶m) == DW_TAG_formal_parameter); } break; case DW_OP_GNU_convert: case DW_OP_GNU_reinterpret: /* Special, unsigned CU relative DIE offset pointing to a DW_TAG_base_type. Pops a value, converts or reinterprets the value to the given type. When the argument is zero the value becomes untyped again. */ { Dwarf_Die type; Dwarf_Off off = expr->number; if (off != 0) { if (dwarf_getlocation_die (attr, expr, &type) != 0) error (EXIT_FAILURE, 0, "dwarf_getlocation_die: %s", dwarf_errmsg (-1)); off = dwarf_dieoffset (&type); assert (expr->number == dwarf_cuoffset (&type)); printf ("%s", opname); print_base_type (&type); } else printf ("%s[%" PRIu64 "]", opname, off); } break; case DW_OP_GNU_regval_type: /* Special, unsigned register number plus unsigned CU relative DIE offset pointing to a DW_TAG_base_type. */ { Dwarf_Die type; if (dwarf_getlocation_die (attr, expr, &type) != 0) error (EXIT_FAILURE, 0, "dwarf_getlocation_die: %s", dwarf_errmsg (-1)); assert (expr->number2 == dwarf_cuoffset (&type)); // XXX check size against base_type size? printf ("%s(reg%" PRIu64 ")", opname, expr->number); print_base_type (&type); } break; case DW_OP_GNU_deref_type: /* Special, unsigned size plus unsigned CU relative DIE offset pointing to a DW_TAG_base_type. */ { Dwarf_Die type; if (dwarf_getlocation_die (attr, expr, &type) != 0) error (EXIT_FAILURE, 0, "dwarf_getlocation_die: %s", dwarf_errmsg (-1)); assert (expr->number2 == dwarf_cuoffset (&type)); // XXX check size against base_type size? printf ("%s(%" PRIu64 ")", opname, expr->number); print_base_type (&type); } break; case DW_OP_GNU_const_type: /* Special, unsigned CU relative DIE offset pointing to a DW_TAG_base_type, an unsigned size length plus a block with the constant value. */ { Dwarf_Die type; if (dwarf_getlocation_die (attr, expr, &type) != 0) error (EXIT_FAILURE, 0, "dwarf_getlocation_die: %s", dwarf_errmsg (-1)); assert (expr->number == dwarf_cuoffset (&type)); Dwarf_Attribute const_attr; if (dwarf_getlocation_attr (attr, expr, &const_attr) != 0) error (EXIT_FAILURE, 0, "dwarf_getlocation_attr for type: %s", dwarf_errmsg (-1)); Dwarf_Block block; if (dwarf_formblock (&const_attr, &block) != 0) error (EXIT_FAILURE, 0, "dwarf_formblock for type: %s", dwarf_errmsg (-1)); printf ("%s", opname); print_base_type (&type); printf ("(%" PRIu64 ")[", block.length); for (size_t i = 0; i < block.length; i++) printf ("%02x", block.data[i]); printf("]"); } break; default: error (EXIT_FAILURE, 0, "unhandled opcode: DW_OP_%s (0x%x)", opname, atom); } }
static void show_all_attrs(Dwarf_Die die, unsigned long level, void *ndata){ Dwarf_Error error; Dwarf_Half tag; dwarf_tag(die,&tag,&error); const char *stag; dwarf_get_TAG_name(tag,&stag); Dwarf_Off off = 0x0; dwarf_die_CU_offset(die,&off,&error); fprintf(stderr,"[%u]<%x>%s\n",level,off,stag); char **sourceFiles; Dwarf_Signed num; int res; if( (res = dwarf_srcfiles(die,&sourceFiles,&num,&error)) == DW_DLV_OK){ fprintf(stderr,"Source Files Referenced:\n"); int i; for(i = 0; i < num; i++){ fprintf(stderr,"%s\n",sourceFiles[i]); dwarf_dealloc(d, sourceFiles[i],DW_DLA_STRING); } dwarf_dealloc(d, sourceFiles,DW_DLA_LIST); } Dwarf_Unsigned atcnt; Dwarf_Attribute *atlist; int errv; if((errv = dwarf_attrlist(die, &atlist, &atcnt, &error)) == DW_DLV_OK){ int i; for(i = 0; i < atcnt; i++){ Dwarf_Half attr; if(dwarf_whatattr(atlist[i],&attr,&error) == DW_DLV_OK){ const char *sattr; dwarf_get_AT_name(attr,&sattr); fprintf(stderr,"\t%s => ",sattr); }else{ fprintf(stderr,"\tCouldn't Get Attr Type!\n"); continue; } Dwarf_Half form; if(dwarf_whatform(atlist[i],&form,&error) == DW_DLV_OK){ //const char *formname; //dwarf_get_FORM_name(form,&formname); //fprintf(stderr,"[%s] ",formname); switch(form){ case DW_FORM_ref1: case DW_FORM_ref2: case DW_FORM_ref4: case DW_FORM_ref8: case DW_FORM_ref_udata: {Dwarf_Off offset; dwarf_formref(atlist[i],&offset,&error); fprintf(stderr,"%x\n",offset);} break; case DW_FORM_ref_addr: {Dwarf_Off offset; dwarf_global_formref(atlist[i],&offset,&error); fprintf(stderr,"%x\n",offset);} break; case DW_FORM_addr: {Dwarf_Addr addr; dwarf_formaddr(atlist[i],&addr,&error); fprintf(stderr,"%x\n",addr);} break; case DW_FORM_flag: {Dwarf_Bool flag; dwarf_formflag(atlist[i],&flag,&error); fprintf(stderr,"%s\n",flag ? "True" : "False");} break; case DW_FORM_udata: case DW_FORM_data1: case DW_FORM_data2: case DW_FORM_data4: case DW_FORM_data8: {Dwarf_Unsigned val; dwarf_formudata(atlist[i],&val,&error); fprintf(stderr,"%u\n",val);} break; case DW_FORM_sdata: {Dwarf_Signed val; dwarf_formsdata(atlist[i],&val,&error); fprintf(stderr,"%d\n",val);} break; case DW_FORM_block: case DW_FORM_block1: if(attr == DW_AT_location || attr == DW_AT_data_member_location || attr == DW_AT_vtable_elem_location || attr == DW_AT_string_length || attr == DW_AT_use_location || attr == DW_AT_return_addr){ /* Dwarf_Locdesc *locationList; Dwarf_Signed listLength; int ret = dwarf_loclist( atlist[i], &locationList, &listLength, &error ); int frameRel = 0; long offset = 0; decode_location(locationList,listLength,&offset,NULL,&frameRel); int i; for( i = 0; i < listLength; ++i){ dwarf_dealloc(d,locationList[i].ld_s,DW_DLA_LOC_BLOCK); } dwarf_dealloc(d,locationList,DW_DLA_LOCDESC); */ DC_location dcl; DC_get_location_attr_value(atlist[i],&dcl); fprintf(stderr," %s:",dcl.isFrameOffset ? "FP Offset" : "Address"); fprintf(stderr," %ld\n",dcl.offset); }else{ fprintf(stderr,"UNSUPPORTED ATTRIBUTE TYPE\n"); } break; case DW_FORM_string: {char *val; dwarf_formstring(atlist[i],&val,&error); fprintf(stderr,"%s\n",val);} break; case DW_FORM_strp: {char *str; if( (dwarf_formstring(atlist[i],&str,&error) == DW_DLV_OK) ){ fprintf(stderr,"%s\n",str); } } break; default: fprintf(stderr,"Unhandled Attribute Form!\n"); break; }; } dwarf_dealloc(d, atlist[i], DW_DLA_ATTR); } dwarf_dealloc(d, atlist, DW_DLA_LIST); } }
/* 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; }
QVariant DwarfDie::attributeLocal(Dwarf_Half attributeType) const { Dwarf_Attribute attr; auto res = dwarf_attr(m_die, attributeType, &attr, nullptr); if (res != DW_DLV_OK) return {}; Dwarf_Half formType; res = dwarf_whatform(attr, &formType, nullptr); if (res != DW_DLV_OK) return {}; QVariant value; switch (formType) { case DW_FORM_data1: case DW_FORM_data2: case DW_FORM_data4: case DW_FORM_data8: case DW_FORM_udata: { Dwarf_Unsigned n; res = dwarf_formudata(attr, &n, nullptr); value = n; break; } case DW_FORM_sdata: { Dwarf_Signed n; res = dwarf_formsdata(attr, &n, nullptr); value = n; break; } case DW_FORM_string: case DW_FORM_strp: { char *str; res = dwarf_formstring(attr, &str, nullptr); value = QByteArray(str); break; } case DW_FORM_flag: case DW_FORM_flag_present: { Dwarf_Bool b; res = dwarf_formflag(attr, &b, nullptr); value = b ? true : false; break; } case DW_FORM_ref1: case DW_FORM_ref2: case DW_FORM_ref4: case DW_FORM_ref8: { Dwarf_Off offset; res = dwarf_global_formref(attr, &offset, nullptr); value = QVariant::fromValue(dwarfInfo()->dieAtOffset(offset)); break; } case DW_FORM_sec_offset: { Dwarf_Off offset; res = dwarf_global_formref(attr, &offset, nullptr); value = offset; break; } case DW_FORM_addr: { Dwarf_Addr addr; res = dwarf_formaddr(attr, &addr, nullptr); value = addr; break; } case DW_FORM_exprloc: { Dwarf_Unsigned len; Dwarf_Ptr block; res = dwarf_formexprloc(attr, &len, &block, nullptr); value = QVariant::fromValue(DwarfExpression(block, len, dwarfInfo()->elfFile()->addressSize())); break; } default: { const char* formName; res = dwarf_get_FORM_name(formType, &formName); if (res != DW_DLV_OK) return {}; value = QStringLiteral("TODO: ") + QString::fromLocal8Bit(formName); break; } } // post-process some well-known types switch (attributeType) { case DW_AT_decl_file: case DW_AT_call_file: { const auto fileIndex = value.value<Dwarf_Unsigned>(); // index 0 means not present, TODO handle that value = compilationUnit()->sourceFileForIndex(fileIndex -1); break; } case DW_AT_ranges: value = QVariant::fromValue(DwarfRanges(this, value.toLongLong())); break; case DW_AT_accessibility: stringifyEnum(value, &dwarf_get_ACCESS_name); break; case DW_AT_language: stringifyEnum(value, &dwarf_get_LANG_name); break; case DW_AT_virtuality: value = QVariant::fromValue(static_cast<DwarfVirtuality>(value.toInt())); break; case DW_AT_visibility: stringifyEnum(value, &dwarf_get_VIS_name); break; case DW_AT_identifier_case: stringifyEnum(value, &dwarf_get_ID_name); break; case DW_AT_inline: stringifyEnum(value, &dwarf_get_INL_name); break; case DW_AT_encoding: stringifyEnum(value, &dwarf_get_ATE_name); break; case DW_AT_ordering: stringifyEnum(value, &dwarf_get_ORD_name); break; case DW_AT_calling_convention: stringifyEnum(value, &dwarf_get_CC_name); break; case DW_AT_discr_list: stringifyEnum(value, &dwarf_get_DSC_name); break; default: break; } return value; }
/* 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); }
static struct variable* analyze_variable(Dwarf_Die *die, Dwarf_Files *files, struct expr_context *ctx) { int ret; Dwarf_Attribute at; struct variable* var; /* ignore declarations */ if (dwarf_attr_integrate(die, DW_AT_declaration, &at) != NULL) { bool flag; ret = dwarf_formflag(&at, &flag); fail_if(ret == -1, "dwarf_formflag"); if (flag) return NULL; } var = xalloc(sizeof(struct variable)); analyze_name_location(die, files, &var->name, &var->loc); if (dwarf_attr_integrate(die, DW_AT_type, &at) != NULL) { Dwarf_Die type_die; if (dwarf_formref_die(&at, &type_die) == NULL) fail("dwarf_formref_die"); analyze_type(&type_die, &(var->type)); } if (dwarf_attr_integrate(die, DW_AT_const_value, &at) != NULL) { Dwarf_Word w; Dwarf_Block bl; unsigned int form = dwarf_whatform(&at); debug("variable %s has constant value of form %x", var->name, form); if (dwarf_formudata(&at, &w) == 0) { fail_if(sizeof(w) < var->type.width, "constant value too small"); var->value = xalloc(var->type.width); memcpy(var->value, &w, var->type.width); } else if (dwarf_formblock(&at, &bl) == 0) { fail_if(bl.length < var->type.width, "constant value too small"); var->value = xalloc(var->type.width); memcpy(var->value, bl.data, var->type.width); } else { warn("unable to get constant value of variable %x (form %x)", var->name, form); } } else if (dwarf_attr_integrate(die, DW_AT_location, &at) != NULL) { size_t exprlen; Dwarf_Op *expr; ret = dwarf_getlocation_addr(&at, ctx->ip, &expr, &exprlen, 1); if (ret != 1) { if (ret == -1) /* it seems that elfutils have some kind of problem with * DW_OP_GNU_entry_value but that operation is useless for us * anyway */ warn("cannot get location for variable %s (ip: %lx), %s", var->name, ctx->ip, dwarf_errmsg(-1)); else if (ret == 0) debug("no location available for variable %s (ip: %lx)", var->name, ctx->ip); else fail("unreachable reached"); return var; } var->value = evaluate_loc_expr(expr, exprlen, ctx, var->type.width); } return var; }
static VALUE rd_attr_raw_value(VALUE self) { rd_attr_t *attr = GetAttr(self); Dwarf_Half form; Dwarf_Error err; union { Dwarf_Addr addr; Dwarf_Off off; Dwarf_Unsigned udata; Dwarf_Signed sdata; Dwarf_Bool bool; char *str; } val; VALUE top; chkerr1(dwarf_whatform(attr->attr, &form, &err), &err, self); switch (form) { case DW_FORM_addr: chkerr1(dwarf_formaddr(attr->attr, &val.addr, &err), &err, self); return ULL2NUM(val.addr); case DW_FORM_ref1: case DW_FORM_ref2: case DW_FORM_ref4: case DW_FORM_ref8: case DW_FORM_ref_udata: chkerr1(dwarf_global_formref(attr->attr, &val.off, &err), &err, self); top = rb_ivar_get(self, id_at_top); return rdwarf_die_at(top, LL2NUM(val.off)); case DW_FORM_data1: case DW_FORM_data2: case DW_FORM_data4: case DW_FORM_data8: case DW_FORM_udata: chkerr1(dwarf_formudata(attr->attr, &val.udata, &err), &err, self); return ULL2NUM(val.udata); case DW_FORM_sdata: chkerr1(dwarf_formsdata(attr->attr, &val.sdata, &err), &err, self); return LL2NUM(val.sdata); case DW_FORM_flag: chkerr1(dwarf_formflag(attr->attr, &val.bool, &err), &err, self); return val.bool ? Qtrue : Qfalse; case DW_FORM_strp: case DW_FORM_string: chkerr1(dwarf_formstring(attr->attr, &val.str, &err), &err, self); return rb_str_new_cstr(val.str); } return sym_unsupported_type; }