diff options
Diffstat (limited to 'dwarfgen/createirepfrombinary.cc')
-rw-r--r-- | dwarfgen/createirepfrombinary.cc | 608 |
1 files changed, 608 insertions, 0 deletions
diff --git a/dwarfgen/createirepfrombinary.cc b/dwarfgen/createirepfrombinary.cc new file mode 100644 index 0000000..193e35d --- /dev/null +++ b/dwarfgen/createirepfrombinary.cc @@ -0,0 +1,608 @@ +/* + Copyright (C) 2010-2011 David Anderson. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2 of the GNU General Public License as + published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + You should have received a copy of the GNU General Public License along + with this program; if not, write the Free Software Foundation, Inc., 51 + Franklin Street - Fifth Floor, Boston MA 02110-1301, USA. + +*/ + +// createirepfrombinary.cc + +// Reads an object and inserts its dwarf data into +// an object intended to hold all the dwarf data. + +#include "config.h" +#include <unistd.h> +#include <stdlib.h> // for exit +#include <iostream> +#include <string> +#include <list> +#include <vector> +#include <string.h> // For memset etc +#include <sys/stat.h> //open +#include <fcntl.h> //open +#include "elf.h" +#include "gelf.h" +#include "strtabdata.h" +#include "dwarf.h" +#include "libdwarf.h" +#include "irepresentation.h" +#include "createirepfrombinary.h" +#include "general.h" // For IToHex() + +using std::string; +using std::cout; +using std::cerr; +using std::endl; +using std::vector; +using std::list; + +static void readFrameDataFromBinary(Dwarf_Debug dbg, IRepresentation & irep); +static void readMacroDataFromBinary(Dwarf_Debug dbg, IRepresentation & irep); +static void readCUDataFromBinary(Dwarf_Debug dbg, IRepresentation & irep); + +class DbgInAutoCloser { +public: + DbgInAutoCloser(Dwarf_Debug dbg,int fd): dbg_(dbg),fd_(fd) {}; + ~DbgInAutoCloser() { + Dwarf_Error err = 0; + dwarf_finish(dbg_,&err); + close(fd_); + }; +private: + Dwarf_Debug dbg_; + int fd_; +}; + + +void +createIrepFromBinary(const std::string &infile, + IRepresentation & irep) +{ + Dwarf_Debug dbg = 0; + Dwarf_Error err; + int fd = open(infile.c_str(),O_RDONLY, 0); + if(fd < 0 ) { + cerr << "Unable to open " << infile << + " for reading." << endl; + exit(1); + } + // All reader error handling is via the err argument. + int res = dwarf_init(fd,DW_DLC_READ, + 0, + 0, + &dbg, + &err); + if(res != DW_DLV_OK) { + close(fd); + cerr << "Error init-ing " << infile << + " for reading." << endl; + exit(1); + } + + DbgInAutoCloser closer(dbg,fd); + + readFrameDataFromBinary(dbg,irep); + readCUDataFromBinary(dbg,irep); + readMacroDataFromBinary(dbg,irep); + + return; +} + +static void +readFrameDataFromBinary(Dwarf_Debug dbg, IRepresentation & irep) +{ + Dwarf_Error err = 0; + Dwarf_Cie * cie_data = 0; + Dwarf_Signed cie_count = 0; + Dwarf_Fde * fde_data = 0; + Dwarf_Signed fde_count = 0; + int res = dwarf_get_fde_list(dbg, + &cie_data, + &cie_count, + &fde_data, + &fde_count, + &err); + if(res == DW_DLV_NO_ENTRY) { + // No frame data. + return; + } + if(res == DW_DLV_ERROR) { + cerr << "Error reading frame data " << endl; + exit(1); + } + + for(Dwarf_Signed i =0; i < cie_count; ++i) { + Dwarf_Unsigned bytes_in_cie = 0; + Dwarf_Small version = 0; + char * augmentation = 0; + Dwarf_Unsigned code_alignment_factor = 0; + Dwarf_Signed data_alignment_factor = 0; + Dwarf_Half return_address_register_rule = 0; + Dwarf_Ptr initial_instructions = 0; + Dwarf_Unsigned initial_instructions_length = 0; + res = dwarf_get_cie_info(cie_data[i], &bytes_in_cie, + &version,&augmentation, &code_alignment_factor, + &data_alignment_factor,&return_address_register_rule, + &initial_instructions,&initial_instructions_length, + &err); + if(res != DW_DLV_OK) { + cerr << "Error reading frame data cie index " << i << endl; + exit(1); + } + // Index in cie_data must match index in ciedata_, here + // correct by construction. + IRCie cie(bytes_in_cie,version,augmentation,code_alignment_factor, + data_alignment_factor,return_address_register_rule, + initial_instructions,initial_instructions_length); + irep.framedata().insert_cie(cie); + } + for(Dwarf_Signed i =0; i < fde_count; ++i) { + Dwarf_Addr low_pc = 0; + Dwarf_Unsigned func_length = 0; + Dwarf_Ptr fde_bytes = 0; + Dwarf_Unsigned fde_byte_length = 0; + Dwarf_Off cie_offset = 0; + Dwarf_Signed cie_index = 0; + Dwarf_Off fde_offset = 0; + res = dwarf_get_fde_range(fde_data[i], &low_pc, + &func_length,&fde_bytes, &fde_byte_length, + &cie_offset,&cie_index, + &fde_offset, + &err); + if(res != DW_DLV_OK) { + cerr << "Error reading frame data fde index " << i << endl; + exit(1); + } + IRFde fde(low_pc,func_length,fde_bytes,fde_byte_length, + cie_offset, cie_index,fde_offset); + Dwarf_Ptr instr_in = 0; + Dwarf_Unsigned instr_len = 0; + res = dwarf_get_fde_instr_bytes(fde_data[i], + &instr_in, &instr_len, &err); + if(res != DW_DLV_OK) { + cerr << "Error reading frame data fde instructions " << i << endl; + exit(1); + } + fde.get_fde_instrs_into_ir(instr_in,instr_len); + irep.framedata().insert_fde(fde); + } + dwarf_fde_cie_list_dealloc(dbg,cie_data,cie_count, + fde_data,fde_count); +} + + +static void +readCUMacroDataFromBinary(Dwarf_Debug dbg, IRepresentation & irep, + Dwarf_Unsigned macrodataoffset,IRCUdata &cu) +{ + // Arbitrary, but way too high to be real! + // Probably should be lower. + Dwarf_Unsigned maxcount = 1000000000; + Dwarf_Error error; + Dwarf_Signed mcount=0; + Dwarf_Macro_Details *md = 0; + int res = dwarf_get_macro_details(dbg,macrodataoffset, + maxcount, &mcount, &md, &error); + if(res == DW_DLV_OK) { + IRMacro ¯odata = irep.macrodata(); + vector<IRMacroRecord> mvec = macrodata.getMacroVec(); + mvec.reserve(mcount); + Dwarf_Unsigned dieoffset = cu.baseDie().getGlobalOffset(); + Dwarf_Macro_Details *mdp = md; + for(int i = 0; i < mcount; ++i, mdp++ ) { + IRMacroRecord i(dieoffset,mdp->dmd_offset, + mdp->dmd_type, mdp->dmd_lineno, + mdp->dmd_fileindex, mdp->dmd_macro?mdp->dmd_macro:""); + mvec.push_back(i); + } + } + dwarf_dealloc(dbg, md, DW_DLA_STRING); +} + +void +get_basic_attr_data_one_attr(Dwarf_Debug dbg, + Dwarf_Attribute attr,IRCUdata &cudata,IRAttr & irattr) +{ + Dwarf_Error error; + Dwarf_Half attrnum = 0; + Dwarf_Half dirform = 0; + Dwarf_Half indirform = 0; + int res = dwarf_whatattr(attr,&attrnum,&error); + if(res != DW_DLV_OK) { + cerr << "Unable to get attr number " << endl; + exit(1); + } + res = dwarf_whatform(attr,&dirform,&error); + if(res != DW_DLV_OK) { + cerr << "Unable to get attr form " << endl; + exit(1); + } + + res = dwarf_whatform_direct(attr,&indirform,&error); + if(res != DW_DLV_OK) { + cerr << "Unable to get attr direct form " << endl; + exit(1); + } + irattr.setBaseData(attrnum,dirform,indirform); + enum Dwarf_Form_Class cl = dwarf_get_form_class( + cudata.getVersionStamp(), attrnum, + cudata.getOffsetSize(), dirform); + irattr.setFormClass(cl); + if (cl == DW_FORM_CLASS_UNKNOWN) { + cerr << "Unable to figure out form class. ver " << + cudata.getVersionStamp() << + " attrnum " << attrnum << + " offsetsize " << cudata.getOffsetSize() << + " formnum " << dirform << endl; + return; + } + irattr.setFormData(formFactory(dbg,attr,cudata,irattr)); +} +void +get_basic_die_data(Dwarf_Debug dbg,Dwarf_Die indie,IRDie &irdie) +{ + Dwarf_Half tagval = 0; + Dwarf_Error error = 0; + int res = dwarf_tag(indie,&tagval,&error); + if(res != DW_DLV_OK) { + cerr << "Unable to get die tag "<< endl; + exit(1); + } + Dwarf_Off goff = 0; + res = dwarf_dieoffset(indie,&goff,&error); + if(res != DW_DLV_OK) { + cerr << "Unable to get die offset "<< endl; + exit(1); + } + Dwarf_Off localoff = 0; + res = dwarf_die_CU_offset(indie,&localoff,&error); + if(res != DW_DLV_OK) { + cerr << "Unable to get cu die offset "<< endl; + exit(1); + } + irdie.setBaseData(tagval,goff,localoff); +} + + +static void +get_attrs_of_die(Dwarf_Die in_die,IRDie &irdie, + IRCUdata &data, IRepresentation &irep, + Dwarf_Debug dbg) +{ + Dwarf_Error error = 0; + Dwarf_Attribute *atlist = 0; + Dwarf_Signed atcnt = 0; + std::list<IRAttr> &attrlist = irdie.getAttributes(); + int res = dwarf_attrlist(in_die, &atlist,&atcnt,&error); + if(res == DW_DLV_NO_ENTRY) { + return; + } + if(res == DW_DLV_ERROR) { + cerr << "dwarf_attrlist failed " << endl; + exit(1); + } + for (Dwarf_Signed i = 0; i < atcnt; ++i) { + Dwarf_Attribute attr = atlist[i]; + IRAttr irattr; + get_basic_attr_data_one_attr(dbg,attr,data,irattr); + attrlist.push_back(irattr); + + } + dwarf_dealloc(dbg,atlist, DW_DLA_LIST); +} + +// Invariant: IRDie and IRCUdata is in the irep tree, +// not local record references to local scopes. +static void +get_children_of_die(Dwarf_Die in_die,IRDie&irdie, + IRCUdata &ircudata, + IRepresentation &irep, + Dwarf_Debug dbg) +{ + Dwarf_Die curchilddie = 0; + Dwarf_Error error = 0; + int res = dwarf_child(in_die,&curchilddie,&error); + if(res == DW_DLV_NO_ENTRY) { + return; + } + if(res == DW_DLV_ERROR) { + cerr << "dwarf_child failed " << endl; + exit(1); + } + //std::list<IRDie> & childlist = irdie.getChildren(); + int childcount = 0; + for(;;) { + IRDie child; + get_basic_die_data(dbg,curchilddie,child); + get_attrs_of_die(curchilddie,child,ircudata,irep,dbg); + irdie.addChild(child); + IRDie &lastchild = irdie.lastChild(); + + get_children_of_die(curchilddie,lastchild,ircudata,irep,dbg); + ++childcount; + + Dwarf_Die tchild = 0; + res = dwarf_siblingof(dbg,curchilddie,&tchild,&error); + if(res == DW_DLV_NO_ENTRY) { + break; + } + if(res == DW_DLV_ERROR) { + cerr << "dwarf_siblingof failed " << endl; + exit(1); + } + dwarf_dealloc(dbg,curchilddie,DW_DLA_DIE); + curchilddie = tchild; + } + dwarf_dealloc(dbg,curchilddie,DW_DLA_DIE); +} + +static void +get_linedata_of_cu_die(Dwarf_Die in_die,IRDie&irdie, + IRCUdata &ircudata, + IRepresentation &irep, + Dwarf_Debug dbg) +{ + Dwarf_Error error = 0; + char **srcfiles = 0; + Dwarf_Signed srccount = 0; + IRCULineData&culinesdata = ircudata.getCULines(); + int res = dwarf_srcfiles(in_die,&srcfiles, &srccount,&error); + if(res == DW_DLV_ERROR) { + cerr << "dwarf_srcfiles failed " << endl; + exit(1); + } else if (res == DW_DLV_NO_ENTRY) { + // No data. + return; + } + + std::vector<IRCUSrcfile> &srcs = culinesdata.get_cu_srcfiles(); + for (Dwarf_Signed i = 0; i < srccount; ++i) { + IRCUSrcfile S(srcfiles[i]); + srcs.push_back(S); + /* use srcfiles[i] */ + dwarf_dealloc(dbg, srcfiles[i], DW_DLA_STRING); + } + dwarf_dealloc(dbg, srcfiles, DW_DLA_LIST); + + Dwarf_Line * linebuf = 0; + Dwarf_Signed linecnt = 0; + int res2 = dwarf_srclines(in_die,&linebuf,&linecnt, &error); + if(res == DW_DLV_ERROR) { + cerr << "dwarf_srclines failed " << endl; + exit(1); + } else if (res == DW_DLV_NO_ENTRY) { + // No data. + cerr << "dwarf_srclines failed NO_ENTRY, crazy " + "since srcfiles worked" << endl; + exit(1); + } + + std::vector<IRCULine> &lines = culinesdata.get_cu_lines(); + for(Dwarf_Signed j = 0; j < linecnt ; ++j ) { + Dwarf_Line li = linebuf[j]; + int lres; + + Dwarf_Addr address = 0; + lres = dwarf_lineaddr(li,&address,&error); + if (lres != DW_DLV_OK) { + cerr << "dwarf_lineaddr failed. " << endl; + exit(1); + } + Dwarf_Bool is_addr_set = 0; + lres = dwarf_line_is_addr_set(li,&is_addr_set,&error); + if (lres != DW_DLV_OK) { + cerr << "dwarf_line_is_addr_set failed. " << endl; + exit(1); + } + Dwarf_Unsigned fileno = 0; + lres = dwarf_line_srcfileno(li,&fileno,&error); + if (lres != DW_DLV_OK) { + cerr << "dwarf_srcfileno failed. " << endl; + exit(1); + } + Dwarf_Unsigned lineno = 0; + lres = dwarf_lineno(li,&lineno,&error); + if (lres != DW_DLV_OK) { + cerr << "dwarf_lineno failed. " << endl; + exit(1); + } + Dwarf_Unsigned lineoff = 0; + lres = dwarf_lineoff_b(li,&lineoff,&error); + if (lres != DW_DLV_OK) { + cerr << "dwarf_lineoff failed. " << endl; + exit(1); + } + char *linesrctmp = 0; + lres = dwarf_linesrc(li,&linesrctmp,&error); + if (lres != DW_DLV_OK) { + cerr << "dwarf_linesrc failed. " << endl; + exit(1); + } + // libdwarf is trying to generate a full path, + // the string here is that generated data, not + // simply the 'file' path represented by the + // file number (fileno). + std::string linesrc(linesrctmp); + + + Dwarf_Bool is_stmt = 0; + lres = dwarf_linebeginstatement(li,&is_stmt,&error); + if (lres != DW_DLV_OK) { + cerr << "dwarf_linebeginstatement failed. " << endl; + exit(1); + } + + Dwarf_Bool basic_block = 0; + lres = dwarf_lineblock(li,&basic_block,&error); + if (lres != DW_DLV_OK) { + cerr << "dwarf_lineblock failed. " << endl; + exit(1); + } + + Dwarf_Bool end_sequence = 0; + lres = dwarf_lineendsequence(li,&end_sequence,&error); + if (lres != DW_DLV_OK) { + cerr << "dwarf_lineendsequence failed. " << endl; + exit(1); + } + + Dwarf_Bool prologue_end = 0; + Dwarf_Bool epilogue_begin = 0; + Dwarf_Unsigned isa = 0; + Dwarf_Unsigned discriminator = 0; + lres = dwarf_prologue_end_etc(li,&prologue_end, + &epilogue_begin,&isa,&discriminator,&error); + if (lres != DW_DLV_OK) { + cerr << "dwarf_prologue_end_etc failed. " << endl; + exit(1); + } + + IRCULine L(address, + is_addr_set, + fileno, + lineno, + lineoff, + linesrc, + is_stmt, + basic_block, + end_sequence, + prologue_end,epilogue_begin, + isa,discriminator); + lines.push_back(L); + } + dwarf_srclines_dealloc(dbg, linebuf, linecnt); +} + +static bool +getToplevelOffsetAttr(Dwarf_Die cu_die,Dwarf_Half attrnumber, + Dwarf_Unsigned &offset_out) +{ + Dwarf_Error error = 0; + Dwarf_Off offset = 0; + Dwarf_Attribute attr = 0; + int res = dwarf_attr(cu_die,attrnumber,&attr, &error); + bool foundit = false; + Dwarf_Off sectoff = 0; + if(res == DW_DLV_OK) { + Dwarf_Signed sval = 0; + Dwarf_Unsigned uval = 0; + res = dwarf_global_formref(attr,&offset,&error); + if(res == DW_DLV_OK) { + foundit = true; + offset_out = offset; + } + } + return foundit; +} + +// We record the .debug_info info for each CU found +// To start with we restrict attention to very few DIEs and +// attributes, but intend to get all eventually. +static void +readCUDataFromBinary(Dwarf_Debug dbg, IRepresentation & irep) +{ + Dwarf_Error error; + int cu_number = 0; + std::list<IRCUdata> &culist = irep.infodata().getCUData(); + + for(;;++cu_number) { + Dwarf_Unsigned cu_header_length = 0; + Dwarf_Half version_stamp = 0; + Dwarf_Unsigned abbrev_offset = 0; + Dwarf_Half address_size = 0; + Dwarf_Unsigned next_cu_header = 0; + Dwarf_Half offset_size = 0; + Dwarf_Half extension_size = 0; + Dwarf_Die no_die = 0; + Dwarf_Die cu_die = 0; + int res = DW_DLV_ERROR; + res = dwarf_next_cu_header_b(dbg,&cu_header_length, + &version_stamp, &abbrev_offset, &address_size, + &offset_size, &extension_size, + &next_cu_header, &error); + if(res == DW_DLV_ERROR) { + cerr <<"Error in dwarf_next_cu_header"<< endl; + exit(1); + } + if(res == DW_DLV_NO_ENTRY) { + /* Done. */ + return; + } + IRCUdata cudata(cu_header_length,version_stamp, + abbrev_offset,address_size, offset_size, + extension_size,next_cu_header); + + // The CU will have a single sibling (well, it is + // not exactly a sibling, but close enough), a cu_die. + res = dwarf_siblingof(dbg,no_die,&cu_die,&error); + if(res == DW_DLV_ERROR) { + cerr <<"Error in dwarf_siblingof on CU die "<< endl; + exit(1); + } + if(res == DW_DLV_NO_ENTRY) { + /* Impossible case. */ + cerr <<"no Entry! in dwarf_siblingof on CU die "<< endl; + exit(1); + } + Dwarf_Off macrooffset = 0; + bool foundmsect = getToplevelOffsetAttr(cu_die,DW_AT_macro_info, + macrooffset); + Dwarf_Off linesoffset = 0; + bool foundlines = getToplevelOffsetAttr(cu_die,DW_AT_stmt_list, + linesoffset); + Dwarf_Off dieoff = 0; + res = dwarf_dieoffset(cu_die,&dieoff,&error); + if(res != DW_DLV_OK) { + cerr << "Unable to get cu die offset for macro infomation "<< endl; + exit(1); + } + if(foundmsect) { + cudata.setMacroData(macrooffset,dieoff); + } + if(foundlines) { + cudata.setLineData(linesoffset,dieoff); + } + culist.push_back(cudata); + IRCUdata & treecu = irep.infodata().lastCU(); + IRDie &cuirdie = treecu.baseDie(); + get_basic_die_data(dbg,cu_die,cuirdie); + get_attrs_of_die(cu_die,cuirdie,treecu,irep,dbg); + get_children_of_die(cu_die,cuirdie,treecu,irep,dbg); + get_linedata_of_cu_die(cu_die,cuirdie,treecu,irep,dbg); + dwarf_dealloc(dbg,cu_die,DW_DLA_DIE); + } + // If we want pointers from child to parent now is the time + // we can construct them. +} + +// We read thru the CU headers and the CU die to find +// the macro info for each CU (if any). +// We record the CU macro info for each CU found (using +// the value of the DW_AT_macro_info attribute, if any). +static void +readMacroDataFromBinary(Dwarf_Debug dbg, IRepresentation & irep) +{ + + list<IRCUdata> &cudata = irep.infodata().getCUData(); + list<IRCUdata>::iterator it = cudata.begin(); + int ct = 0; + for( ; it != cudata.end(); ++it,++ct) { + Dwarf_Unsigned macrooffset = 0; + Dwarf_Unsigned cudieoffset = 0; + bool foundmsect = it->hasMacroData(¯ooffset,&cudieoffset); + if(foundmsect) { + readCUMacroDataFromBinary(dbg, irep, macrooffset,*it); + } + } +} + |