Index: llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst =================================================================== --- llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst +++ llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst @@ -464,12 +464,14 @@ :option:`--select` option. If :option:`--select-nocase` is specified, the regular expression becomes case-insensitive. -If the criteria is too general, a more selective option can -be specified to target a particular category of elements: +If the criteria is too general, a more selective option +(:ref:`filter-label`) can be specified to target a particular category +of elements: lines (:option:`--select-lines`), scopes (:option:`--select-scopes`), symbols (:option:`--select-symbols`) and types (:option:`--select-types`). + These options require knowledge of the debug information format (DWARF, -CodeView, COFF), as the given **kind** describes a very specific type +CodeView), as the given **kind** describes a very specific type of element. LINES @@ -576,6 +578,74 @@ =Unspecified: Unspecified type. =Volatile: Volatile specifier. +.. _filter-label: + +FILTER +^^^^^^ +If the output generated by any of the options (:option:`--select`), +(:option:`--select-elements`), (:option:`--select-lines`), +(:option:`--select-scopes`), (:option:`--select-symbols`), +(:option:`--select-types`) is too general, a combined selection can be +used to add extra filtering. + +:program:`llvm-debuginfo-analyzer` supports a combined selection feature, +that includes the and as a criteria, to allow the +selection of a specific of logical element, line, scope, symbol +or type that matches the given . + +The most basic combined criteria will include one of the following +options: + +.. code-block:: none + + --select= --select-elements= + +which select logical elements that satisfy the given +**and** whose name or line number matches the given . + +.. code-block:: none + + --select= --select-lines= + +which select logical lines that match the given **and** whose +line number matches . + +.. code-block:: none + + --select= --select-scopes= + +which select logical scopes that match the given **and** whose +name matches the given . + +.. code-block:: none + + --select= --select-symbols= + +which select logical symbols that match the given **and** whose +name matches the given . + +.. code-block:: none + + --select= --select-types= + +which select logical types that match the given **and** whose +name matches the given . + +For more specific combined criterias, a mix of the following options + +.. code-block:: none + + --select= --select-elements= + --select= --select-lines= + --select= --select-scopes= + --select= --select-symbols= + --select= --select-types= + +can be specified. A logical element, line, scope, symbol or type will +be selected if their name or line number matches any of the given +s **and** their or matches any of the given +s or s. + .. _compare_: COMPARE @@ -598,7 +668,7 @@ accuracy depends on how close the debug information represents the user code. For instance, a logical view created from a binary file with DWARF debug information may include more detailed data than a logical -view created from a binary file with CodeView/COFF debug information. +view created from a binary file with CodeView debug information. The following options describe the elements to compare. @@ -847,6 +917,51 @@ ----------------------------- Total 26 8 +COMBINED SELECT LOGICAL ELEMENTS +"""""""""""""""""""""""""""""""" +The following prints all *scopes* that are **Function**, all *lines* +that are **LineDebug** or **LineAssembler**, all *symbols* that are +**Parameter** and all *types* that are **Typedef** and that contain +**'foo'** or **'ParamBool'** or **'retq'** or **'INTEGER'** or **'6'** +in their names, types, assembler instructions or line numbers, using +a tab layout and given the number of matches. + +.. code-block:: none + + llvm-debuginfo-analyzer --attribute=level + --select=foo + --select=ParamBool + --select=retq + --select=INTEGER + --select=6 + --select-lines=LineAssembler,LineDebug + --select-scopes=Function + --select-symbols=Parameter + --select-types=Typedef + --report=list + --print=elements,summary + test-dwarf-clang.o + + Logical View: + [000] {File} 'test-dwarf-clang.o' + + [001] {CompileUnit} 'test.cpp' + [003] {Code} 'retq' + [003] 2 {Parameter} 'ParamBool' -> 'bool' + [002] 2 {Function} extern not_inlined 'foo' -> 'int' + [003] 4 {TypeAlias} 'INTEGER' -> 'int' + [004] 6 {Line} + + ----------------------------- + Element Total Found + ----------------------------- + Scopes 3 1 + Symbols 4 1 + Types 2 1 + Lines 25 2 + ----------------------------- + Total 34 5 + COMPARISON MODE ^^^^^^^^^^^^^^^ In this mode :program:`llvm-debuginfo-analyzer` compares logical views Index: llvm/include/llvm/DebugInfo/LogicalView/Core/LVOptions.h =================================================================== --- llvm/include/llvm/DebugInfo/LogicalView/Core/LVOptions.h +++ llvm/include/llvm/DebugInfo/LogicalView/Core/LVOptions.h @@ -232,19 +232,20 @@ class LVSelect { public: - bool IgnoreCase = false; // --select-ignore-case - bool UseRegex = false; // --select-use-regex - bool Execute = false; // Select requested. - bool GenericKind = false; // We have collected generic kinds. - bool GenericPattern = false; // We have collected generic patterns. - bool OffsetPattern = false; // We have collected offset patterns. - StringSet<> Generic; // --select= - LVOffsetSet Offsets; // --select-offset= - LVElementKindSet Elements; // --select-elements= - LVLineKindSet Lines; // --select-lines= - LVScopeKindSet Scopes; // --select-scopes= - LVSymbolKindSet Symbols; // --select-symbols= - LVTypeKindSelection Types; // --select-types= + bool IgnoreCase = false; // --select-ignore-case + bool UseRegex = false; // --select-use-regex + bool Execute = false; // Select requested. + bool GenericKind = false; // We have collected generic kinds. + bool GenericPattern = false; // We have collected generic patterns. + bool OffsetPattern = false; // We have collected offset patterns. + bool CombinedPattern = false; // We have combined selection. + StringSet<> Generic; // --select= + LVOffsetSet Offsets; // --select-offset= + LVElementKindSet Elements; // --select-elements= + LVLineKindSet Lines; // --select-lines= + LVScopeKindSet Scopes; // --select-scopes= + LVSymbolKindSet Symbols; // --select-symbols= + LVTypeKindSelection Types; // --select-types= }; class LVOutput { @@ -416,6 +417,7 @@ BOOL_FUNCTION(Select, GenericKind); BOOL_FUNCTION(Select, GenericPattern); BOOL_FUNCTION(Select, OffsetPattern); + BOOL_FUNCTION(Select, CombinedPattern); // --warning. WARNING_OPTION(All); @@ -507,6 +509,16 @@ void addElement(LVElement *Element); + // 'SelectCombinedPattern' is set when one or more of the '--select-xxx' + // and at least one '--select' options are specified in the command line, + // with '--select-xxx' being: + // --select-elements, --select-lines, --select-scopes + // --select-symbols, --select-types` + // + // There are 2 cases for the combined selection matching, with target being: + // - LVLine + // - LVScopes, LVSymbols, LVTypes + template void resolveGenericPatternMatch(T *Element, const U &Requests) { assert(Element && "Element must not be nullptr"); @@ -520,6 +532,12 @@ auto CheckOffset = [=]() -> bool { return matchOffsetPattern(Element->getOffset()); }; + if (options().getSelectCombinedPattern()) { + if (CheckPattern() && (Requests.size() || ElementRequest.size()) && + checkElementRequest(Element, Requests)) + addElement(Element); + return; + } if ((options().getSelectGenericPattern() && CheckPattern()) || (options().getSelectOffsetPattern() && CheckOffset()) || ((Requests.size() || ElementRequest.size()) && @@ -538,6 +556,12 @@ auto CheckOffset = [=]() -> bool { return matchOffsetPattern(Line->getAddress()); }; + if (options().getSelectCombinedPattern()) { + if (CheckPattern() && + (Requests.size() && checkElementRequest(Line, Requests))) + addElement(Line); + return; + } if ((options().getSelectGenericPattern() && CheckPattern()) || (options().getSelectOffsetPattern() && CheckOffset()) || (Requests.size() && checkElementRequest(Line, Requests))) Index: llvm/lib/DebugInfo/LogicalView/Core/LVOptions.cpp =================================================================== --- llvm/lib/DebugInfo/LogicalView/Core/LVOptions.cpp +++ llvm/lib/DebugInfo/LogicalView/Core/LVOptions.cpp @@ -369,12 +369,13 @@ // --select OS << "** Select **\n" - << "IgnoreCase: " << getSelectIgnoreCase() << ", " - << "UseRegex: " << getSelectUseRegex() << ", " - << "Execute: " << getSelectExecute() << ", " - << "GenericKind: " << getSelectGenericKind() << "\n" - << "GenericPattern: " << getSelectGenericPattern() << ", " - << "OffsetPattern: " << getSelectOffsetPattern() << "\n" + << "IgnoreCase: " << getSelectIgnoreCase() << ", " + << "UseRegex: " << getSelectUseRegex() << ", " + << "Execute: " << getSelectExecute() << ", " + << "GenericKind: " << getSelectGenericKind() << "\n" + << "GenericPattern: " << getSelectGenericPattern() << ", " + << "OffsetPattern: " << getSelectOffsetPattern() << "," + << "CombinedPattern: " << getSelectCombinedPattern() << "\n" << "\n"; // --warning @@ -490,6 +491,9 @@ void LVPatterns::updateReportOptions() { if (ElementRequest.size() || LineRequest.size() || ScopeRequest.size() || SymbolRequest.size() || TypeRequest.size()) { + // Compound selection. + if (options().getSelectGenericPattern()) + options().setSelectCombinedPattern(); options().setSelectGenericKind(); options().setSelectExecute(); } Index: llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp =================================================================== --- llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp +++ llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp @@ -741,9 +741,10 @@ (Scope->*SetFunction)(); - Traverse(Scope->getTypes()); - Traverse(Scope->getSymbols()); - Traverse(Scope->getLines()); + // The 'HasPattern' property for all the elements that meet the selection + // criteria is already set to true. Do not traverse the children that are + // types, symbols or lines, because that will include elements that do not + // meet the selection criteria. if (const LVScopes *Scopes = Scope->getScopes()) for (LVScope *Scope : *Scopes) Index: llvm/test/tools/llvm-debuginfo-analyzer/COFF/01-coff-select-logical-elements.test =================================================================== --- llvm/test/tools/llvm-debuginfo-analyzer/COFF/01-coff-select-logical-elements.test +++ llvm/test/tools/llvm-debuginfo-analyzer/COFF/01-coff-select-logical-elements.test @@ -93,3 +93,45 @@ ; THREE-EMPTY: ; THREE-NEXT: [001] {CompileUnit} 'test.cpp' ; THREE-NEXT: [002] {Function} extern not_inlined 'foo' -> 'int' + +; Select logical elements (Combined). +; The following prints all 'scopes:Function', 'lines:LineDebug', +; 'instructions:LineAssembler', 'symbols:Parameter' and 'types:Typedef' +; that contain 'foo', 'ParamBool', 'retq', 'INTEGER' or '6' in their +; names, types or line number, using a tab layout and given the number +; of matches. + +; RUN: llvm-debuginfo-analyzer --attribute=level \ +; RUN: --select=foo \ +; RUN: --select=ParamBool \ +; RUN: --select=retq \ +; RUN: --select=INTEGER \ +; RUN: --select=6 \ +; RUN: --select-lines=LineAssembler,LineDebug \ +; RUN: --select-scopes=Function \ +; RUN: --select-symbols=Parameter \ +; RUN: --select-types=Typedef \ +; RUN: --report=list \ +; RUN: --print=elements \ +; RUN: %p/Inputs/test-codeview-clang.o \ +; RUN: %p/Inputs/test-codeview-msvc.o 2>&1 | \ +; RUN: FileCheck --strict-whitespace -check-prefix=FOUR %s + +; FOUR: Logical View: +; FOUR-NEXT: [000] {File} 'test-codeview-clang.o' +; FOUR-EMPTY: +; FOUR-NEXT: [001] {CompileUnit} 'test.cpp' +; FOUR-NEXT: [003] {TypeAlias} 'INTEGER' -> 'int' +; FOUR-NEXT: [003] {Parameter} 'ParamBool' -> 'bool' +; FOUR-NEXT: [002] {Function} extern not_inlined 'foo' -> 'int' +; FOUR-NEXT: [003] {Code} 'retq' +; FOUR-NEXT: [004] 6 {Line} +; FOUR-EMPTY: +; FOUR-NEXT: Logical View: +; FOUR-NEXT: [000] {File} 'test-codeview-msvc.o' +; FOUR-EMPTY: +; FOUR-NEXT: [001] {CompileUnit} 'test.cpp' +; FOUR-NEXT: [004] {TypeAlias} 'INTEGER' -> 'int' +; FOUR-NEXT: [002] {Function} extern not_inlined 'foo' -> 'int' +; FOUR-NEXT: [003] {Code} 'retq' +; FOUR-NEXT: [004] 6 {Line} Index: llvm/test/tools/llvm-debuginfo-analyzer/DWARF/01-dwarf-select-logical-elements.test =================================================================== --- llvm/test/tools/llvm-debuginfo-analyzer/DWARF/01-dwarf-select-logical-elements.test +++ llvm/test/tools/llvm-debuginfo-analyzer/DWARF/01-dwarf-select-logical-elements.test @@ -96,3 +96,46 @@ ; THREE-EMPTY: ; THREE-NEXT: [001] {CompileUnit} 'test.cpp' ; THREE-NEXT: [002] 2 {Function} extern not_inlined 'foo' -> 'int' + +; Select logical elements (Combined). +; The following prints all 'scopes:Function', 'lines:LineDebug', +; 'instructions:LineAssembler', 'symbols:Parameter' and 'types:Typedef' +; that contain 'foo', 'ParamBool', 'retq', 'INTEGER' or '6' in their +; names, types or line number, using a tab layout and given the number +; of matches. + +; RUN: llvm-debuginfo-analyzer --attribute=level \ +; RUN: --select=foo \ +; RUN: --select=ParamBool \ +; RUN: --select=retq \ +; RUN: --select=INTEGER \ +; RUN: --select=6 \ +; RUN: --select-lines=LineAssembler,LineDebug \ +; RUN: --select-scopes=Function \ +; RUN: --select-symbols=Parameter \ +; RUN: --select-types=Typedef \ +; RUN: --report=list \ +; RUN: --print=elements \ +; RUN: %p/Inputs/test-dwarf-clang.o \ +; RUN: %p/Inputs/test-dwarf-gcc.o 2>&1 | \ +; RUN: FileCheck --strict-whitespace -check-prefix=FOUR %s + +; FOUR: Logical View: +; FOUR-NEXT: [000] {File} 'test-dwarf-clang.o' +; FOUR-EMPTY: +; FOUR-NEXT: [001] {CompileUnit} 'test.cpp' +; FOUR-NEXT: [003] {Code} 'retq' +; FOUR-NEXT: [003] 2 {Parameter} 'ParamBool' -> 'bool' +; FOUR-NEXT: [002] 2 {Function} extern not_inlined 'foo' -> 'int' +; FOUR-NEXT: [003] 4 {TypeAlias} 'INTEGER' -> 'int' +; FOUR-NEXT: [004] 6 {Line} +; FOUR-EMPTY: +; FOUR-NEXT: Logical View: +; FOUR-NEXT: [000] {File} 'test-dwarf-gcc.o' +; FOUR-EMPTY: +; FOUR-NEXT: [001] {CompileUnit} 'test.cpp' +; FOUR-NEXT: [003] {Code} 'retq' +; FOUR-NEXT: [003] 2 {Parameter} 'ParamBool' -> 'bool' +; FOUR-NEXT: [002] 2 {Function} extern not_inlined 'foo' -> 'int' +; FOUR-NEXT: [004] 4 {TypeAlias} 'INTEGER' -> 'int' +; FOUR-NEXT: [004] 6 {Line}