#include "llvm/DebugInfo/CodeView/CodeView.h"
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecordHelpers.h"
#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h"
#include "llvm/Support/BinaryStreamArray.h"
#include "llvm/Support/ErrorHandling.h"
}
return Error::success();
}
+
+Error CVSymbolVisitor::visitSymbolStreamFiltered(const CVSymbolArray &Symbols,
+ const FilterOptions &Filter) {
+ if (!Filter.SymbolOffset)
+ return visitSymbolStream(Symbols);
+ uint32_t SymbolOffset = *Filter.SymbolOffset;
+ uint32_t ParentRecurseDepth =
+ Filter.ParentRecursiveDepth ? *Filter.ParentRecursiveDepth : 0;
+ uint32_t ChildrenRecurseDepth =
+ Filter.ChildRecursiveDepth ? *Filter.ChildRecursiveDepth : 0;
+ if (!Symbols.isOffsetValid(SymbolOffset))
+ return createStringError(inconvertibleErrorCode(), "Invalid symbol offset");
+ CVSymbol Sym = *Symbols.at(SymbolOffset);
+ uint32_t SymEndOffset =
+ symbolOpensScope(Sym.kind()) ? getScopeEndOffset(Sym) : 0;
+
+ std::vector<uint32_t> ParentOffsets;
+ std::vector<uint32_t> ParentEndOffsets;
+ uint32_t ChildrenDepth = 0;
+ for (auto Begin = Symbols.begin(), End = Symbols.end(); Begin != End;
+ ++Begin) {
+ uint32_t BeginOffset = Begin.offset();
+ CVSymbol BeginSym = *Begin;
+ if (BeginOffset < SymbolOffset) {
+ if (symbolOpensScope(Begin->kind())) {
+ uint32_t EndOffset = getScopeEndOffset(BeginSym);
+ if (SymbolOffset < EndOffset) {
+ ParentOffsets.push_back(BeginOffset);
+ ParentEndOffsets.push_back(EndOffset);
+ }
+ }
+ } else if (BeginOffset == SymbolOffset) {
+ // Found symbol at offset. Visit its parent up to ParentRecurseDepth.
+ if (ParentRecurseDepth >= ParentOffsets.size())
+ ParentRecurseDepth = ParentOffsets.size();
+ uint32_t StartIndex = ParentOffsets.size() - ParentRecurseDepth;
+ while (StartIndex < ParentOffsets.size()) {
+ if (!Symbols.isOffsetValid(ParentOffsets[StartIndex]))
+ break;
+ CVSymbol Parent = *Symbols.at(ParentOffsets[StartIndex]);
+ if (auto EC = visitSymbolRecord(Parent, ParentOffsets[StartIndex]))
+ return EC;
+ ++StartIndex;
+ }
+ if (auto EC = visitSymbolRecord(Sym, SymbolOffset))
+ return EC;
+ } else if (BeginOffset <= SymEndOffset) {
+ if (ChildrenRecurseDepth) {
+ // Visit children.
+ if (symbolEndsScope(Begin->kind()))
+ --ChildrenDepth;
+ if (ChildrenDepth < ChildrenRecurseDepth ||
+ BeginOffset == SymEndOffset) {
+ if (auto EC = visitSymbolRecord(BeginSym, BeginOffset))
+ return EC;
+ }
+ if (symbolOpensScope(Begin->kind()))
+ ++ChildrenDepth;
+ }
+ } else {
+ // Visit parents' ends.
+ if (ParentRecurseDepth && BeginOffset == ParentEndOffsets.back()) {
+ if (auto EC = visitSymbolRecord(BeginSym, BeginOffset))
+ return EC;
+ ParentEndOffsets.pop_back();
+ --ParentRecurseDepth;
+ }
+ }
+ }
+ return Error::success();
+}
--- /dev/null
+; RUN: llvm-pdbutil yaml2pdb %p/Inputs/symbol-offset.yaml --pdb=%t.pdb
+
+; RUN: llvm-pdbutil dump --symbols --modi=0 --symbol-offset=80 %t.pdb \
+; RUN: | FileCheck --check-prefix=OFFSET %s
+
+; RUN: llvm-pdbutil dump --symbols --modi=0 --symbol-offset=4 --show-parents \
+; RUN: %t.pdb | FileCheck --check-prefix=SHOW-PARENT1 %s
+
+; RUN: llvm-pdbutil dump --symbols --modi=0 --symbol-offset=80 --show-parents \
+; RUN: %t.pdb | FileCheck --check-prefix=SHOW-PARENT2 %s
+
+; RUN: llvm-pdbutil dump --symbols --modi=0 --symbol-offset=308 --show-parents \
+; RUN: %t.pdb | FileCheck --check-prefix=SHOW-PARENT3 %s
+
+; RUN: llvm-pdbutil dump --symbols --modi=0 --symbol-offset=260 --show-parents \
+; RUN: --parent-recurse-depth=1 %t.pdb \
+; RUN: | FileCheck --check-prefix=SHOW-PARENT-DEPTH1 %s
+
+; RUN: llvm-pdbutil dump --symbols --modi=0 --symbol-offset=260 --show-parents \
+; RUN: --parent-recurse-depth=2 %t.pdb \
+; RUN: | FileCheck --check-prefix=SHOW-PARENT-DEPTH2 %s
+
+; RUN: llvm-pdbutil dump --symbols --modi=0 --symbol-offset=416 --show-children\
+; RUN: %t.pdb | FileCheck --check-prefix=SHOW-CHILDREN1 %s
+
+; RUN: llvm-pdbutil dump --symbols --modi=0 --symbol-offset=292 --show-children\
+; RUN: %t.pdb | FileCheck --check-prefix=SHOW-CHILDREN2 %s
+
+; RUN: llvm-pdbutil dump --symbols --modi=0 --symbol-offset=4 --show-children \
+; RUN: --children-recurse-depth=1 %t.pdb \
+; RUN: | FileCheck --check-prefix=SHOW-CHILDREN-DEPTH1 %s
+
+; RUN: llvm-pdbutil dump --symbols --modi=0 --symbol-offset=292 --show-children\
+; RUN: --children-recurse-depth=2 %t.pdb \
+; RUN: | FileCheck --check-prefix=SHOW-CHILDREN-DEPTH2 %s
+
+The pdb file is generate from following cpp file and use llvm-pdbutil's pdb2yaml
+functionality to convert pdb to yaml. Unrelated information was removed from the
+yaml test file.
+; [[clang::always_inline]] int func1(int x) {
+; return x * 2;
+; }
+;
+; [[clang::always_inline]] int func2(int x, int y) {
+; return func1(x + y);
+; }
+;
+; [[clang::always_inline]] int func3(int x, int y, int z) {
+; y += func1(x);
+; x += func2(y, z);
+; return x + func1(x);
+; }
+;
+; int main(int argc, char** argv) {
+; return func3(argc, 1, 2);
+; }
+
+
+OFFSET: 80 | S_LOCAL [size = 16] `argc`
+OFFSET-NEXT: type=0x0074 (int), flags = param
+
+SHOW-PARENT1: 4 | S_GPROC32 [size = 44] `main`
+SHOW-PARENT1-NEXT: parent = 0, end = 468, addr = 0001:0176, code size = 137
+SHOW-PARENT1-NEXT: type = `0x1008 (<unknown UDT>)`, debug start = 0, debug end = 0, flags = none
+
+SHOW-PARENT2: 4 | S_GPROC32 [size = 44] `main`
+SHOW-PARENT2-NEXT: parent = 0, end = 468, addr = 0001:0176, code size = 137
+SHOW-PARENT2-NEXT: type = `0x1008 (<unknown UDT>)`, debug start = 0, debug end = 0, flags = none
+SHOW-PARENT2-NEXT: 80 | S_LOCAL [size = 16] `argc`
+SHOW-PARENT2-NEXT: type=0x0074 (int), flags = param
+SHOW-PARENT2-NEXT: 468 | S_END [size = 4]
+
+SHOW-PARENT3: 4 | S_GPROC32 [size = 44] `main`
+SHOW-PARENT3-NEXT: parent = 0, end = 468, addr = 0001:0176, code size = 137
+SHOW-PARENT3-NEXT: type = `0x1008 (<unknown UDT>)`, debug start = 0, debug end = 0, flags = none
+SHOW-PARENT3-NEXT: 144 | S_INLINESITE [size = 16]
+SHOW-PARENT3-NEXT: inlinee = 0x1002 (<unknown UDT>), parent = 4, end = 464
+SHOW-PARENT3-NEXT: 292 | S_INLINESITE [size = 16]
+SHOW-PARENT3-NEXT: inlinee = 0x1001 (<unknown UDT>), parent = 144, end = 412
+SHOW-PARENT3-NEXT: 308 | S_LOCAL [size = 12] `x`
+SHOW-PARENT3-NEXT: type=0x0074 (int), flags = param
+SHOW-PARENT3-NEXT: 412 | S_INLINESITE_END [size = 4]
+SHOW-PARENT3-NEXT: 464 | S_INLINESITE_END [size = 4]
+SHOW-PARENT3-NEXT: 468 | S_END [size = 4]
+
+
+SHOW-PARENT-DEPTH1: 244 | S_INLINESITE [size = 16]
+SHOW-PARENT-DEPTH1-NEXT: inlinee = 0x1000 (<unknown UDT>), parent = 144, end = 288
+SHOW-PARENT-DEPTH1-NEXT: 260 | S_LOCAL [size = 12] `x`
+SHOW-PARENT-DEPTH1-NEXT: type=0x0074 (int), flags = param
+SHOW-PARENT-DEPTH1-NEXT: 288 | S_INLINESITE_END [size = 4]
+
+SHOW-PARENT-DEPTH2: 144 | S_INLINESITE [size = 16]
+SHOW-PARENT-DEPTH2-NEXT: inlinee = 0x1002 (<unknown UDT>), parent = 4, end = 464
+SHOW-PARENT-DEPTH2-NEXT: 244 | S_INLINESITE [size = 16]
+SHOW-PARENT-DEPTH2-NEXT: inlinee = 0x1000 (<unknown UDT>), parent = 144, end = 288
+SHOW-PARENT-DEPTH2-NEXT: 260 | S_LOCAL [size = 12] `x`
+SHOW-PARENT-DEPTH2-NEXT: type=0x0074 (int), flags = param
+SHOW-PARENT-DEPTH2-NEXT: 288 | S_INLINESITE_END [size = 4]
+SHOW-PARENT-DEPTH2-NEXT: 464 | S_INLINESITE_END [size = 4]
+
+SHOW-CHILDREN1: 416 | S_INLINESITE [size = 16]
+SHOW-CHILDREN1-NEXT: inlinee = 0x1000 (<unknown UDT>), parent = 144, end = 460
+SHOW-CHILDREN1-NEXT: 432 | S_LOCAL [size = 12] `x`
+SHOW-CHILDREN1-NEXT: type=0x0074 (int), flags = param
+SHOW-CHILDREN1-NEXT: 444 | S_DEFRANGE_FRAMEPOINTER_REL [size = 16]
+SHOW-CHILDREN1-NEXT: offset = 36, range = [0001:0299,+7)
+SHOW-CHILDREN1-NEXT: gaps = []
+SHOW-CHILDREN1-NEXT: 460 | S_INLINESITE_END [size = 4]
+
+SHOW-CHILDREN2: 292 | S_INLINESITE [size = 16]
+SHOW-CHILDREN2-NEXT: inlinee = 0x1001 (<unknown UDT>), parent = 144, end = 412
+SHOW-CHILDREN2-NEXT: 308 | S_LOCAL [size = 12] `x`
+SHOW-CHILDREN2-NEXT: type=0x0074 (int), flags = param
+SHOW-CHILDREN2-NEXT: 320 | S_DEFRANGE_FRAMEPOINTER_REL [size = 16]
+SHOW-CHILDREN2-NEXT: offset = 44, range = [0001:0260,+19)
+SHOW-CHILDREN2-NEXT: gaps = []
+SHOW-CHILDREN2-NEXT: 336 | S_LOCAL [size = 12] `y`
+SHOW-CHILDREN2-NEXT: type=0x0074 (int), flags = param
+SHOW-CHILDREN2-NEXT: 348 | S_DEFRANGE_FRAMEPOINTER_REL [size = 16]
+SHOW-CHILDREN2-NEXT: offset = 48, range = [0001:0260,+19)
+SHOW-CHILDREN2-NEXT: gaps = []
+SHOW-CHILDREN2-NEXT: 364 | S_INLINESITE [size = 16]
+SHOW-CHILDREN2-NEXT: inlinee = 0x1000 (<unknown UDT>), parent = 292, end = 408
+SHOW-CHILDREN2-NEXT: 380 | S_LOCAL [size = 12] `x`
+SHOW-CHILDREN2-NEXT: type=0x0074 (int), flags = param
+SHOW-CHILDREN2-NEXT: 392 | S_DEFRANGE_FRAMEPOINTER_REL [size = 16]
+SHOW-CHILDREN2-NEXT: offset = 52, range = [0001:0272,+7)
+SHOW-CHILDREN2-NEXT: gaps = []
+SHOW-CHILDREN2-NEXT: 408 | S_INLINESITE_END [size = 4]
+SHOW-CHILDREN2-NEXT: 412 | S_INLINESITE_END [size = 4]
+
+SHOW-CHILDREN-DEPTH1: 4 | S_GPROC32 [size = 44] `main`
+SHOW-CHILDREN-DEPTH1-NEXT: parent = 0, end = 468, addr = 0001:0176, code size = 137
+SHOW-CHILDREN-DEPTH1-NEXT: type = `0x1008 (<unknown UDT>)`, debug start = 0, debug end = 0, flags = none
+SHOW-CHILDREN-DEPTH1-NEXT: 48 | S_FRAMEPROC [size = 32]
+SHOW-CHILDREN-DEPTH1-NEXT: size = 56, padding size = 0, offset to padding = 0
+SHOW-CHILDREN-DEPTH1-NEXT: bytes of callee saved registers = 0, exception handler addr = 0000:0000
+SHOW-CHILDREN-DEPTH1-NEXT: local fp reg = NONE, param fp reg = NONE
+SHOW-CHILDREN-DEPTH1-NEXT: flags = none
+SHOW-CHILDREN-DEPTH1-NEXT: 80 | S_LOCAL [size = 16] `argc`
+SHOW-CHILDREN-DEPTH1-NEXT: type=0x0074 (int), flags = param
+SHOW-CHILDREN-DEPTH1-NEXT: 96 | S_DEFRANGE_FRAMEPOINTER_REL [size = 16]
+SHOW-CHILDREN-DEPTH1-NEXT: offset = 4, range = [0001:0197,+116)
+SHOW-CHILDREN-DEPTH1-NEXT: gaps = []
+SHOW-CHILDREN-DEPTH1-NEXT: 112 | S_LOCAL [size = 16] `argv`
+SHOW-CHILDREN-DEPTH1-NEXT: type=0x1006 (<unknown UDT>), flags = param
+SHOW-CHILDREN-DEPTH1-NEXT: 128 | S_DEFRANGE_FRAMEPOINTER_REL [size = 16]
+SHOW-CHILDREN-DEPTH1-NEXT: offset = 8, range = [0001:0197,+116)
+SHOW-CHILDREN-DEPTH1-NEXT: gaps = []
+SHOW-CHILDREN-DEPTH1-NEXT: 144 | S_INLINESITE [size = 16]
+SHOW-CHILDREN-DEPTH1-NEXT: inlinee = 0x1002 (<unknown UDT>), parent = 4, end = 464
+SHOW-CHILDREN-DEPTH1-NEXT: 464 | S_INLINESITE_END [size = 4]
+SHOW-CHILDREN-DEPTH1-NEXT: 468 | S_END [size = 4]
+
+SHOW-CHILDREN-DEPTH2: 292 | S_INLINESITE [size = 16]
+SHOW-CHILDREN-DEPTH2-NEXT: inlinee = 0x1001 (<unknown UDT>), parent = 144, end = 412
+SHOW-CHILDREN-DEPTH2-NEXT: 308 | S_LOCAL [size = 12] `x`
+SHOW-CHILDREN-DEPTH2-NEXT: type=0x0074 (int), flags = param
+SHOW-CHILDREN-DEPTH2-NEXT: 320 | S_DEFRANGE_FRAMEPOINTER_REL [size = 16]
+SHOW-CHILDREN-DEPTH2-NEXT: offset = 44, range = [0001:0260,+19)
+SHOW-CHILDREN-DEPTH2-NEXT: gaps = []
+SHOW-CHILDREN-DEPTH2-NEXT: 336 | S_LOCAL [size = 12] `y`
+SHOW-CHILDREN-DEPTH2-NEXT: type=0x0074 (int), flags = param
+SHOW-CHILDREN-DEPTH2-NEXT: 348 | S_DEFRANGE_FRAMEPOINTER_REL [size = 16]
+SHOW-CHILDREN-DEPTH2-NEXT: offset = 48, range = [0001:0260,+19)
+SHOW-CHILDREN-DEPTH2-NEXT: gaps = []
+SHOW-CHILDREN-DEPTH2-NEXT: 364 | S_INLINESITE [size = 16]
+SHOW-CHILDREN-DEPTH2-NEXT: inlinee = 0x1000 (<unknown UDT>), parent = 292, end = 408
+SHOW-CHILDREN-DEPTH2-NEXT: 380 | S_LOCAL [size = 12] `x`
+SHOW-CHILDREN-DEPTH2-NEXT: type=0x0074 (int), flags = param
+SHOW-CHILDREN-DEPTH2-NEXT: 392 | S_DEFRANGE_FRAMEPOINTER_REL [size = 16]
+SHOW-CHILDREN-DEPTH2-NEXT: offset = 52, range = [0001:0272,+7)
+SHOW-CHILDREN-DEPTH2-NEXT: gaps = []
+SHOW-CHILDREN-DEPTH2-NEXT: 408 | S_INLINESITE_END [size = 4]
+SHOW-CHILDREN-DEPTH2-NEXT: 412 | S_INLINESITE_END [size = 4]
\ No newline at end of file
cl::opt<bool> DumpFpo("fpo", cl::desc("dump FPO records"),
cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
+cl::opt<uint32_t> DumpSymbolOffset(
+ "symbol-offset", cl::Optional,
+ cl::desc("only dump symbol record with the specified symbol offset"),
+ cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
+cl::opt<bool> DumpParents("show-parents",
+ cl::desc("dump the symbols record's all parents."),
+ cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
+cl::opt<uint32_t>
+ DumpParentDepth("parent-recurse-depth", cl::Optional, cl::init(-1U),
+ cl::desc("only recurse to a depth of N when displaying "
+ "parents of a symbol record."),
+ cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
+cl::opt<bool> DumpChildren("show-children",
+ cl::desc("dump the symbols record's all children."),
+ cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
+cl::opt<uint32_t>
+ DumpChildrenDepth("children-recurse-depth", cl::Optional, cl::init(-1U),
+ cl::desc("only recurse to a depth of N when displaying "
+ "children of a symbol record."),
+ cl::cat(SymbolOptions), cl::sub(DumpSubcommand));
+
// MODULE & FILE OPTIONS
cl::opt<bool> DumpModules("modules", cl::desc("dump compiland information"),
cl::cat(FileOptions), cl::sub(DumpSubcommand));
errs().flush();
exit(1);
}
- opts::Filters.NumOccurrences = opts::dump::DumpModi.getNumOccurrences();
opts::Filters.DumpModi = opts::dump::DumpModi;
}
+ if (opts::dump::DumpSymbolOffset) {
+ if (opts::dump::DumpModi.getNumOccurrences() != 1) {
+ errs()
+ << "need to specify argument '-modi' when using '-symbol-offset'.\n";
+ errs().flush();
+ exit(1);
+ }
+ opts::Filters.SymbolOffset = opts::dump::DumpSymbolOffset;
+ if (opts::dump::DumpParents)
+ opts::Filters.ParentRecurseDepth = opts::dump::DumpParentDepth;
+ if (opts::dump::DumpChildren)
+ opts::Filters.ChildrenRecurseDepth = opts::dump::DumpChildrenDepth;
+ }
if (opts::PdbToYamlSubcommand) {
pdb2Yaml(opts::pdb2yaml::InputFilename.front());