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; }
Dwarf_P_Die ElfWriter::addFunctionInfo(FunctionInfo* f) { Dwarf_Error error = 0; /* top level DIE for each function */ Dwarf_P_Die func = dwarf_new_die(m_dwarfProducer, DW_TAG_subprogram, NULL, NULL, NULL, NULL, &error); if (reinterpret_cast<Dwarf_Addr>(func) == DW_DLV_BADADDR) { logError("unable to create child DIE"); return NULL; } 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 NULL; } 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 NULL; } /* 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 NULL; } /* 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 NULL; } /* 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 NULL; } /* 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 NULL; } 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 NULL; } return func; }