mirror of
https://github.com/intel/llvm.git
synced 2026-02-05 22:17:23 +08:00
[LLDB][NativePDB] Add support for inlined functions
This adds inline function support to NativePDB by parsing S_INLINESITE records to retrieve inlinee line info and add them into line table at `ParseLineTable`. Differential Revision: https://reviews.llvm.org/D116845
This commit is contained in:
@@ -206,7 +206,6 @@ public:
|
||||
|
||||
LineTable *LinkLineTable(const FileRangeMap &file_range_map);
|
||||
|
||||
protected:
|
||||
struct Entry {
|
||||
Entry()
|
||||
: line(0), is_start_of_statement(false), is_start_of_basic_block(false),
|
||||
@@ -303,6 +302,7 @@ protected:
|
||||
uint16_t file_idx = 0;
|
||||
};
|
||||
|
||||
protected:
|
||||
struct EntrySearchInfo {
|
||||
LineTable *line_table;
|
||||
lldb_private::Section *a_section;
|
||||
|
||||
@@ -106,6 +106,24 @@ static void ParseExtendedInfo(PdbIndex &index, CompilandIndexItem &item) {
|
||||
}
|
||||
}
|
||||
|
||||
static void ParseInlineeLineTableForCompileUnit(CompilandIndexItem &item) {
|
||||
for (const auto &ss : item.m_debug_stream.getSubsectionsArray()) {
|
||||
if (ss.kind() != DebugSubsectionKind::InlineeLines)
|
||||
continue;
|
||||
|
||||
DebugInlineeLinesSubsectionRef inlinee_lines;
|
||||
llvm::BinaryStreamReader reader(ss.getRecordData());
|
||||
if (llvm::Error error = inlinee_lines.initialize(reader)) {
|
||||
consumeError(std::move(error));
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const InlineeSourceLine &Line : inlinee_lines) {
|
||||
item.m_inline_map[Line.Header->Inlinee] = Line;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CompilandIndexItem::CompilandIndexItem(
|
||||
PdbCompilandId id, llvm::pdb::ModuleDebugStreamRef debug_stream,
|
||||
llvm::pdb::DbiModuleDescriptor descriptor)
|
||||
@@ -142,6 +160,7 @@ CompilandIndexItem &CompileUnitIndex::GetOrCreateCompiland(uint16_t modi) {
|
||||
cci = std::make_unique<CompilandIndexItem>(
|
||||
PdbCompilandId{modi}, std::move(debug_stream), std::move(descriptor));
|
||||
ParseExtendedInfo(m_index, *cci);
|
||||
ParseInlineeLineTableForCompileUnit(*cci);
|
||||
|
||||
cci->m_strings.initialize(debug_stream.getSubsectionsArray());
|
||||
PDBStringTable &strings = cantFail(m_index.pdb().getStringTable());
|
||||
|
||||
@@ -9,10 +9,12 @@
|
||||
#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_COMPILEUNITINDEX_H
|
||||
#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_COMPILEUNITINDEX_H
|
||||
|
||||
#include "lldb/Utility/RangeMap.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/IntervalMap.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
|
||||
#include "llvm/DebugInfo/CodeView/StringsAndChecksums.h"
|
||||
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
|
||||
@@ -69,6 +71,17 @@ struct CompilandIndexItem {
|
||||
// command line, etc. This usually contains exactly 5 items which
|
||||
// are references to other strings.
|
||||
llvm::SmallVector<llvm::codeview::TypeIndex, 5> m_build_info;
|
||||
|
||||
// Inlinee lines table in this compile unit.
|
||||
std::map<llvm::codeview::TypeIndex, llvm::codeview::InlineeSourceLine>
|
||||
m_inline_map;
|
||||
|
||||
// It's the line table parsed from DEBUG_S_LINES sections, mapping the file
|
||||
// address range to file index and source line number.
|
||||
using GlobalLineTable =
|
||||
lldb_private::RangeDataVector<lldb::addr_t, uint32_t,
|
||||
std::pair<uint32_t, uint32_t>>;
|
||||
GlobalLineTable m_global_line_table;
|
||||
};
|
||||
|
||||
/// Indexes information about all compile units. This is really just a map of
|
||||
|
||||
@@ -330,31 +330,65 @@ uint32_t SymbolFileNativePDB::CalculateNumCompileUnits() {
|
||||
Block &SymbolFileNativePDB::CreateBlock(PdbCompilandSymId block_id) {
|
||||
CompilandIndexItem *cii = m_index->compilands().GetCompiland(block_id.modi);
|
||||
CVSymbol sym = cii->m_debug_stream.readSymbolAtOffset(block_id.offset);
|
||||
|
||||
if (sym.kind() == S_GPROC32 || sym.kind() == S_LPROC32) {
|
||||
// This is a function. It must be global. Creating the Function entry for
|
||||
// it automatically creates a block for it.
|
||||
CompUnitSP comp_unit = GetOrCreateCompileUnit(*cii);
|
||||
return GetOrCreateFunction(block_id, *comp_unit)->GetBlock(false);
|
||||
}
|
||||
|
||||
lldbassert(sym.kind() == S_BLOCK32);
|
||||
|
||||
// This is a block. Its parent is either a function or another block. In
|
||||
// either case, its parent can be viewed as a block (e.g. a function contains
|
||||
// 1 big block. So just get the parent block and add this block to it.
|
||||
BlockSym block(static_cast<SymbolRecordKind>(sym.kind()));
|
||||
cantFail(SymbolDeserializer::deserializeAs<BlockSym>(sym, block));
|
||||
lldbassert(block.Parent != 0);
|
||||
PdbCompilandSymId parent_id(block_id.modi, block.Parent);
|
||||
Block &parent_block = GetOrCreateBlock(parent_id);
|
||||
CompUnitSP comp_unit = GetOrCreateCompileUnit(*cii);
|
||||
lldb::user_id_t opaque_block_uid = toOpaqueUid(block_id);
|
||||
BlockSP child_block = std::make_shared<Block>(opaque_block_uid);
|
||||
parent_block.AddChild(child_block);
|
||||
|
||||
m_ast->GetOrCreateBlockDecl(block_id);
|
||||
switch (sym.kind()) {
|
||||
case S_GPROC32:
|
||||
case S_LPROC32: {
|
||||
// This is a function. It must be global. Creating the Function entry
|
||||
// for it automatically creates a block for it.
|
||||
FunctionSP func = GetOrCreateFunction(block_id, *comp_unit);
|
||||
Block &block = func->GetBlock(false);
|
||||
if (block.GetNumRanges() == 0)
|
||||
block.AddRange(Block::Range(0, func->GetAddressRange().GetByteSize()));
|
||||
return block;
|
||||
}
|
||||
case S_BLOCK32: {
|
||||
// This is a block. Its parent is either a function or another block. In
|
||||
// either case, its parent can be viewed as a block (e.g. a function
|
||||
// contains 1 big block. So just get the parent block and add this block
|
||||
// to it.
|
||||
BlockSym block(static_cast<SymbolRecordKind>(sym.kind()));
|
||||
cantFail(SymbolDeserializer::deserializeAs<BlockSym>(sym, block));
|
||||
lldbassert(block.Parent != 0);
|
||||
PdbCompilandSymId parent_id(block_id.modi, block.Parent);
|
||||
Block &parent_block = GetOrCreateBlock(parent_id);
|
||||
parent_block.AddChild(child_block);
|
||||
m_ast->GetOrCreateBlockDecl(block_id);
|
||||
m_blocks.insert({opaque_block_uid, child_block});
|
||||
break;
|
||||
}
|
||||
case S_INLINESITE: {
|
||||
// This ensures line table is parsed first so we have inline sites info.
|
||||
comp_unit->GetLineTable();
|
||||
|
||||
std::shared_ptr<InlineSite> inline_site = m_inline_sites[opaque_block_uid];
|
||||
Block &parent_block = GetOrCreateBlock(inline_site->parent_id);
|
||||
parent_block.AddChild(child_block);
|
||||
|
||||
// Copy ranges from InlineSite to Block.
|
||||
for (size_t i = 0; i < inline_site->ranges.GetSize(); ++i) {
|
||||
auto *entry = inline_site->ranges.GetEntryAtIndex(i);
|
||||
child_block->AddRange(
|
||||
Block::Range(entry->GetRangeBase(), entry->GetByteSize()));
|
||||
}
|
||||
child_block->FinalizeRanges();
|
||||
|
||||
// Get the inlined function callsite info.
|
||||
Declaration &decl = inline_site->inline_function_info->GetDeclaration();
|
||||
Declaration &callsite = inline_site->inline_function_info->GetCallSite();
|
||||
child_block->SetInlinedFunctionInfo(
|
||||
inline_site->inline_function_info->GetName().GetCString(), nullptr,
|
||||
&decl, &callsite);
|
||||
m_blocks.insert({opaque_block_uid, child_block});
|
||||
break;
|
||||
}
|
||||
default:
|
||||
lldbassert(false && "Symbol is not a block!");
|
||||
}
|
||||
|
||||
m_blocks.insert({opaque_block_uid, child_block});
|
||||
return *child_block;
|
||||
}
|
||||
|
||||
@@ -971,16 +1005,22 @@ uint32_t SymbolFileNativePDB::ResolveSymbolContext(
|
||||
continue;
|
||||
if (type == PDB_SymType::Function) {
|
||||
sc.function = GetOrCreateFunction(csid, *sc.comp_unit).get();
|
||||
sc.block = sc.GetFunctionBlock();
|
||||
Block &block = sc.function->GetBlock(true);
|
||||
addr_t func_base =
|
||||
sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();
|
||||
addr_t offset = file_addr - func_base;
|
||||
sc.block = block.FindInnermostBlockByOffset(offset);
|
||||
}
|
||||
|
||||
if (type == PDB_SymType::Block) {
|
||||
sc.block = &GetOrCreateBlock(csid);
|
||||
sc.function = sc.block->CalculateSymbolContextFunction();
|
||||
}
|
||||
resolved_flags |= eSymbolContextFunction;
|
||||
resolved_flags |= eSymbolContextBlock;
|
||||
break;
|
||||
if (sc.function)
|
||||
resolved_flags |= eSymbolContextFunction;
|
||||
if (sc.block)
|
||||
resolved_flags |= eSymbolContextBlock;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -998,43 +1038,24 @@ uint32_t SymbolFileNativePDB::ResolveSymbolContext(
|
||||
uint32_t SymbolFileNativePDB::ResolveSymbolContext(
|
||||
const SourceLocationSpec &src_location_spec,
|
||||
lldb::SymbolContextItem resolve_scope, SymbolContextList &sc_list) {
|
||||
return 0;
|
||||
}
|
||||
std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
|
||||
const uint32_t prev_size = sc_list.GetSize();
|
||||
if (resolve_scope & eSymbolContextCompUnit) {
|
||||
for (uint32_t cu_idx = 0, num_cus = GetNumCompileUnits(); cu_idx < num_cus;
|
||||
++cu_idx) {
|
||||
CompileUnit *cu = ParseCompileUnitAtIndex(cu_idx).get();
|
||||
if (!cu)
|
||||
continue;
|
||||
|
||||
static void AppendLineEntryToSequence(LineTable &table, LineSequence &sequence,
|
||||
const CompilandIndexItem &cci,
|
||||
lldb::addr_t base_addr,
|
||||
uint32_t file_number,
|
||||
const LineFragmentHeader &block,
|
||||
const LineNumberEntry &cur) {
|
||||
LineInfo cur_info(cur.Flags);
|
||||
|
||||
if (cur_info.isAlwaysStepInto() || cur_info.isNeverStepInto())
|
||||
return;
|
||||
|
||||
uint64_t addr = base_addr + cur.Offset;
|
||||
|
||||
bool is_statement = cur_info.isStatement();
|
||||
bool is_prologue = IsFunctionPrologue(cci, addr);
|
||||
bool is_epilogue = IsFunctionEpilogue(cci, addr);
|
||||
|
||||
uint32_t lno = cur_info.getStartLine();
|
||||
|
||||
table.AppendLineEntryToSequence(&sequence, addr, lno, 0, file_number,
|
||||
is_statement, false, is_prologue, is_epilogue,
|
||||
false);
|
||||
}
|
||||
|
||||
static void TerminateLineSequence(LineTable &table,
|
||||
const LineFragmentHeader &block,
|
||||
lldb::addr_t base_addr, uint32_t file_number,
|
||||
uint32_t last_line,
|
||||
std::unique_ptr<LineSequence> seq) {
|
||||
// The end is always a terminal entry, so insert it regardless.
|
||||
table.AppendLineEntryToSequence(seq.get(), base_addr + block.CodeSize,
|
||||
last_line, 0, file_number, false, false,
|
||||
false, false, true);
|
||||
table.InsertSequence(seq.get());
|
||||
bool file_spec_matches_cu_file_spec = FileSpec::Match(
|
||||
src_location_spec.GetFileSpec(), cu->GetPrimaryFile());
|
||||
if (file_spec_matches_cu_file_spec) {
|
||||
cu->ResolveSymbolContext(src_location_spec, resolve_scope, sc_list);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return sc_list.GetSize() - prev_size;
|
||||
}
|
||||
|
||||
bool SymbolFileNativePDB::ParseLineTable(CompileUnit &comp_unit) {
|
||||
@@ -1045,16 +1066,21 @@ bool SymbolFileNativePDB::ParseLineTable(CompileUnit &comp_unit) {
|
||||
std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
|
||||
PdbSymUid cu_id(comp_unit.GetID());
|
||||
lldbassert(cu_id.kind() == PdbSymUidKind::Compiland);
|
||||
CompilandIndexItem *cci =
|
||||
m_index->compilands().GetCompiland(cu_id.asCompiland().modi);
|
||||
lldbassert(cci);
|
||||
auto line_table = std::make_unique<LineTable>(&comp_unit);
|
||||
uint16_t modi = cu_id.asCompiland().modi;
|
||||
CompilandIndexItem *cii = m_index->compilands().GetCompiland(modi);
|
||||
lldbassert(cii);
|
||||
|
||||
// Parse DEBUG_S_LINES subsections first, then parse all S_INLINESITE records
|
||||
// in this CU. Add line entries into the set first so that if there are line
|
||||
// entries with same addres, the later is always more accurate than the
|
||||
// former.
|
||||
std::set<LineTable::Entry, LineTableEntryComparator> line_set;
|
||||
|
||||
// This is basically a copy of the .debug$S subsections from all original COFF
|
||||
// object files merged together with address relocations applied. We are
|
||||
// looking for all DEBUG_S_LINES subsections.
|
||||
for (const DebugSubsectionRecord &dssr :
|
||||
cci->m_debug_stream.getSubsectionsArray()) {
|
||||
cii->m_debug_stream.getSubsectionsArray()) {
|
||||
if (dssr.kind() != DebugSubsectionKind::Lines)
|
||||
continue;
|
||||
|
||||
@@ -1069,42 +1095,111 @@ bool SymbolFileNativePDB::ParseLineTable(CompileUnit &comp_unit) {
|
||||
uint64_t virtual_addr =
|
||||
m_index->MakeVirtualAddress(lfh->RelocSegment, lfh->RelocOffset);
|
||||
|
||||
const auto &checksums = cci->m_strings.checksums().getArray();
|
||||
const auto &strings = cci->m_strings.strings();
|
||||
for (const LineColumnEntry &group : lines) {
|
||||
// Indices in this structure are actually offsets of records in the
|
||||
// DEBUG_S_FILECHECKSUMS subsection. Those entries then have an index
|
||||
// into the global PDB string table.
|
||||
auto iter = checksums.at(group.NameIndex);
|
||||
if (iter == checksums.end())
|
||||
llvm::Expected<uint32_t> file_index_or_err =
|
||||
GetFileIndex(*cii, group.NameIndex);
|
||||
if (!file_index_or_err)
|
||||
continue;
|
||||
|
||||
llvm::Expected<llvm::StringRef> efn =
|
||||
strings.getString(iter->FileNameOffset);
|
||||
if (!efn) {
|
||||
llvm::consumeError(efn.takeError());
|
||||
continue;
|
||||
}
|
||||
|
||||
// LLDB wants the index of the file in the list of support files.
|
||||
auto fn_iter = llvm::find(cci->m_file_list, *efn);
|
||||
lldbassert(fn_iter != cci->m_file_list.end());
|
||||
uint32_t file_index = std::distance(cci->m_file_list.begin(), fn_iter);
|
||||
|
||||
std::unique_ptr<LineSequence> sequence(
|
||||
line_table->CreateLineSequenceContainer());
|
||||
uint32_t file_index = file_index_or_err.get();
|
||||
lldbassert(!group.LineNumbers.empty());
|
||||
|
||||
CompilandIndexItem::GlobalLineTable::Entry line_entry(
|
||||
LLDB_INVALID_ADDRESS, 0);
|
||||
for (const LineNumberEntry &entry : group.LineNumbers) {
|
||||
AppendLineEntryToSequence(*line_table, *sequence, *cci, virtual_addr,
|
||||
file_index, *lfh, entry);
|
||||
LineInfo cur_info(entry.Flags);
|
||||
|
||||
if (cur_info.isAlwaysStepInto() || cur_info.isNeverStepInto())
|
||||
continue;
|
||||
|
||||
uint64_t addr = virtual_addr + entry.Offset;
|
||||
|
||||
bool is_statement = cur_info.isStatement();
|
||||
bool is_prologue = IsFunctionPrologue(*cii, addr);
|
||||
bool is_epilogue = IsFunctionEpilogue(*cii, addr);
|
||||
|
||||
uint32_t lno = cur_info.getStartLine();
|
||||
|
||||
line_set.emplace(addr, lno, 0, file_index, is_statement, false,
|
||||
is_prologue, is_epilogue, false);
|
||||
|
||||
if (line_entry.GetRangeBase() != LLDB_INVALID_ADDRESS) {
|
||||
line_entry.SetRangeEnd(addr);
|
||||
cii->m_global_line_table.Append(line_entry);
|
||||
}
|
||||
line_entry.SetRangeBase(addr);
|
||||
line_entry.data = {file_index, lno};
|
||||
}
|
||||
LineInfo last_line(group.LineNumbers.back().Flags);
|
||||
TerminateLineSequence(*line_table, *lfh, virtual_addr, file_index,
|
||||
last_line.getEndLine(), std::move(sequence));
|
||||
line_set.emplace(virtual_addr + lfh->CodeSize, last_line.getEndLine(), 0,
|
||||
file_index, false, false, false, false, true);
|
||||
|
||||
if (line_entry.GetRangeBase() != LLDB_INVALID_ADDRESS) {
|
||||
line_entry.SetRangeEnd(virtual_addr + lfh->CodeSize);
|
||||
cii->m_global_line_table.Append(line_entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cii->m_global_line_table.Sort();
|
||||
|
||||
// Parse all S_INLINESITE in this CU.
|
||||
const CVSymbolArray &syms = cii->m_debug_stream.getSymbolArray();
|
||||
for (auto iter = syms.begin(); iter != syms.end();) {
|
||||
if (iter->kind() != S_LPROC32 && iter->kind() != S_GPROC32) {
|
||||
++iter;
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t record_offset = iter.offset();
|
||||
CVSymbol func_record =
|
||||
cii->m_debug_stream.readSymbolAtOffset(record_offset);
|
||||
SegmentOffsetLength sol = GetSegmentOffsetAndLength(func_record);
|
||||
addr_t file_vm_addr = m_index->MakeVirtualAddress(sol.so);
|
||||
AddressRange func_range(file_vm_addr, sol.length,
|
||||
comp_unit.GetModule()->GetSectionList());
|
||||
Address func_base = func_range.GetBaseAddress();
|
||||
PdbCompilandSymId func_id{modi, record_offset};
|
||||
|
||||
// Iterate all S_INLINESITEs in the function.
|
||||
auto parse_inline_sites = [&](SymbolKind kind, PdbCompilandSymId id) {
|
||||
if (kind != S_INLINESITE)
|
||||
return false;
|
||||
|
||||
ParseInlineSite(id, func_base);
|
||||
|
||||
for (const auto &line_entry :
|
||||
m_inline_sites[toOpaqueUid(id)]->line_entries) {
|
||||
// If line_entry is not terminal entry, remove previous line entry at
|
||||
// the same address and insert new one. Terminal entry inside an inline
|
||||
// site might not be terminal entry for its parent.
|
||||
if (!line_entry.is_terminal_entry)
|
||||
line_set.erase(line_entry);
|
||||
line_set.insert(line_entry);
|
||||
}
|
||||
// No longer useful after adding to line_set.
|
||||
m_inline_sites[toOpaqueUid(id)]->line_entries.clear();
|
||||
return true;
|
||||
};
|
||||
ParseSymbolArrayInScope(func_id, parse_inline_sites);
|
||||
// Jump to the end of the function record.
|
||||
iter = syms.at(getScopeEndOffset(func_record));
|
||||
}
|
||||
|
||||
cii->m_global_line_table.Clear();
|
||||
|
||||
// Add line entries in line_set to line_table.
|
||||
auto line_table = std::make_unique<LineTable>(&comp_unit);
|
||||
std::unique_ptr<LineSequence> sequence(
|
||||
line_table->CreateLineSequenceContainer());
|
||||
for (const auto &line_entry : line_set) {
|
||||
line_table->AppendLineEntryToSequence(
|
||||
sequence.get(), line_entry.file_addr, line_entry.line,
|
||||
line_entry.column, line_entry.file_idx,
|
||||
line_entry.is_start_of_statement, line_entry.is_start_of_basic_block,
|
||||
line_entry.is_prologue_end, line_entry.is_epilogue_begin,
|
||||
line_entry.is_terminal_entry);
|
||||
}
|
||||
line_table->InsertSequence(sequence.get());
|
||||
|
||||
if (line_table->GetSize() == 0)
|
||||
return false;
|
||||
|
||||
@@ -1117,6 +1212,33 @@ bool SymbolFileNativePDB::ParseDebugMacros(CompileUnit &comp_unit) {
|
||||
return false;
|
||||
}
|
||||
|
||||
llvm::Expected<uint32_t>
|
||||
SymbolFileNativePDB::GetFileIndex(const CompilandIndexItem &cii,
|
||||
uint32_t file_id) {
|
||||
auto index_iter = m_file_indexes.find(file_id);
|
||||
if (index_iter != m_file_indexes.end())
|
||||
return index_iter->getSecond();
|
||||
const auto &checksums = cii.m_strings.checksums().getArray();
|
||||
const auto &strings = cii.m_strings.strings();
|
||||
// Indices in this structure are actually offsets of records in the
|
||||
// DEBUG_S_FILECHECKSUMS subsection. Those entries then have an index
|
||||
// into the global PDB string table.
|
||||
auto iter = checksums.at(file_id);
|
||||
if (iter == checksums.end())
|
||||
return llvm::make_error<RawError>(raw_error_code::no_entry);
|
||||
|
||||
llvm::Expected<llvm::StringRef> efn = strings.getString(iter->FileNameOffset);
|
||||
if (!efn) {
|
||||
return efn.takeError();
|
||||
}
|
||||
|
||||
// LLDB wants the index of the file in the list of support files.
|
||||
auto fn_iter = llvm::find(cii.m_file_list, *efn);
|
||||
lldbassert(fn_iter != cii.m_file_list.end());
|
||||
m_file_indexes[file_id] = std::distance(cii.m_file_list.begin(), fn_iter);
|
||||
return m_file_indexes[file_id];
|
||||
}
|
||||
|
||||
bool SymbolFileNativePDB::ParseSupportFiles(CompileUnit &comp_unit,
|
||||
FileSpecList &support_files) {
|
||||
std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
|
||||
@@ -1141,11 +1263,220 @@ bool SymbolFileNativePDB::ParseImportedModules(
|
||||
return false;
|
||||
}
|
||||
|
||||
void SymbolFileNativePDB::ParseInlineSite(PdbCompilandSymId id,
|
||||
Address func_addr) {
|
||||
lldb::user_id_t opaque_uid = toOpaqueUid(id);
|
||||
if (m_inline_sites.find(opaque_uid) != m_inline_sites.end())
|
||||
return;
|
||||
|
||||
addr_t func_base = func_addr.GetFileAddress();
|
||||
CompilandIndexItem *cii = m_index->compilands().GetCompiland(id.modi);
|
||||
CVSymbol sym = cii->m_debug_stream.readSymbolAtOffset(id.offset);
|
||||
CompUnitSP comp_unit = GetOrCreateCompileUnit(*cii);
|
||||
|
||||
InlineSiteSym inline_site(static_cast<SymbolRecordKind>(sym.kind()));
|
||||
cantFail(SymbolDeserializer::deserializeAs<InlineSiteSym>(sym, inline_site));
|
||||
PdbCompilandSymId parent_id(id.modi, inline_site.Parent);
|
||||
|
||||
std::shared_ptr<InlineSite> inline_site_sp =
|
||||
std::make_shared<InlineSite>(parent_id);
|
||||
|
||||
// Get the inlined function declaration info.
|
||||
auto iter = cii->m_inline_map.find(inline_site.Inlinee);
|
||||
if (iter == cii->m_inline_map.end())
|
||||
return;
|
||||
InlineeSourceLine inlinee_line = iter->second;
|
||||
|
||||
const FileSpecList &files = comp_unit->GetSupportFiles();
|
||||
FileSpec decl_file;
|
||||
llvm::Expected<uint32_t> file_index_or_err =
|
||||
GetFileIndex(*cii, inlinee_line.Header->FileID);
|
||||
if (!file_index_or_err)
|
||||
return;
|
||||
uint32_t decl_file_idx = file_index_or_err.get();
|
||||
decl_file = files.GetFileSpecAtIndex(decl_file_idx);
|
||||
uint32_t decl_line = inlinee_line.Header->SourceLineNum;
|
||||
std::unique_ptr<Declaration> decl_up =
|
||||
std::make_unique<Declaration>(decl_file, decl_line);
|
||||
|
||||
// Parse range and line info.
|
||||
uint32_t code_offset = 0;
|
||||
int32_t line_offset = 0;
|
||||
bool has_base = false;
|
||||
bool is_new_line_offset = false;
|
||||
|
||||
bool is_start_of_statement = false;
|
||||
// The first instruction is the prologue end.
|
||||
bool is_prologue_end = true;
|
||||
|
||||
auto change_code_offset = [&](uint32_t code_delta) {
|
||||
if (has_base) {
|
||||
inline_site_sp->ranges.Append(RangeSourceLineVector::Entry(
|
||||
code_offset, code_delta, decl_line + line_offset));
|
||||
is_prologue_end = false;
|
||||
is_start_of_statement = false;
|
||||
} else {
|
||||
is_start_of_statement = true;
|
||||
}
|
||||
has_base = true;
|
||||
code_offset += code_delta;
|
||||
|
||||
if (is_new_line_offset) {
|
||||
LineTable::Entry line_entry(func_base + code_offset,
|
||||
decl_line + line_offset, 0, decl_file_idx,
|
||||
true, false, is_prologue_end, false, false);
|
||||
inline_site_sp->line_entries.push_back(line_entry);
|
||||
is_new_line_offset = false;
|
||||
}
|
||||
};
|
||||
auto change_code_length = [&](uint32_t length) {
|
||||
inline_site_sp->ranges.Append(RangeSourceLineVector::Entry(
|
||||
code_offset, length, decl_line + line_offset));
|
||||
has_base = false;
|
||||
|
||||
LineTable::Entry end_line_entry(func_base + code_offset + length,
|
||||
decl_line + line_offset, 0, decl_file_idx,
|
||||
false, false, false, false, true);
|
||||
inline_site_sp->line_entries.push_back(end_line_entry);
|
||||
};
|
||||
auto change_line_offset = [&](int32_t line_delta) {
|
||||
line_offset += line_delta;
|
||||
if (has_base) {
|
||||
LineTable::Entry line_entry(
|
||||
func_base + code_offset, decl_line + line_offset, 0, decl_file_idx,
|
||||
is_start_of_statement, false, is_prologue_end, false, false);
|
||||
inline_site_sp->line_entries.push_back(line_entry);
|
||||
} else {
|
||||
// Add line entry in next call to change_code_offset.
|
||||
is_new_line_offset = true;
|
||||
}
|
||||
};
|
||||
|
||||
for (auto &annot : inline_site.annotations()) {
|
||||
switch (annot.OpCode) {
|
||||
case BinaryAnnotationsOpCode::CodeOffset:
|
||||
case BinaryAnnotationsOpCode::ChangeCodeOffset:
|
||||
case BinaryAnnotationsOpCode::ChangeCodeOffsetBase:
|
||||
change_code_offset(annot.U1);
|
||||
break;
|
||||
case BinaryAnnotationsOpCode::ChangeLineOffset:
|
||||
change_line_offset(annot.S1);
|
||||
break;
|
||||
case BinaryAnnotationsOpCode::ChangeCodeLength:
|
||||
change_code_length(annot.U1);
|
||||
code_offset += annot.U1;
|
||||
break;
|
||||
case BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset:
|
||||
change_code_offset(annot.U1);
|
||||
change_line_offset(annot.S1);
|
||||
break;
|
||||
case BinaryAnnotationsOpCode::ChangeCodeLengthAndCodeOffset:
|
||||
change_code_offset(annot.U2);
|
||||
change_code_length(annot.U1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
inline_site_sp->ranges.Sort();
|
||||
inline_site_sp->ranges.CombineConsecutiveEntriesWithEqualData();
|
||||
|
||||
// Get the inlined function callsite info.
|
||||
std::unique_ptr<Declaration> callsite_up;
|
||||
if (!inline_site_sp->ranges.IsEmpty()) {
|
||||
auto *entry = inline_site_sp->ranges.GetEntryAtIndex(0);
|
||||
addr_t base_offset = entry->GetRangeBase();
|
||||
if (cii->m_debug_stream.readSymbolAtOffset(parent_id.offset).kind() ==
|
||||
S_INLINESITE) {
|
||||
// Its parent is another inline site, lookup parent site's range vector
|
||||
// for callsite line.
|
||||
ParseInlineSite(parent_id, func_base);
|
||||
std::shared_ptr<InlineSite> parent_site =
|
||||
m_inline_sites[toOpaqueUid(parent_id)];
|
||||
FileSpec &parent_decl_file =
|
||||
parent_site->inline_function_info->GetDeclaration().GetFile();
|
||||
if (auto *parent_entry =
|
||||
parent_site->ranges.FindEntryThatContains(base_offset)) {
|
||||
callsite_up =
|
||||
std::make_unique<Declaration>(parent_decl_file, parent_entry->data);
|
||||
}
|
||||
} else {
|
||||
// Its parent is a function, lookup global line table for callsite.
|
||||
if (auto *entry = cii->m_global_line_table.FindEntryThatContains(
|
||||
func_base + base_offset)) {
|
||||
const FileSpec &callsite_file =
|
||||
files.GetFileSpecAtIndex(entry->data.first);
|
||||
callsite_up =
|
||||
std::make_unique<Declaration>(callsite_file, entry->data.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the inlined function name.
|
||||
CVType inlinee_cvt = m_index->ipi().getType(inline_site.Inlinee);
|
||||
std::string inlinee_name;
|
||||
if (inlinee_cvt.kind() == LF_MFUNC_ID) {
|
||||
MemberFuncIdRecord mfr;
|
||||
cantFail(
|
||||
TypeDeserializer::deserializeAs<MemberFuncIdRecord>(inlinee_cvt, mfr));
|
||||
LazyRandomTypeCollection &types = m_index->tpi().typeCollection();
|
||||
inlinee_name.append(std::string(types.getTypeName(mfr.ClassType)));
|
||||
inlinee_name.append("::");
|
||||
inlinee_name.append(mfr.getName().str());
|
||||
} else if (inlinee_cvt.kind() == LF_FUNC_ID) {
|
||||
FuncIdRecord fir;
|
||||
cantFail(TypeDeserializer::deserializeAs<FuncIdRecord>(inlinee_cvt, fir));
|
||||
TypeIndex parent_idx = fir.getParentScope();
|
||||
if (!parent_idx.isNoneType()) {
|
||||
LazyRandomTypeCollection &ids = m_index->ipi().typeCollection();
|
||||
inlinee_name.append(std::string(ids.getTypeName(parent_idx)));
|
||||
inlinee_name.append("::");
|
||||
}
|
||||
inlinee_name.append(fir.getName().str());
|
||||
}
|
||||
inline_site_sp->inline_function_info = std::make_shared<InlineFunctionInfo>(
|
||||
inlinee_name.c_str(), llvm::StringRef(), decl_up.get(),
|
||||
callsite_up.get());
|
||||
|
||||
m_inline_sites[opaque_uid] = inline_site_sp;
|
||||
}
|
||||
|
||||
size_t SymbolFileNativePDB::ParseBlocksRecursive(Function &func) {
|
||||
std::lock_guard<std::recursive_mutex> guard(GetModuleMutex());
|
||||
GetOrCreateBlock(PdbSymUid(func.GetID()).asCompilandSym());
|
||||
// FIXME: Parse child blocks
|
||||
return 1;
|
||||
PdbCompilandSymId func_id = PdbSymUid(func.GetID()).asCompilandSym();
|
||||
// After we iterate through inline sites inside the function, we already get
|
||||
// all the info needed, removing from the map to save memory.
|
||||
std::set<uint64_t> remove_uids;
|
||||
auto parse_inline_sites = [&](SymbolKind kind, PdbCompilandSymId id) {
|
||||
if (kind != S_INLINESITE)
|
||||
return false;
|
||||
GetOrCreateBlock(id);
|
||||
remove_uids.insert(toOpaqueUid(id));
|
||||
return true;
|
||||
};
|
||||
size_t count = ParseSymbolArrayInScope(func_id, parse_inline_sites);
|
||||
for (uint64_t uid : remove_uids) {
|
||||
m_inline_sites.erase(uid);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
size_t SymbolFileNativePDB::ParseSymbolArrayInScope(
|
||||
PdbCompilandSymId parent_id,
|
||||
llvm::function_ref<bool(SymbolKind, PdbCompilandSymId)> fn) {
|
||||
CompilandIndexItem *cii = m_index->compilands().GetCompiland(parent_id.modi);
|
||||
CVSymbolArray syms =
|
||||
cii->m_debug_stream.getSymbolArrayForScope(parent_id.offset);
|
||||
|
||||
size_t count = 1;
|
||||
for (auto iter = syms.begin(); iter != syms.end(); ++iter) {
|
||||
PdbCompilandSymId child_id(parent_id.modi, iter.offset());
|
||||
if (fn(iter->kind(), child_id))
|
||||
++count;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void SymbolFileNativePDB::DumpClangAST(Stream &s) { m_ast->Dump(s); }
|
||||
@@ -1396,6 +1727,9 @@ size_t SymbolFileNativePDB::ParseVariablesForBlock(PdbCompilandSymId block_id) {
|
||||
}
|
||||
case S_BLOCK32:
|
||||
break;
|
||||
case S_INLINESITE:
|
||||
// TODO: Handle inline site case.
|
||||
return 0;
|
||||
default:
|
||||
lldbassert(false && "Symbol is not a block!");
|
||||
return 0;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_SYMBOLFILENATIVEPDB_H
|
||||
#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_SYMBOLFILENATIVEPDB_H
|
||||
|
||||
#include "lldb/Symbol/LineTable.h"
|
||||
#include "lldb/Symbol/SymbolFile.h"
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
@@ -161,6 +162,25 @@ public:
|
||||
void DumpClangAST(Stream &s) override;
|
||||
|
||||
private:
|
||||
struct LineTableEntryComparator {
|
||||
bool operator()(const lldb_private::LineTable::Entry &lhs,
|
||||
const lldb_private::LineTable::Entry &rhs) const {
|
||||
return lhs.file_addr < rhs.file_addr;
|
||||
}
|
||||
};
|
||||
|
||||
// From address range relative to function base to source line number.
|
||||
using RangeSourceLineVector =
|
||||
lldb_private::RangeDataVector<uint32_t, uint32_t, int32_t>;
|
||||
// InlineSite contains information in a S_INLINESITE record.
|
||||
struct InlineSite {
|
||||
PdbCompilandSymId parent_id;
|
||||
std::shared_ptr<InlineFunctionInfo> inline_function_info;
|
||||
RangeSourceLineVector ranges;
|
||||
std::vector<lldb_private::LineTable::Entry> line_entries;
|
||||
InlineSite(PdbCompilandSymId parent_id) : parent_id(parent_id){};
|
||||
};
|
||||
|
||||
uint32_t CalculateNumCompileUnits() override;
|
||||
|
||||
lldb::CompUnitSP ParseCompileUnitAtIndex(uint32_t index) override;
|
||||
@@ -225,6 +245,16 @@ private:
|
||||
VariableList &variables);
|
||||
size_t ParseVariablesForBlock(PdbCompilandSymId block_id);
|
||||
|
||||
llvm::Expected<uint32_t> GetFileIndex(const CompilandIndexItem &cii,
|
||||
uint32_t file_id);
|
||||
|
||||
size_t ParseSymbolArrayInScope(
|
||||
PdbCompilandSymId parent,
|
||||
llvm::function_ref<bool(llvm::codeview::SymbolKind, PdbCompilandSymId)>
|
||||
fn);
|
||||
|
||||
void ParseInlineSite(PdbCompilandSymId inline_site_id, Address func_addr);
|
||||
|
||||
llvm::BumpPtrAllocator m_allocator;
|
||||
|
||||
lldb::addr_t m_obj_load_address = 0;
|
||||
@@ -241,6 +271,9 @@ private:
|
||||
llvm::DenseMap<lldb::user_id_t, lldb::FunctionSP> m_functions;
|
||||
llvm::DenseMap<lldb::user_id_t, lldb::CompUnitSP> m_compilands;
|
||||
llvm::DenseMap<lldb::user_id_t, lldb::TypeSP> m_types;
|
||||
llvm::DenseMap<lldb::user_id_t, std::shared_ptr<InlineSite>> m_inline_sites;
|
||||
// A map from file id in records to file index in support files.
|
||||
llvm::DenseMap<uint32_t, uint32_t> m_file_indexes;
|
||||
};
|
||||
|
||||
} // namespace npdb
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
image dump line-table a.cpp -v
|
||||
|
||||
b a.cpp:5
|
||||
b a.h:5
|
||||
b a.h:6
|
||||
b a.h:7
|
||||
b b.h:6
|
||||
b c.h:6
|
||||
|
||||
image lookup -a 0x140001003 -v
|
||||
image lookup -a 0x140001004 -v
|
||||
image lookup -a 0x140001014 -v
|
||||
image lookup -a 0x14000101a -v
|
||||
image lookup -a 0x140001021 -v
|
||||
image lookup -a 0x140001028 -v
|
||||
|
||||
quit
|
||||
667
lldb/test/Shell/SymbolFile/NativePDB/inline_sites.s
Normal file
667
lldb/test/Shell/SymbolFile/NativePDB/inline_sites.s
Normal file
@@ -0,0 +1,667 @@
|
||||
# clang-format off
|
||||
# REQUIRES: lld, x86
|
||||
|
||||
# RUN: llvm-mc -triple=x86_64-windows-msvc --filetype=obj %s > %t.obj
|
||||
# RUN: lld-link -debug:full -nodefaultlib -entry:main %t.obj -out:%t.exe
|
||||
# RUN: env LLDB_USE_NATIVE_PDB_READER=1 %lldb -f %t.exe -s \
|
||||
# RUN: %p/Inputs/inline_sites.lldbinit 2>&1 | FileCheck %s
|
||||
|
||||
# Compiled from the following files, but replaced the call to abort with nop.
|
||||
# a.cpp:
|
||||
# #include "stdlib.h"
|
||||
# #include "a.h"
|
||||
# int main(int argc, char** argv) {
|
||||
# Namespace1::foo(2);
|
||||
# return 0;
|
||||
# }
|
||||
# a.h:
|
||||
# #include "b.h"
|
||||
# namespace Namespace1 {
|
||||
# inline void foo(int x) {
|
||||
# static volatile int gv_foo;
|
||||
# ++gv_foo;
|
||||
# if (!gv_foo)
|
||||
# abort();
|
||||
# Class1::bar(x + 1);
|
||||
# }
|
||||
# }
|
||||
# b.h:
|
||||
# #include "c.h"
|
||||
# class Class1 {
|
||||
# public:
|
||||
# inline static void bar(int x) {
|
||||
# static volatile int gv_bar;
|
||||
# ++gv_bar;
|
||||
# Namespace2::Class2::func(x + 1);
|
||||
# }
|
||||
# };
|
||||
# c.h:
|
||||
# namespace Namespace2{
|
||||
# class Class2{
|
||||
# public:
|
||||
# inline static void func(int x) {
|
||||
# static volatile int gv_func;
|
||||
# gv_func += x;
|
||||
# }
|
||||
# };
|
||||
# }
|
||||
|
||||
# CHECK: (lldb) image dump line-table a.cpp -v
|
||||
# CHECK-NEXT: Line table for /tmp/a.cpp in
|
||||
# CHECK-NEXT: 0x0000000140001000: /tmp/a.cpp:3
|
||||
# CHECK-NEXT: 0x0000000140001004: /tmp/a.h:5, is_start_of_statement = TRUE, is_prologue_end = TRUE
|
||||
# CHECK-NEXT: 0x000000014000100a: /tmp/a.h:6
|
||||
# CHECK-NEXT: 0x0000000140001014: /tmp/b.h:6, is_start_of_statement = TRUE, is_prologue_end = TRUE
|
||||
# CHECK-NEXT: 0x000000014000101a: /tmp/c.h:6, is_start_of_statement = TRUE, is_prologue_end = TRUE
|
||||
# CHECK-NEXT: 0x0000000140001021: /tmp/a.cpp:5
|
||||
# CHECK-NEXT: 0x0000000140001028: /tmp/a.h:7, is_start_of_statement = TRUE
|
||||
# CHECK-NEXT: 0x000000014000102a: /tmp/a.cpp:5, is_terminal_entry = TRUE
|
||||
|
||||
# CEHCK: (lldb) b a.cpp:5
|
||||
# CHECK: Breakpoint 1: where = {{.*}}`main + 33 at a.cpp:5, address = 0x0000000140001021
|
||||
# CEHCK: (lldb) b a.h:5
|
||||
# CHECK: Breakpoint 2: where = {{.*}}`main + 4 [inlined] Namespace1::foo at a.h:5, address = 0x0000000140001004
|
||||
# CEHCK: (lldb) b a.h:6
|
||||
# CHECK: Breakpoint 3: where = {{.*}}`main + 10 [inlined] Namespace1::foo + 6 at a.h:6, address = 0x000000014000100a
|
||||
# CEHCK: (lldb) b a.h:7
|
||||
# CHECK: Breakpoint 4: where = {{.*}}`main + 40 [inlined] Namespace1::foo at a.h:7, address = 0x0000000140001028
|
||||
# CEHCK: (lldb) b b.h:6
|
||||
# CHECK: Breakpoint 5: where = {{.*}}`main + 20 [inlined] Class1::bar at b.h:6, address = 0x0000000140001014
|
||||
# CEHCK: (lldb) b c.h:6
|
||||
# CHECK: Breakpoint 6: where = {{.*}}`main + 26 [inlined] Namespace2::Class2::func at c.h:6, address = 0x000000014000101a
|
||||
|
||||
# CEHCK-LABEL: (lldb) image lookup -a 0x140001003 -v
|
||||
# CHECK: Summary: {{.*}}`main + 3 at a.cpp:3
|
||||
# CHECK: Function: id = {{.*}}, name = "main", range = [0x0000000140001000-0x000000014000102a)
|
||||
# CHECK: Blocks: id = {{.*}}, range = [0x140001000-0x14000102a)
|
||||
# CHECK: LineEntry: [0x0000000140001000-0x0000000140001004): /tmp/a.cpp:3
|
||||
|
||||
# CEHCK-LABEL: (lldb) image lookup -a 0x140001004 -v
|
||||
# CHECK: Summary: {{.*}}`main + 4 [inlined] Namespace1::foo at a.h:5
|
||||
# CHECK-NEXT: {{.*}}`main + 4 at a.cpp:4
|
||||
# CHECK: Function: id = {{.*}}, name = "main", range = [0x0000000140001000-0x000000014000102a)
|
||||
# CHECK: Blocks: id = {{.*}}, range = [0x140001000-0x14000102a)
|
||||
# CHECK-NEXT: id = {{.*}}, ranges = [0x140001004-0x140001021)[0x140001028-0x14000102a), name = "Namespace1::foo", decl = a.h:3
|
||||
# CHECK: LineEntry: [0x0000000140001004-0x000000014000100a): /tmp/a.h:5
|
||||
|
||||
# CEHCK-LABEL: (lldb) image lookup -a 0x140001014 -v
|
||||
# CHECK: Summary: {{.*}}`main + 20 [inlined] Class1::bar at b.h:6
|
||||
# CHECK-NEXT: {{.*}}`main + 20 [inlined] Namespace1::foo + 16 at a.h:8
|
||||
# CHECK-NEXT: {{.*}}`main + 4 at a.cpp:4
|
||||
# CHECK: Function: id = {{.*}}, name = "main", range = [0x0000000140001000-0x000000014000102a)
|
||||
# CHECK: Blocks: id = {{.*}}, range = [0x140001000-0x14000102a)
|
||||
# CHECK-NEXT: id = {{.*}}, ranges = [0x140001004-0x140001021)[0x140001028-0x14000102a), name = "Namespace1::foo", decl = a.h:3
|
||||
# CHECK-NEXT: id = {{.*}}, range = [0x140001014-0x140001021), name = "Class1::bar", decl = b.h:4
|
||||
# CHECK: LineEntry: [0x0000000140001014-0x000000014000101a): /tmp/b.h:6
|
||||
|
||||
# CEHCK-LABEL: (lldb) image lookup -a 0x14000101a -v
|
||||
# CHECK: Summary: {{.*}}`main + 26 [inlined] Namespace2::Class2::func at c.h:6
|
||||
# CHECK-NEXT: {{.*}}`main + 26 [inlined] Class1::bar + 6 at b.h:7
|
||||
# CHECK-NEXT: {{.*}}`main + 20 [inlined] Namespace1::foo + 16 at a.h:8
|
||||
# CHECK-NEXT: {{.*}}`main + 4 at a.cpp:4
|
||||
# CHECK: Function: id = {{.*}}, name = "main", range = [0x0000000140001000-0x000000014000102a)
|
||||
# CHECK: Blocks: id = {{.*}}, range = [0x140001000-0x14000102a)
|
||||
# CHECK-NEXT: id = {{.*}}, ranges = [0x140001004-0x140001021)[0x140001028-0x14000102a), name = "Namespace1::foo", decl = a.h:3
|
||||
# CHECK-NEXT: id = {{.*}}, range = [0x140001014-0x140001021), name = "Class1::bar", decl = b.h:4
|
||||
# CHECK-NEXT: id = {{.*}}, range = [0x14000101a-0x140001021), name = "Namespace2::Class2::func", decl = c.h:4
|
||||
# CHECK: LineEntry: [0x000000014000101a-0x0000000140001021): /tmp/c.h:6
|
||||
|
||||
# CEHCK-LABEL: (lldb) image lookup -a 0x140001021 -v
|
||||
# CHECK: Summary: {{.*}}`main + 33 at a.cpp:5
|
||||
# CHECK: Function: id = {{.*}}, name = "main", range = [0x0000000140001000-0x000000014000102a)
|
||||
# CHECK: Blocks: id = {{.*}}, range = [0x140001000-0x14000102a)
|
||||
# CHECK: LineEntry: [0x0000000140001021-0x0000000140001028): /tmp/a.cpp:5
|
||||
|
||||
# CEHCK-LABEL: (lldb) image lookup -a 0x140001028 -v
|
||||
# CHECK: Summary: {{.*}}`main + 40 [inlined] Namespace1::foo at a.h:7
|
||||
# CHECK-NEXT: {{.*}}`main + 40 at a.cpp:4
|
||||
# CHECK: Function: id = {{.*}}, name = "main", range = [0x0000000140001000-0x000000014000102a)
|
||||
# CHECK: Blocks: id = {{.*}}, range = [0x140001000-0x14000102a)
|
||||
# CHECK-NEXT: id = {{.*}}, ranges = [0x140001004-0x140001021)[0x140001028-0x14000102a), name = "Namespace1::foo", decl = a.h:3
|
||||
# CHECK: LineEntry: [0x0000000140001028-0x000000014000102a): /tmp/a.h:7
|
||||
|
||||
.text
|
||||
.def @feat.00;
|
||||
.scl 3;
|
||||
.type 0;
|
||||
.endef
|
||||
.globl @feat.00
|
||||
.set @feat.00, 0
|
||||
.intel_syntax noprefix
|
||||
.file "a.cpp"
|
||||
.def main;
|
||||
.scl 2;
|
||||
.type 32;
|
||||
.endef
|
||||
.section .text,"xr",one_only,main
|
||||
.globl main # -- Begin function main
|
||||
main: # @main
|
||||
.Lfunc_begin0:
|
||||
.cv_func_id 0
|
||||
.cv_file 1 "/tmp/a.cpp" "4ECCDD2814054DCF80EA72F4349036C4" 1
|
||||
.cv_loc 0 1 3 0 # a.cpp:3:0
|
||||
.seh_proc main
|
||||
# %bb.0: # %entry
|
||||
#DEBUG_VALUE: main:argv <- $rdx
|
||||
#DEBUG_VALUE: main:argc <- $ecx
|
||||
#DEBUG_VALUE: foo:x <- 2
|
||||
sub rsp, 40
|
||||
.seh_stackalloc 40
|
||||
.seh_endprologue
|
||||
.Ltmp0:
|
||||
.cv_file 2 "/tmp/./a.h" "9E656AFA1B1B681265C87EEA8BBE073E" 1
|
||||
.cv_inline_site_id 1 within 0 inlined_at 1 4 0
|
||||
.cv_loc 1 2 5 0 # ./a.h:5:0
|
||||
inc dword ptr [rip + "?gv_foo@?1??foo@Namespace1@@YAXH@Z@4HC"]
|
||||
.cv_loc 1 2 6 0 # ./a.h:6:0
|
||||
mov eax, dword ptr [rip + "?gv_foo@?1??foo@Namespace1@@YAXH@Z@4HC"]
|
||||
test eax, eax
|
||||
je .LBB0_2
|
||||
.Ltmp1:
|
||||
# %bb.1: # %"?foo@Namespace1@@YAXH@Z.exit"
|
||||
#DEBUG_VALUE: foo:x <- 2
|
||||
#DEBUG_VALUE: main:argc <- $ecx
|
||||
#DEBUG_VALUE: main:argv <- $rdx
|
||||
#DEBUG_VALUE: bar:x <- [DW_OP_plus_uconst 1, DW_OP_stack_value] 2
|
||||
.cv_file 3 "/tmp/./b.h" "BE52983EB17A3B0DA14E68A5CCBC4399" 1
|
||||
.cv_inline_site_id 2 within 1 inlined_at 2 8 0
|
||||
.cv_loc 2 3 6 0 # ./b.h:6:0
|
||||
inc dword ptr [rip + "?gv_bar@?1??bar@Class1@@SAXH@Z@4HC"]
|
||||
.Ltmp2:
|
||||
#DEBUG_VALUE: func:x <- 4
|
||||
.cv_file 4 "/tmp/./c.h" "D1B76A1C2A54DBEA648F3A11496166B8" 1
|
||||
.cv_inline_site_id 3 within 2 inlined_at 3 7 0
|
||||
.cv_loc 3 4 6 0 # ./c.h:6:0
|
||||
add dword ptr [rip + "?gv_func@?1??func@Class2@Namespace2@@SAXH@Z@4HC"], 4
|
||||
.Ltmp3:
|
||||
.cv_loc 0 1 5 0 # a.cpp:5:0
|
||||
xor eax, eax
|
||||
add rsp, 40
|
||||
ret
|
||||
.Ltmp4:
|
||||
.LBB0_2: # %if.then.i
|
||||
#DEBUG_VALUE: foo:x <- 2
|
||||
#DEBUG_VALUE: main:argc <- $ecx
|
||||
#DEBUG_VALUE: main:argv <- $rdx
|
||||
.cv_loc 1 2 7 0 # ./a.h:7:0
|
||||
nop
|
||||
.Ltmp5:
|
||||
int3
|
||||
.Ltmp6:
|
||||
#DEBUG_VALUE: main:argv <- [DW_OP_LLVM_entry_value 1] $rdx
|
||||
#DEBUG_VALUE: main:argc <- [DW_OP_LLVM_entry_value 1] $ecx
|
||||
.Lfunc_end0:
|
||||
.seh_endproc
|
||||
# -- End function
|
||||
.section .bss,"bw",discard,"?gv_foo@?1??foo@Namespace1@@YAXH@Z@4HC"
|
||||
.globl "?gv_foo@?1??foo@Namespace1@@YAXH@Z@4HC" # @"?gv_foo@?1??foo@Namespace1@@YAXH@Z@4HC"
|
||||
.p2align 2
|
||||
"?gv_foo@?1??foo@Namespace1@@YAXH@Z@4HC":
|
||||
.long 0 # 0x0
|
||||
|
||||
.section .bss,"bw",discard,"?gv_bar@?1??bar@Class1@@SAXH@Z@4HC"
|
||||
.globl "?gv_bar@?1??bar@Class1@@SAXH@Z@4HC" # @"?gv_bar@?1??bar@Class1@@SAXH@Z@4HC"
|
||||
.p2align 2
|
||||
"?gv_bar@?1??bar@Class1@@SAXH@Z@4HC":
|
||||
.long 0 # 0x0
|
||||
|
||||
.section .bss,"bw",discard,"?gv_func@?1??func@Class2@Namespace2@@SAXH@Z@4HC"
|
||||
.globl "?gv_func@?1??func@Class2@Namespace2@@SAXH@Z@4HC" # @"?gv_func@?1??func@Class2@Namespace2@@SAXH@Z@4HC"
|
||||
.p2align 2
|
||||
"?gv_func@?1??func@Class2@Namespace2@@SAXH@Z@4HC":
|
||||
.long 0 # 0x0
|
||||
|
||||
.section .drectve,"yn"
|
||||
.ascii " /DEFAULTLIB:libcmt.lib"
|
||||
.ascii " /DEFAULTLIB:oldnames.lib"
|
||||
.section .debug$S,"dr"
|
||||
.p2align 2
|
||||
.long 4 # Debug section magic
|
||||
.long 241
|
||||
.long .Ltmp8-.Ltmp7 # Subsection size
|
||||
.Ltmp7:
|
||||
.short .Ltmp10-.Ltmp9 # Record length
|
||||
.Ltmp9:
|
||||
.short 4353 # Record kind: S_OBJNAME
|
||||
.long 0 # Signature
|
||||
.asciz "/tmp/a-e5dd01.obj" # Object name
|
||||
.p2align 2
|
||||
.Ltmp10:
|
||||
.short .Ltmp12-.Ltmp11 # Record length
|
||||
.Ltmp11:
|
||||
.short 4412 # Record kind: S_COMPILE3
|
||||
.long 1 # Flags and language
|
||||
.short 208 # CPUType
|
||||
.short 14 # Frontend version
|
||||
.short 0
|
||||
.short 0
|
||||
.short 0
|
||||
.short 14000 # Backend version
|
||||
.short 0
|
||||
.short 0
|
||||
.short 0
|
||||
.asciz "clang version 14.0.0" # Null-terminated compiler version string
|
||||
.p2align 2
|
||||
.Ltmp12:
|
||||
.Ltmp8:
|
||||
.p2align 2
|
||||
.long 246 # Inlinee lines subsection
|
||||
.long .Ltmp14-.Ltmp13 # Subsection size
|
||||
.Ltmp13:
|
||||
.long 0 # Inlinee lines signature
|
||||
|
||||
# Inlined function foo starts at ./a.h:3
|
||||
.long 4099 # Type index of inlined function
|
||||
.cv_filechecksumoffset 2 # Offset into filechecksum table
|
||||
.long 3 # Starting line number
|
||||
|
||||
# Inlined function bar starts at ./b.h:4
|
||||
.long 4106 # Type index of inlined function
|
||||
.cv_filechecksumoffset 3 # Offset into filechecksum table
|
||||
.long 4 # Starting line number
|
||||
|
||||
# Inlined function func starts at ./c.h:4
|
||||
.long 4113 # Type index of inlined function
|
||||
.cv_filechecksumoffset 4 # Offset into filechecksum table
|
||||
.long 4 # Starting line number
|
||||
.Ltmp14:
|
||||
.p2align 2
|
||||
.section .debug$S,"dr",associative,main
|
||||
.p2align 2
|
||||
.long 4 # Debug section magic
|
||||
.long 241 # Symbol subsection for main
|
||||
.long .Ltmp16-.Ltmp15 # Subsection size
|
||||
.Ltmp15:
|
||||
.short .Ltmp18-.Ltmp17 # Record length
|
||||
.Ltmp17:
|
||||
.short 4423 # Record kind: S_GPROC32_ID
|
||||
.long 0 # PtrParent
|
||||
.long 0 # PtrEnd
|
||||
.long 0 # PtrNext
|
||||
.long .Lfunc_end0-main # Code size
|
||||
.long 0 # Offset after prologue
|
||||
.long 0 # Offset before epilogue
|
||||
.long 4117 # Function type index
|
||||
.secrel32 main # Function section relative address
|
||||
.secidx main # Function section index
|
||||
.byte 0 # Flags
|
||||
.asciz "main" # Function name
|
||||
.p2align 2
|
||||
.Ltmp18:
|
||||
.short .Ltmp20-.Ltmp19 # Record length
|
||||
.Ltmp19:
|
||||
.short 4114 # Record kind: S_FRAMEPROC
|
||||
.long 40 # FrameSize
|
||||
.long 0 # Padding
|
||||
.long 0 # Offset of padding
|
||||
.long 0 # Bytes of callee saved registers
|
||||
.long 0 # Exception handler offset
|
||||
.short 0 # Exception handler section
|
||||
.long 81920 # Flags (defines frame register)
|
||||
.p2align 2
|
||||
.Ltmp20:
|
||||
.short .Ltmp22-.Ltmp21 # Record length
|
||||
.Ltmp21:
|
||||
.short 4414 # Record kind: S_LOCAL
|
||||
.long 116 # TypeIndex
|
||||
.short 1 # Flags
|
||||
.asciz "argc"
|
||||
.p2align 2
|
||||
.Ltmp22:
|
||||
.cv_def_range .Lfunc_begin0 .Ltmp5, reg, 18
|
||||
.short .Ltmp24-.Ltmp23 # Record length
|
||||
.Ltmp23:
|
||||
.short 4414 # Record kind: S_LOCAL
|
||||
.long 4114 # TypeIndex
|
||||
.short 1 # Flags
|
||||
.asciz "argv"
|
||||
.p2align 2
|
||||
.Ltmp24:
|
||||
.cv_def_range .Lfunc_begin0 .Ltmp5, reg, 331
|
||||
.short .Ltmp26-.Ltmp25 # Record length
|
||||
.Ltmp25:
|
||||
.short 4365 # Record kind: S_GDATA32
|
||||
.long 4118 # Type
|
||||
.secrel32 "?gv_foo@?1??foo@Namespace1@@YAXH@Z@4HC" # DataOffset
|
||||
.secidx "?gv_foo@?1??foo@Namespace1@@YAXH@Z@4HC" # Segment
|
||||
.asciz "Namespace1::foo::gv_foo" # Name
|
||||
.p2align 2
|
||||
.Ltmp26:
|
||||
.short .Ltmp28-.Ltmp27 # Record length
|
||||
.Ltmp27:
|
||||
.short 4365 # Record kind: S_GDATA32
|
||||
.long 4118 # Type
|
||||
.secrel32 "?gv_bar@?1??bar@Class1@@SAXH@Z@4HC" # DataOffset
|
||||
.secidx "?gv_bar@?1??bar@Class1@@SAXH@Z@4HC" # Segment
|
||||
.asciz "Class1::bar::gv_bar" # Name
|
||||
.p2align 2
|
||||
.Ltmp28:
|
||||
.short .Ltmp30-.Ltmp29 # Record length
|
||||
.Ltmp29:
|
||||
.short 4365 # Record kind: S_GDATA32
|
||||
.long 4118 # Type
|
||||
.secrel32 "?gv_func@?1??func@Class2@Namespace2@@SAXH@Z@4HC" # DataOffset
|
||||
.secidx "?gv_func@?1??func@Class2@Namespace2@@SAXH@Z@4HC" # Segment
|
||||
.asciz "Namespace2::Class2::func::gv_func" # Name
|
||||
.p2align 2
|
||||
.Ltmp30:
|
||||
.short .Ltmp32-.Ltmp31 # Record length
|
||||
.Ltmp31:
|
||||
.short 4429 # Record kind: S_INLINESITE
|
||||
.long 0 # PtrParent
|
||||
.long 0 # PtrEnd
|
||||
.long 4099 # Inlinee type index
|
||||
.cv_inline_linetable 1 2 3 .Lfunc_begin0 .Lfunc_end0
|
||||
.p2align 2
|
||||
.Ltmp32:
|
||||
.short .Ltmp34-.Ltmp33 # Record length
|
||||
.Ltmp33:
|
||||
.short 4414 # Record kind: S_LOCAL
|
||||
.long 116 # TypeIndex
|
||||
.short 257 # Flags
|
||||
.asciz "x"
|
||||
.p2align 2
|
||||
.Ltmp34:
|
||||
.short .Ltmp36-.Ltmp35 # Record length
|
||||
.Ltmp35:
|
||||
.short 4429 # Record kind: S_INLINESITE
|
||||
.long 0 # PtrParent
|
||||
.long 0 # PtrEnd
|
||||
.long 4106 # Inlinee type index
|
||||
.cv_inline_linetable 2 3 4 .Lfunc_begin0 .Lfunc_end0
|
||||
.p2align 2
|
||||
.Ltmp36:
|
||||
.short .Ltmp38-.Ltmp37 # Record length
|
||||
.Ltmp37:
|
||||
.short 4414 # Record kind: S_LOCAL
|
||||
.long 116 # TypeIndex
|
||||
.short 257 # Flags
|
||||
.asciz "x"
|
||||
.p2align 2
|
||||
.Ltmp38:
|
||||
.short .Ltmp40-.Ltmp39 # Record length
|
||||
.Ltmp39:
|
||||
.short 4429 # Record kind: S_INLINESITE
|
||||
.long 0 # PtrParent
|
||||
.long 0 # PtrEnd
|
||||
.long 4113 # Inlinee type index
|
||||
.cv_inline_linetable 3 4 4 .Lfunc_begin0 .Lfunc_end0
|
||||
.p2align 2
|
||||
.Ltmp40:
|
||||
.short .Ltmp42-.Ltmp41 # Record length
|
||||
.Ltmp41:
|
||||
.short 4414 # Record kind: S_LOCAL
|
||||
.long 116 # TypeIndex
|
||||
.short 257 # Flags
|
||||
.asciz "x"
|
||||
.p2align 2
|
||||
.Ltmp42:
|
||||
.short 2 # Record length
|
||||
.short 4430 # Record kind: S_INLINESITE_END
|
||||
.short 2 # Record length
|
||||
.short 4430 # Record kind: S_INLINESITE_END
|
||||
.short 2 # Record length
|
||||
.short 4430 # Record kind: S_INLINESITE_END
|
||||
.short 2 # Record length
|
||||
.short 4431 # Record kind: S_PROC_ID_END
|
||||
.Ltmp16:
|
||||
.p2align 2
|
||||
.cv_linetable 0, main, .Lfunc_end0
|
||||
.section .debug$S,"dr"
|
||||
.long 241
|
||||
.long .Ltmp44-.Ltmp43 # Subsection size
|
||||
.Ltmp43:
|
||||
.short .Ltmp46-.Ltmp45 # Record length
|
||||
.Ltmp45:
|
||||
.short 4360 # Record kind: S_UDT
|
||||
.long 4103 # Type
|
||||
.asciz "Class1"
|
||||
.p2align 2
|
||||
.Ltmp46:
|
||||
.short .Ltmp48-.Ltmp47 # Record length
|
||||
.Ltmp47:
|
||||
.short 4360 # Record kind: S_UDT
|
||||
.long 4110 # Type
|
||||
.asciz "Namespace2::Class2"
|
||||
.p2align 2
|
||||
.Ltmp48:
|
||||
.Ltmp44:
|
||||
.p2align 2
|
||||
.cv_filechecksums # File index to string table offset subsection
|
||||
.cv_stringtable # String table
|
||||
.long 241
|
||||
.long .Ltmp50-.Ltmp49 # Subsection size
|
||||
.Ltmp49:
|
||||
.short .Ltmp52-.Ltmp51 # Record length
|
||||
.Ltmp51:
|
||||
.short 4428 # Record kind: S_BUILDINFO
|
||||
.long 4121 # LF_BUILDINFO index
|
||||
.p2align 2
|
||||
.Ltmp52:
|
||||
.Ltmp50:
|
||||
.p2align 2
|
||||
.section .debug$T,"dr"
|
||||
.p2align 2
|
||||
.long 4 # Debug section magic
|
||||
# StringId (0x1000)
|
||||
.short 0x12 # Record length
|
||||
.short 0x1605 # Record kind: LF_STRING_ID
|
||||
.long 0x0 # Id
|
||||
.asciz "Namespace1" # StringData
|
||||
.byte 241
|
||||
# ArgList (0x1001)
|
||||
.short 0xa # Record length
|
||||
.short 0x1201 # Record kind: LF_ARGLIST
|
||||
.long 0x1 # NumArgs
|
||||
.long 0x74 # Argument: int
|
||||
# Procedure (0x1002)
|
||||
.short 0xe # Record length
|
||||
.short 0x1008 # Record kind: LF_PROCEDURE
|
||||
.long 0x3 # ReturnType: void
|
||||
.byte 0x0 # CallingConvention: NearC
|
||||
.byte 0x0 # FunctionOptions
|
||||
.short 0x1 # NumParameters
|
||||
.long 0x1001 # ArgListType: (int)
|
||||
# FuncId (0x1003)
|
||||
.short 0xe # Record length
|
||||
.short 0x1601 # Record kind: LF_FUNC_ID
|
||||
.long 0x1000 # ParentScope: Namespace1
|
||||
.long 0x1002 # FunctionType: void (int)
|
||||
.asciz "foo" # Name
|
||||
# Class (0x1004)
|
||||
.short 0x2a # Record length
|
||||
.short 0x1504 # Record kind: LF_CLASS
|
||||
.short 0x0 # MemberCount
|
||||
.short 0x280 # Properties ( ForwardReference (0x80) | HasUniqueName (0x200) )
|
||||
.long 0x0 # FieldList
|
||||
.long 0x0 # DerivedFrom
|
||||
.long 0x0 # VShape
|
||||
.short 0x0 # SizeOf
|
||||
.asciz "Class1" # Name
|
||||
.asciz ".?AVClass1@@" # LinkageName
|
||||
.byte 242
|
||||
.byte 241
|
||||
# MemberFunction (0x1005)
|
||||
.short 0x1a # Record length
|
||||
.short 0x1009 # Record kind: LF_MFUNCTION
|
||||
.long 0x3 # ReturnType: void
|
||||
.long 0x1004 # ClassType: Class1
|
||||
.long 0x0 # ThisType
|
||||
.byte 0x0 # CallingConvention: NearC
|
||||
.byte 0x0 # FunctionOptions
|
||||
.short 0x1 # NumParameters
|
||||
.long 0x1001 # ArgListType: (int)
|
||||
.long 0x0 # ThisAdjustment
|
||||
# FieldList (0x1006)
|
||||
.short 0xe # Record length
|
||||
.short 0x1203 # Record kind: LF_FIELDLIST
|
||||
.short 0x1511 # Member kind: OneMethod ( LF_ONEMETHOD )
|
||||
.short 0xb # Attrs: Public, Static
|
||||
.long 0x1005 # Type: void Class1::(int)
|
||||
.asciz "bar" # Name
|
||||
# Class (0x1007)
|
||||
.short 0x2a # Record length
|
||||
.short 0x1504 # Record kind: LF_CLASS
|
||||
.short 0x1 # MemberCount
|
||||
.short 0x200 # Properties ( HasUniqueName (0x200) )
|
||||
.long 0x1006 # FieldList: <field list>
|
||||
.long 0x0 # DerivedFrom
|
||||
.long 0x0 # VShape
|
||||
.short 0x1 # SizeOf
|
||||
.asciz "Class1" # Name
|
||||
.asciz ".?AVClass1@@" # LinkageName
|
||||
.byte 242
|
||||
.byte 241
|
||||
# StringId (0x1008)
|
||||
.short 0x12 # Record length
|
||||
.short 0x1605 # Record kind: LF_STRING_ID
|
||||
.long 0x0 # Id
|
||||
.asciz "/tmp/./b.h" # StringData
|
||||
.byte 241
|
||||
# UdtSourceLine (0x1009)
|
||||
.short 0xe # Record length
|
||||
.short 0x1606 # Record kind: LF_UDT_SRC_LINE
|
||||
.long 0x1007 # UDT: Class1
|
||||
.long 0x1008 # SourceFile: /tmp/./b.h
|
||||
.long 0x2 # LineNumber
|
||||
# MemberFuncId (0x100A)
|
||||
.short 0xe # Record length
|
||||
.short 0x1602 # Record kind: LF_MFUNC_ID
|
||||
.long 0x1004 # ClassType: Class1
|
||||
.long 0x1005 # FunctionType: void Class1::(int)
|
||||
.asciz "bar" # Name
|
||||
# Class (0x100B)
|
||||
.short 0x42 # Record length
|
||||
.short 0x1504 # Record kind: LF_CLASS
|
||||
.short 0x0 # MemberCount
|
||||
.short 0x280 # Properties ( ForwardReference (0x80) | HasUniqueName (0x200) )
|
||||
.long 0x0 # FieldList
|
||||
.long 0x0 # DerivedFrom
|
||||
.long 0x0 # VShape
|
||||
.short 0x0 # SizeOf
|
||||
.asciz "Namespace2::Class2" # Name
|
||||
.asciz ".?AVClass2@Namespace2@@" # LinkageName
|
||||
.byte 243
|
||||
.byte 242
|
||||
.byte 241
|
||||
# MemberFunction (0x100C)
|
||||
.short 0x1a # Record length
|
||||
.short 0x1009 # Record kind: LF_MFUNCTION
|
||||
.long 0x3 # ReturnType: void
|
||||
.long 0x100b # ClassType: Namespace2::Class2
|
||||
.long 0x0 # ThisType
|
||||
.byte 0x0 # CallingConvention: NearC
|
||||
.byte 0x0 # FunctionOptions
|
||||
.short 0x1 # NumParameters
|
||||
.long 0x1001 # ArgListType: (int)
|
||||
.long 0x0 # ThisAdjustment
|
||||
# FieldList (0x100D)
|
||||
.short 0x12 # Record length
|
||||
.short 0x1203 # Record kind: LF_FIELDLIST
|
||||
.short 0x1511 # Member kind: OneMethod ( LF_ONEMETHOD )
|
||||
.short 0xb # Attrs: Public, Static
|
||||
.long 0x100c # Type: void Namespace2::Class2::(int)
|
||||
.asciz "func" # Name
|
||||
.byte 243
|
||||
.byte 242
|
||||
.byte 241
|
||||
# Class (0x100E)
|
||||
.short 0x42 # Record length
|
||||
.short 0x1504 # Record kind: LF_CLASS
|
||||
.short 0x1 # MemberCount
|
||||
.short 0x200 # Properties ( HasUniqueName (0x200) )
|
||||
.long 0x100d # FieldList: <field list>
|
||||
.long 0x0 # DerivedFrom
|
||||
.long 0x0 # VShape
|
||||
.short 0x1 # SizeOf
|
||||
.asciz "Namespace2::Class2" # Name
|
||||
.asciz ".?AVClass2@Namespace2@@" # LinkageName
|
||||
.byte 243
|
||||
.byte 242
|
||||
.byte 241
|
||||
# StringId (0x100F)
|
||||
.short 0x12 # Record length
|
||||
.short 0x1605 # Record kind: LF_STRING_ID
|
||||
.long 0x0 # Id
|
||||
.asciz "/tmp/./c.h" # StringData
|
||||
.byte 241
|
||||
# UdtSourceLine (0x1010)
|
||||
.short 0xe # Record length
|
||||
.short 0x1606 # Record kind: LF_UDT_SRC_LINE
|
||||
.long 0x100e # UDT: Namespace2::Class2
|
||||
.long 0x100f # SourceFile: /tmp/./c.h
|
||||
.long 0x2 # LineNumber
|
||||
# MemberFuncId (0x1011)
|
||||
.short 0x12 # Record length
|
||||
.short 0x1602 # Record kind: LF_MFUNC_ID
|
||||
.long 0x100b # ClassType: Namespace2::Class2
|
||||
.long 0x100c # FunctionType: void Namespace2::Class2::(int)
|
||||
.asciz "func" # Name
|
||||
.byte 243
|
||||
.byte 242
|
||||
.byte 241
|
||||
# Pointer (0x1012)
|
||||
.short 0xa # Record length
|
||||
.short 0x1002 # Record kind: LF_POINTER
|
||||
.long 0x670 # PointeeType: char*
|
||||
.long 0x1000c # Attrs: [ Type: Near64, Mode: Pointer, SizeOf: 8 ]
|
||||
# ArgList (0x1013)
|
||||
.short 0xe # Record length
|
||||
.short 0x1201 # Record kind: LF_ARGLIST
|
||||
.long 0x2 # NumArgs
|
||||
.long 0x74 # Argument: int
|
||||
.long 0x1012 # Argument: char**
|
||||
# Procedure (0x1014)
|
||||
.short 0xe # Record length
|
||||
.short 0x1008 # Record kind: LF_PROCEDURE
|
||||
.long 0x74 # ReturnType: int
|
||||
.byte 0x0 # CallingConvention: NearC
|
||||
.byte 0x0 # FunctionOptions
|
||||
.short 0x2 # NumParameters
|
||||
.long 0x1013 # ArgListType: (int, char**)
|
||||
# FuncId (0x1015)
|
||||
.short 0x12 # Record length
|
||||
.short 0x1601 # Record kind: LF_FUNC_ID
|
||||
.long 0x0 # ParentScope
|
||||
.long 0x1014 # FunctionType: int (int, char**)
|
||||
.asciz "main" # Name
|
||||
.byte 243
|
||||
.byte 242
|
||||
.byte 241
|
||||
# Modifier (0x1016)
|
||||
.short 0xa # Record length
|
||||
.short 0x1001 # Record kind: LF_MODIFIER
|
||||
.long 0x74 # ModifiedType: int
|
||||
.short 0x2 # Modifiers ( Volatile (0x2) )
|
||||
.byte 242
|
||||
.byte 241
|
||||
# StringId (0x1017)
|
||||
.short 0xe # Record length
|
||||
.short 0x1605 # Record kind: LF_STRING_ID
|
||||
.long 0x0 # Id
|
||||
.asciz "/tmp" # StringData
|
||||
.byte 243
|
||||
.byte 242
|
||||
.byte 241
|
||||
# StringId (0x1018)
|
||||
.short 0xe # Record length
|
||||
.short 0x1605 # Record kind: LF_STRING_ID
|
||||
.long 0x0 # Id
|
||||
.asciz "a.cpp" # StringData
|
||||
.byte 242
|
||||
.byte 241
|
||||
# BuildInfo (0x1019)
|
||||
.short 0x1a # Record length
|
||||
.short 0x1603 # Record kind: LF_BUILDINFO
|
||||
.short 0x5 # NumArgs
|
||||
.long 0x1017 # Argument: /tmp
|
||||
.long 0x0 # Argument
|
||||
.long 0x1018 # Argument: a.cpp
|
||||
.long 0x0 # Argument
|
||||
.long 0x0 # Argument
|
||||
.byte 242
|
||||
.byte 241
|
||||
.addrsig
|
||||
.addrsig_sym "?gv_foo@?1??foo@Namespace1@@YAXH@Z@4HC"
|
||||
.addrsig_sym "?gv_bar@?1??bar@Class1@@SAXH@Z@4HC"
|
||||
.addrsig_sym "?gv_func@?1??func@Class2@Namespace2@@SAXH@Z@4HC"
|
||||
Reference in New Issue
Block a user