static int printLineInfoForInput() { // Load any dylibs requested on the command line. loadDylibs(); // If we don't have any input files, read from stdin. if (!InputFileList.size()) InputFileList.push_back("-"); for(unsigned i = 0, e = InputFileList.size(); i != e; ++i) { // Instantiate a dynamic linker. TrivialMemoryManager MemMgr; RuntimeDyld Dyld(&MemMgr); // Load the input memory buffer. std::unique_ptr<MemoryBuffer> InputBuffer; std::unique_ptr<ObjectImage> LoadedObject; if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFileList[i], InputBuffer)) return Error("unable to read input: '" + ec.message() + "'"); // Load the object file LoadedObject.reset(Dyld.loadObject(new ObjectBuffer(InputBuffer.release()))); if (!LoadedObject) { return Error(Dyld.getErrorString()); } // Resolve all the relocations we can. Dyld.resolveRelocations(); std::unique_ptr<DIContext> Context( DIContext::getDWARFContext(LoadedObject->getObjectFile())); // Use symbol info to iterate functions in the object. for (object::symbol_iterator I = LoadedObject->begin_symbols(), E = LoadedObject->end_symbols(); I != E; ++I) { object::SymbolRef::Type SymType; if (I->getType(SymType)) continue; if (SymType == object::SymbolRef::ST_Function) { StringRef Name; uint64_t Addr; uint64_t Size; if (I->getName(Name)) continue; if (I->getAddress(Addr)) continue; if (I->getSize(Size)) continue; outs() << "Function: " << Name << ", Size = " << Size << "\n"; DILineInfoTable Lines = Context->getLineInfoForAddressRange(Addr, Size); DILineInfoTable::iterator Begin = Lines.begin(); DILineInfoTable::iterator End = Lines.end(); for (DILineInfoTable::iterator It = Begin; It != End; ++It) { outs() << " Line info @ " << It->first - Addr << ": " << It->second.FileName << ", line:" << It->second.Line << "\n"; } } } } return 0; }
DILineInfoTable DWARFContext::getLineInfoForAddressRange(uint64_t Address, uint64_t Size, DILineInfoSpecifier Specifier) { DILineInfoTable Lines; DWARFCompileUnit *CU = getCompileUnitForAddress(Address); if (!CU) return Lines; std::string FunctionName = "<invalid>"; if (Specifier.needs(DILineInfoSpecifier::FunctionName)) { // The address may correspond to instruction in some inlined function, // so we have to build the chain of inlined functions and take the // name of the topmost function in it. const DWARFDebugInfoEntryMinimal::InlinedChain &InlinedChain = CU->getInlinedChainForAddress(Address); if (InlinedChain.size() > 0) { const DWARFDebugInfoEntryMinimal &TopFunctionDIE = InlinedChain[0]; if (const char *Name = TopFunctionDIE.getSubroutineName(CU)) FunctionName = Name; } } StringRef FuncNameRef = StringRef(FunctionName); // If the Specifier says we don't need FileLineInfo, just // return the top-most function at the starting address. if (!Specifier.needs(DILineInfoSpecifier::FileLineInfo)) { Lines.push_back(std::make_pair(Address, DILineInfo(StringRef("<invalid>"), FuncNameRef, 0, 0))); return Lines; } const DWARFLineTable *LineTable = getLineTableForCompileUnit(CU); const bool NeedsAbsoluteFilePath = Specifier.needs(DILineInfoSpecifier::AbsoluteFilePath); // Get the index of row we're looking for in the line table. std::vector<uint32_t> RowVector; if (!LineTable->lookupAddressRange(Address, Size, RowVector)) return Lines; uint32_t NumRows = RowVector.size(); for (uint32_t i = 0; i < NumRows; ++i) { uint32_t RowIndex = RowVector[i]; // Take file number and line/column from the row. const DWARFDebugLine::Row &Row = LineTable->Rows[RowIndex]; std::string FileName = "<invalid>"; getFileNameForCompileUnit(CU, LineTable, Row.File, NeedsAbsoluteFilePath, FileName); Lines.push_back(std::make_pair(Row.Address, DILineInfo(StringRef(FileName), FuncNameRef, Row.Line, Row.Column))); } return Lines; }
void LLVMGetLineInfoForAddressRange(LLVMObjectFileRef O, uint64_t Address, uint64_t Size, int* OutSize, uint64_t** Out) { DIContext* ctx = DIContext::getDWARFContext(*(unwrap(O)->getBinary())); DILineInfoTable lineTable = ctx->getLineInfoForAddressRange(Address, Size); *OutSize = lineTable.size(); *Out = NULL; if (lineTable.size() > 0) { *Out = (uint64_t*) calloc(lineTable.size() * 2, sizeof(uint64_t)); for (int i = 0; i < lineTable.size(); i++) { std::pair<uint64_t, DILineInfo> p = lineTable[i]; (*Out)[i * 2] = p.first; (*Out)[i * 2 + 1] = p.second.Line; } } }
DILineInfoTable DWARFContext::getLineInfoForAddressRange(uint64_t Address, uint64_t Size, DILineInfoSpecifier Specifier) { DILineInfoTable Lines; DWARFCompileUnit *CU = getCompileUnitForAddress(Address); if (!CU) return Lines; std::string FunctionName = "<invalid>"; if (Specifier.needs(DILineInfoSpecifier::FunctionName)) { getFunctionNameForAddress(CU, Address, FunctionName); } // If the Specifier says we don't need FileLineInfo, just // return the top-most function at the starting address. if (!Specifier.needs(DILineInfoSpecifier::FileLineInfo)) { DILineInfo Result; Result.FunctionName = FunctionName; Lines.push_back(std::make_pair(Address, Result)); return Lines; } const DWARFLineTable *LineTable = getLineTableForCompileUnit(CU); const bool NeedsAbsoluteFilePath = Specifier.needs(DILineInfoSpecifier::AbsoluteFilePath); // Get the index of row we're looking for in the line table. std::vector<uint32_t> RowVector; if (!LineTable->lookupAddressRange(Address, Size, RowVector)) return Lines; for (uint32_t RowIndex : RowVector) { // Take file number and line/column from the row. const DWARFDebugLine::Row &Row = LineTable->Rows[RowIndex]; DILineInfo Result; getFileNameForCompileUnit(CU, LineTable, Row.File, NeedsAbsoluteFilePath, Result.FileName); Result.FunctionName = FunctionName; Result.Line = Row.Line; Result.Column = Row.Column; Lines.push_back(std::make_pair(Row.Address, Result)); } return Lines; }
DILineInfoTable PDBContext::getLineInfoForAddressRange(uint64_t Address, uint64_t Size, DILineInfoSpecifier Specifier) { if (Size == 0) return DILineInfoTable(); DILineInfoTable Table; auto LineNumbers = Session->findLineNumbersByAddress(Address, Size); if (!LineNumbers || LineNumbers->getChildCount() == 0) return Table; while (auto LineInfo = LineNumbers->getNext()) { DILineInfo LineEntry = getLineInfoForAddress(LineInfo->getVirtualAddress(), Specifier); Table.push_back(std::make_pair(LineInfo->getVirtualAddress(), LineEntry)); } return Table; }
void ObjectLoadListener::getDebugInfoForObject( const ObjectFile &Obj, const RuntimeDyld::LoadedObjectInfo &L) { OwningBinary<ObjectFile> DebugObjOwner = L.getObjectForDebug(Obj); const ObjectFile &DebugObj = *DebugObjOwner.getBinary(); // TODO: This extracts DWARF information from the object file, but we will // want to also be able to eventually extract WinCodeView information as well DWARFContextInMemory DwarfContext(DebugObj); // Use symbol info to find the function size. // If there are funclets, they will each have separate symbols, so we need // to sum the sizes, since the EE wants a single report for the entire // function+funclets. uint64_t Addr = UINT64_MAX; uint64_t Size = 0; std::vector<std::pair<SymbolRef, uint64_t>> SymbolSizes = object::computeSymbolSizes(DebugObj); for (const auto &Pair : SymbolSizes) { object::SymbolRef Symbol = Pair.first; SymbolRef::Type SymType = Symbol.getType(); if (SymType != SymbolRef::ST_Function) continue; // Function info ErrorOr<uint64_t> AddrOrError = Symbol.getAddress(); if (!AddrOrError) { continue; // Error. } uint64_t SingleAddr = AddrOrError.get(); uint64_t SingleSize = Pair.second; if (SingleAddr < Addr) { // The main function is always laid out first Addr = SingleAddr; } Size += SingleSize; } uint32_t LastDebugOffset = (uint32_t)-1; uint32_t NumDebugRanges = 0; ICorDebugInfo::OffsetMapping *OM; DILineInfoTable Lines = DwarfContext.getLineInfoForAddressRange(Addr, Size); DILineInfoTable::iterator Begin = Lines.begin(); DILineInfoTable::iterator End = Lines.end(); // Count offset entries. Will skip an entry if the current IL offset // matches the previous offset. for (DILineInfoTable::iterator It = Begin; It != End; ++It) { uint32_t LineNumber = (It->second).Line; if (LineNumber != LastDebugOffset) { NumDebugRanges++; LastDebugOffset = LineNumber; } } // Reset offset LastDebugOffset = (uint32_t)-1; if (NumDebugRanges > 0) { // Allocate OffsetMapping array unsigned SizeOfArray = (NumDebugRanges) * sizeof(ICorDebugInfo::OffsetMapping); OM = (ICorDebugInfo::OffsetMapping *)Context->JitInfo->allocateArray( SizeOfArray); unsigned CurrentDebugEntry = 0; // Iterate through the debug entries and save IL offset, native // offset, and source reason for (DILineInfoTable::iterator It = Begin; It != End; ++It) { int Offset = It->first; uint32_t LineNumber = (It->second).Line; // We store info about if the instruction is being recorded because // it is a call in the column field bool IsCall = (It->second).Column == 1; if (LineNumber != LastDebugOffset) { LastDebugOffset = LineNumber; OM[CurrentDebugEntry].nativeOffset = Offset; OM[CurrentDebugEntry].ilOffset = LineNumber; OM[CurrentDebugEntry].source = IsCall ? ICorDebugInfo::CALL_INSTRUCTION : ICorDebugInfo::STACK_EMPTY; CurrentDebugEntry++; } } // Send array of OffsetMappings to CLR EE CORINFO_METHOD_INFO *MethodInfo = Context->MethodInfo; CORINFO_METHOD_HANDLE MethodHandle = MethodInfo->ftn; Context->JitInfo->setBoundaries(MethodHandle, NumDebugRanges, OM); getDebugInfoForLocals(DwarfContext, Addr, Size); } }
static int printLineInfoForInput() { // Load any dylibs requested on the command line. loadDylibs(); // If we don't have any input files, read from stdin. if (!InputFileList.size()) InputFileList.push_back("-"); for(unsigned i = 0, e = InputFileList.size(); i != e; ++i) { // Instantiate a dynamic linker. TrivialMemoryManager MemMgr; RuntimeDyld Dyld(MemMgr, MemMgr); // Load the input memory buffer. ErrorOr<std::unique_ptr<MemoryBuffer>> InputBuffer = MemoryBuffer::getFileOrSTDIN(InputFileList[i]); if (std::error_code EC = InputBuffer.getError()) return Error("unable to read input: '" + EC.message() + "'"); ErrorOr<std::unique_ptr<ObjectFile>> MaybeObj( ObjectFile::createObjectFile((*InputBuffer)->getMemBufferRef())); if (std::error_code EC = MaybeObj.getError()) return Error("unable to create object file: '" + EC.message() + "'"); ObjectFile &Obj = **MaybeObj; // Load the object file std::unique_ptr<RuntimeDyld::LoadedObjectInfo> LoadedObjInfo = Dyld.loadObject(Obj); if (Dyld.hasError()) return Error(Dyld.getErrorString()); // Resolve all the relocations we can. Dyld.resolveRelocations(); OwningBinary<ObjectFile> DebugObj = LoadedObjInfo->getObjectForDebug(Obj); std::unique_ptr<DIContext> Context( new DWARFContextInMemory(*DebugObj.getBinary())); // Use symbol info to iterate functions in the object. for (object::symbol_iterator I = DebugObj.getBinary()->symbol_begin(), E = DebugObj.getBinary()->symbol_end(); I != E; ++I) { object::SymbolRef::Type SymType; if (I->getType(SymType)) continue; if (SymType == object::SymbolRef::ST_Function) { StringRef Name; uint64_t Addr; uint64_t Size; if (I->getName(Name)) continue; if (I->getAddress(Addr)) continue; if (I->getSize(Size)) continue; outs() << "Function: " << Name << ", Size = " << Size << "\n"; DILineInfoTable Lines = Context->getLineInfoForAddressRange(Addr, Size); DILineInfoTable::iterator Begin = Lines.begin(); DILineInfoTable::iterator End = Lines.end(); for (DILineInfoTable::iterator It = Begin; It != End; ++It) { outs() << " Line info @ " << It->first - Addr << ": " << It->second.FileName << ", line:" << It->second.Line << "\n"; } } } } return 0; }
static int printLineInfoForInput(bool LoadObjects, bool UseDebugObj) { assert(LoadObjects || !UseDebugObj); // Load any dylibs requested on the command line. loadDylibs(); // If we don't have any input files, read from stdin. if (!InputFileList.size()) InputFileList.push_back("-"); for(unsigned i = 0, e = InputFileList.size(); i != e; ++i) { // Instantiate a dynamic linker. TrivialMemoryManager MemMgr; RuntimeDyld Dyld(MemMgr, MemMgr); // Load the input memory buffer. ErrorOr<std::unique_ptr<MemoryBuffer>> InputBuffer = MemoryBuffer::getFileOrSTDIN(InputFileList[i]); if (std::error_code EC = InputBuffer.getError()) return Error("unable to read input: '" + EC.message() + "'"); ErrorOr<std::unique_ptr<ObjectFile>> MaybeObj( ObjectFile::createObjectFile((*InputBuffer)->getMemBufferRef())); if (std::error_code EC = MaybeObj.getError()) return Error("unable to create object file: '" + EC.message() + "'"); ObjectFile &Obj = **MaybeObj; OwningBinary<ObjectFile> DebugObj; std::unique_ptr<RuntimeDyld::LoadedObjectInfo> LoadedObjInfo = nullptr; ObjectFile *SymbolObj = &Obj; if (LoadObjects) { // Load the object file LoadedObjInfo = Dyld.loadObject(Obj); if (Dyld.hasError()) return Error(Dyld.getErrorString()); // Resolve all the relocations we can. Dyld.resolveRelocations(); if (UseDebugObj) { DebugObj = LoadedObjInfo->getObjectForDebug(Obj); SymbolObj = DebugObj.getBinary(); LoadedObjInfo.reset(); } } std::unique_ptr<DIContext> Context( new DWARFContextInMemory(*SymbolObj,LoadedObjInfo.get())); std::vector<std::pair<SymbolRef, uint64_t>> SymAddr = object::computeSymbolSizes(*SymbolObj); // Use symbol info to iterate functions in the object. for (const auto &P : SymAddr) { object::SymbolRef Sym = P.first; if (Sym.getType() == object::SymbolRef::ST_Function) { ErrorOr<StringRef> Name = Sym.getName(); if (!Name) continue; ErrorOr<uint64_t> AddrOrErr = Sym.getAddress(); if (!AddrOrErr) continue; uint64_t Addr = *AddrOrErr; uint64_t Size = P.second; // If we're not using the debug object, compute the address of the // symbol in memory (rather than that in the unrelocated object file) // and use that to query the DWARFContext. if (!UseDebugObj && LoadObjects) { object::section_iterator Sec(SymbolObj->section_end()); Sym.getSection(Sec); StringRef SecName; Sec->getName(SecName); uint64_t SectionLoadAddress = LoadedObjInfo->getSectionLoadAddress(*Sec); if (SectionLoadAddress != 0) Addr += SectionLoadAddress - Sec->getAddress(); } outs() << "Function: " << *Name << ", Size = " << Size << ", Addr = " << Addr << "\n"; DILineInfoTable Lines = Context->getLineInfoForAddressRange(Addr, Size); DILineInfoTable::iterator Begin = Lines.begin(); DILineInfoTable::iterator End = Lines.end(); for (DILineInfoTable::iterator It = Begin; It != End; ++It) { outs() << " Line info @ " << It->first - Addr << ": " << It->second.FileName << ", line:" << It->second.Line << "\n"; } } } } return 0; }