bool ElfWriter::addSymbolInfo(DwarfChunk* d) { Dwarf_Error error = 0; /* create a top level DIE (debug information entry) * all subsequent DIEs' will be children of this DIE */ Dwarf_P_Die codeUnit = dwarf_new_die(m_dwarfProducer, DW_TAG_compile_unit, nullptr, nullptr, nullptr, nullptr, &error); if (reinterpret_cast<Dwarf_Addr>(codeUnit) == DW_DLV_BADADDR) { logError("unable to create code unit DIE"); return false; } Dwarf_P_Die lastChild = nullptr; FuncPtrDB::iterator it; Dwarf_P_Die type = makeLocalTypeDie(); if (type == nullptr) { logError("unable to create type DIE"); return false; } Dwarf_P_Die linkRes; linkRes = dwarf_die_link(type, codeUnit, nullptr, nullptr, nullptr, &error); if (reinterpret_cast<Dwarf_Addr>(linkRes) == DW_DLV_BADADDR) { logError("unable to link die"); return false; } for (it = d->m_functions.begin(); it != d->m_functions.end(); it++) { /* for each function, add DIE entries with information about name, * line number, file, etc */ Dwarf_P_Die func = addFunctionInfo(*it, type); if (func == nullptr) { logError("unable to create child DIE"); return false; } if (lastChild) { linkRes = dwarf_die_link(func, nullptr, nullptr, lastChild, nullptr, &error); } else { linkRes = dwarf_die_link(func, codeUnit, nullptr, nullptr, nullptr, &error); } if (reinterpret_cast<Dwarf_Addr>(linkRes) == DW_DLV_BADADDR) { logError("unable to link die"); return false; } lastChild = func; } /* register top level DIE */ Dwarf_Unsigned res = dwarf_add_die_to_debug(m_dwarfProducer, codeUnit, &error); if (res != DW_DLV_OK) { logError("unable to add DIE to DWARF"); return false; } return true; }
/*---------------------------------------------------------------------------- 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 new_die, ret_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_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; }
Dwarf_P_Die ElfWriter::addFunctionInfo(FunctionInfo* f, Dwarf_P_Die type) { Dwarf_Error error = 0; /* top level DIE for each function */ Dwarf_P_Die func = dwarf_new_die(m_dwarfProducer, DW_TAG_subprogram, nullptr, nullptr, nullptr, nullptr, &error); if (reinterpret_cast<Dwarf_Addr>(func) == DW_DLV_BADADDR) { logError("unable to create child DIE"); return nullptr; } Dwarf_Signed file; FileDB::iterator it = m_fileDB.find(f->file); /* if this function is from an unseen file, register file name * and get index to file name */ if (it == m_fileDB.end()) { file = dwarf_add_file_decl(m_dwarfProducer, (char *)f->file, 0, 0, 1000, &error); if (file == DW_DLV_NOCOUNT) { logError("unable to add file declaration"); return nullptr; } m_fileDB[f->file] = file; } else { file = it->second; } /* add function name attribute to function DIE */ Dwarf_P_Attribute at; at = dwarf_add_AT_name(func, (char *)f->name.c_str(), &error); if (reinterpret_cast<Dwarf_Addr>(at) == DW_DLV_BADADDR) { logError("unable to add name attribute to function"); return nullptr; } /* Add lower PC bound to function DIE */ at = dwarf_add_AT_targ_address(m_dwarfProducer, func, DW_AT_low_pc, reinterpret_cast<Dwarf_Unsigned>(f->range.begin()), 0, &error); if (reinterpret_cast<Dwarf_Addr>(at) == DW_DLV_BADADDR) { logError("unable to add low_pc attribute to function"); return nullptr; } /* add upper PC bound to function DIE */ at = dwarf_add_AT_targ_address(m_dwarfProducer, func, DW_AT_high_pc, reinterpret_cast<Dwarf_Unsigned>(f->range.end()), 0, &error); if (reinterpret_cast<Dwarf_Addr>(at) == DW_DLV_BADADDR) { logError("unable to add high_pc attribute to function"); return nullptr; } /* register line number information for function: * 1. register start address */ Dwarf_Unsigned u; u = dwarf_lne_set_address(m_dwarfProducer, reinterpret_cast<Dwarf_Addr>(f->range.begin()), 0, &error); if (u != 0) { logError("unable to set line start address"); return nullptr; } /* 2. register line number info for each tracelet in function */ std::vector<LineEntry>::iterator it2; for (it2 = f->m_lineTable.begin(); it2 != f->m_lineTable.end(); it2++) { u = dwarf_add_line_entry(m_dwarfProducer, file, reinterpret_cast<Dwarf_Addr>(it2->range.begin()), it2->lineNumber, 0, 1, 0, &error); if (u != 0) { logError("unable to add line entry"); return nullptr; } TRACE(1, "elfwriter tracelet: %s %p %p\n", m_filename.c_str(), it2->range.begin(), it2->range.end()); } /* 3. register end address of function */ u = dwarf_lne_end_sequence(m_dwarfProducer, reinterpret_cast<Dwarf_Addr>(f->range.end()), &error); if (u != 0) { logError("unable to set line end address"); return nullptr; } /* 4. register frame base of function */ Dwarf_P_Expr locExpr = dwarf_new_expr(m_dwarfProducer, &error); if (locExpr == nullptr) { logError("unable to create new location expression"); return nullptr; } u = dwarf_add_expr_gen(locExpr, DW_OP_call_frame_cfa, 0, 0, &error); if (u == DW_DLV_NOCOUNT) { logError("unable to add subexpression to location expression"); return nullptr; } u = dwarf_add_expr_gen(locExpr, DW_OP_const1u, CFA_OFFSET, 0, &error); if (u == DW_DLV_NOCOUNT) { logError("unable to add subexpression to location expression"); return nullptr; } u = dwarf_add_expr_gen(locExpr, DW_OP_minus, 0, 0, &error); if (u == DW_DLV_NOCOUNT) { logError("unable to add subexpression to location expression"); return nullptr; } Dwarf_P_Attribute frameBaseAttr = dwarf_add_AT_location_expr(m_dwarfProducer, func, DW_AT_frame_base, locExpr, &error); if (reinterpret_cast<Dwarf_Addr>(frameBaseAttr) == DW_DLV_BADADDR) { logError("unable to add frame_base attribute"); return nullptr; } /* 5. register all the named locals of function */ Dwarf_P_Die lastLocal = nullptr; int i = 1; for (std::vector<std::string>::iterator it = f->m_namedLocals.begin(); it != f->m_namedLocals.end(); it++) { Dwarf_P_Die localVar = dwarf_new_die(m_dwarfProducer, DW_TAG_variable, nullptr, nullptr, nullptr, nullptr, &error); if (reinterpret_cast<Dwarf_Addr>(localVar) == DW_DLV_BADADDR) { logError("unable to create new DIE for local variable"); return nullptr; } /* Create location expression defined w.r.t DW_AT_frame_base */ Dwarf_P_Expr locExpr = dwarf_new_expr(m_dwarfProducer, &error); if (locExpr == nullptr) { logError("unable to create new location expression"); return nullptr; } u = dwarf_add_expr_gen(locExpr, DW_OP_fbreg, -(i * sizeof(TypedValue)), 0, &error); ++i; if (u == DW_DLV_NOCOUNT) { logError("unable to add subexpression to location expression"); return nullptr; } Dwarf_P_Attribute locAttr = dwarf_add_AT_location_expr(m_dwarfProducer, localVar, DW_AT_location, locExpr, &error); if (reinterpret_cast<Dwarf_Addr>(locAttr) == DW_DLV_BADADDR) { logError("unable to add location attribute to local variable"); return nullptr; } Dwarf_P_Attribute nameAttr = dwarf_add_AT_name(localVar, const_cast<char *>(it->data()), &error); if (reinterpret_cast<Dwarf_Addr>(nameAttr) == DW_DLV_BADADDR) { logError("unable to add name attribute to local variable"); return nullptr; } Dwarf_P_Attribute varTypeAttr = dwarf_add_AT_reference(m_dwarfProducer, localVar, DW_AT_type, type, &error); if (reinterpret_cast<Dwarf_Addr>(varTypeAttr) == DW_DLV_BADADDR) { logError("unable to add type attribute to local variable DIE"); return nullptr; } Dwarf_P_Die res = 0; if (lastLocal != nullptr) { res = dwarf_die_link(localVar, nullptr, nullptr, lastLocal, nullptr, &error); } else { res = dwarf_die_link(localVar, func, nullptr, nullptr, nullptr, &error); } if (reinterpret_cast<Dwarf_Addr>(res) == DW_DLV_BADADDR) { logError("unable to link die"); return nullptr; } lastLocal = localVar; } return func; }