std::string JITDebugRegisterer::MakeELF(const Function *F, DebugInfo &I) { // Stack allocate an empty module with an empty LLVMContext for the ELFWriter // API. We don't use the real module because then the ELFWriter would write // out unnecessary GlobalValues during finalization. LLVMContext Context; Module M("", Context); // Make a buffer for the ELF in memory. std::string Buffer; raw_string_ostream O(Buffer); ELFWriter EW(O, TM); EW.doInitialization(M); // Copy the binary into the .text section. This isn't necessary, but it's // useful to be able to disassemble the ELF by hand. ELFSection &Text = EW.getTextSection(const_cast<Function *>(F)); Text.Addr = (uint64_t)I.FnStart; // TODO: We could eliminate this copy if we somehow used a pointer/size pair // instead of a vector. Text.getData().assign(I.FnStart, I.FnEnd); // Copy the exception handling call frame information into the .eh_frame // section. This allows GDB to get a good stack trace, particularly on // linux x86_64. Mark this as a PROGBITS section that needs to be loaded // into memory at runtime. ELFSection &EH = EW.getSection(".eh_frame", ELF::SHT_PROGBITS, ELF::SHF_ALLOC); // Pointers in the DWARF EH info are all relative to the EH frame start, // which is stored here. EH.Addr = (uint64_t)I.EhStart; // TODO: We could eliminate this copy if we somehow used a pointer/size pair // instead of a vector. EH.getData().assign(I.EhStart, I.EhEnd); // Add this single function to the symbol table, so the debugger prints the // name instead of '???'. We give the symbol default global visibility. ELFSym *FnSym = ELFSym::getGV(F, ELF::STB_GLOBAL, ELF::STT_FUNC, ELF::STV_DEFAULT); FnSym->SectionIdx = Text.SectionIdx; FnSym->Size = I.FnEnd - I.FnStart; FnSym->Value = 0; // Offset from start of section. EW.SymbolList.push_back(FnSym); EW.doFinalization(M); O.flush(); // When trying to debug why GDB isn't getting the debug info right, it's // awfully helpful to write the object file to disk so that it can be // inspected with readelf and objdump. if (JITEmitDebugInfoToDisk) { std::string Filename; raw_string_ostream O2(Filename); O2 << "/tmp/llvm_function_" << I.FnStart << "_" << F->getNameStr() << ".o"; O2.flush(); std::string Errors; raw_fd_ostream O3(Filename.c_str(), Errors); O3 << Buffer; O3.close(); } return Buffer; }
/* * Hash OIDs * * SHA1 = 1.3.14.3.2.26 * MDx = 1.2.840.113549.2.x */ #define O0(a,b) ((a)*40+(b)) #define O2(x) \ (((x)>>7)&0x7F)|0x80, \ ((x)&0x7F) #define O3(x) \ (((x)>>14)&0x7F)|0x80, \ (((x)>>7)&0x7F)|0x80, \ ((x)&0x7F) uchar oidsha1[] = { O0(1, 3), 14, 3, 2, 26 }; uchar oidmd2[] = { O0(1, 2), O2(840), O3(113549), 2, 2 }; uchar oidmd5[] = { O0(1, 2), O2(840), O3(113549), 2, 5 }; /* * DigestInfo ::= SEQUENCE { * digestAlgorithm AlgorithmIdentifier, * digest OCTET STRING * } * * except that OpenSSL seems to sign * * DigestInfo ::= SEQUENCE { * SEQUENCE{ digestAlgorithm AlgorithmIdentifier, NULL } * digest OCTET STRING * } *