Index: llvm/docs/CommandGuide/index.rst =================================================================== --- llvm/docs/CommandGuide/index.rst +++ llvm/docs/CommandGuide/index.rst @@ -23,6 +23,7 @@ llvm-cxxmap llvm-diff llvm-dis + llvm-dva llvm-dwarfdump llvm-lib llvm-libtool-darwin Index: llvm/docs/CommandGuide/llvm-dva.rst =================================================================== --- /dev/null +++ llvm/docs/CommandGuide/llvm-dva.rst @@ -0,0 +1,1947 @@ +llvm-dva - Print a logical representation of low-level debug information. +========================================================================= + +.. program:: llvm-dva + +.. contents:: + :local: + +SYNOPSIS +-------- +:program:`llvm-dva` [*options*] [*filename ...*] + +DESCRIPTION +----------- +:program:`llvm-dva` parses debug and text sections in binary object +files and prints their contents in a logical view, which is a human +readable representation that closely matches the structure of the +original user source code. Supported object file formats include ELF, +MacOS, PDB and COFF. + +The **logical view** abstracts the complexity associated with the +different low-level representations of the debugging information that +is embedded in the object file. :program:`llvm-dva` produces a canonical +view of the debug information regardless of how it is formatted. The +same logical view will be seen regardless of object file format, assuming +the debug information correctly represents the same original source code. + +The logical view includes the following **logical elements**: *type*, +*scope*, *symbol* and *line*, which are the basic software elements used +in the C/C++ programming language. Each logical element has a set of +**attributes**, such as *types*, *classes*, *functions*, *variables*, +*parameters*, etc. The :option:`--attribute` can be used to specify which +attributes to include when printing a logical element. A logical element +may have a **kind** that describes specific types of elements. For +instance, a *scope* could have a kind value of *function*, *class*, +*namespace*. + +:program:`llvm-dva` defaults to print a pre-defined layout of logical +elements and attributes. The command line options can be used to control +the printed elements (:option:`--print`), using a specific layout +(:option:`--report`), matching a given pattern (:option:`--select`, +:option:`--select-offsets`). Also, the output can be limited to specified +logical elements using (:option:`--select-lines`, :option:`--select-scopes`, +:option:`--select-symbols`, :option:`--select-types`). + +:program:`llvm-dva` can also compare a set of logical views +(:option:`--compare`), to find differences and identify possible debug +information syntax issues (:option:`--warning`) in any object file. + +OPTIONS +------- +:program:`llvm-dva` options are separated into several categories, each +tailored to a different purpose: + + * :ref:`general_` - Standard LLVM options to display help, version, etc. + * :ref:`attributes_` - Describe how to include different details when + printing an element. + * :ref:`print_` - Specify which elements will be included when printing + the view. + * :ref:`output_` - Describe the supported formats when printing the view. + * :ref:`report_` - Describe the format layouts for view printing. + * :ref:`select_` - Allows to use specific criteria or conditions to + select which elements to print. + * :ref:`compare_` - Compare logical views and print missing and/or + added elements. + * :ref:`warning_` - Print the warnings detected during the creation + of the view. + * :ref:`internal_` - Internal analysis of the logical view. + +.. _general_: + +GENERAL +~~~~~~~ +This section describes the standard help options, used to display the +usage, version, response files, etc. + +.. option:: -h, --help + + Show help and usage for this command. (--help-hidden for more). + +.. option:: --help-list + + Show help and usage for this command without grouping the options + into categories (--help-list-hidden for more). + +.. option:: --help-hidden + + Display all available options. + +.. option:: --print-all-options + + Print all option values after command line parsing. + +.. option:: --print-options + + Print non-default options after command line parsing + +.. option:: --version + + Display the version of the tool. + +.. option:: @ + + Read command-line options from ``. + +If no input file is specified, :program:`llvm-dva` defaults to read +`a.out` and return an error when no input file is found. + +If `-` is used as the input file, :program:`llvm-dva` reads the input +from its standard input stream. + +.. _attributes_: + +ATTRIBUTES +~~~~~~~~~~ +The following options enable attributes given for the printed elements. +The attributes are divided in categories based on the type of data being +added, such as: internal offsets in the binary file, location descriptors, +register names, user source filenames, additional element transformations, +toolchain name, binary file format, etc. + +.. option:: --attribute= + + With **value** being one the options in the following lists. + + .. code-block:: text + + =all: Include all the below attributes. + =extended: Add low-level attributes. + =standard: Add standard high-level attributes. + + The following attributes describe the most common information for a + logical element. They help to identify the lexical scope level; the + element visibility across modules (global, local); the toolchain name + that produced the binary file. + + .. code-block:: text + + =global: Element referenced across Compile Units. + =format: Object file format name. + =level: Lexical scope level (File=0, Compile Unit=1). + =local: Element referenced only in the Compile Unit. + =producer: Toolchain identification name. + + The following attributes describe files and directory names from the + user source code, where the elements are declared or defined; functions + with public visibility across modules. These options allow to map the + elements to their user code location, for cross references purposes. + + .. code-block:: text + + =directories: Directories referenced in the debug information. + =filename: Filename where the element is defined. + =files: Files referenced in the debug information. + =pathname: Pathname where the object is defined. + =publics: Function names that are public. + + The following attributes describe additional logical element source + transformations, in order to display built-in types (int, bool, etc.); + parameters and arguments used during template instantiation; parent + name hierarchy; array dimensions information; compiler generated + elements and the underlying types associated with the types aliases. + + .. code-block:: text + + =argument: Template parameters replaced by its arguments. + =base: Base types (int, bool, etc.). + =generated: Compiler generated elements. + =encoded: Template arguments encoded in the template name. + =qualified: The element type include parents in its name. + =reference: Element declaration and definition references. + =subrange: Subrange encoding information for arrays. + =typename: Template parameters. + =underlying: Underlying type for type definitions. + + The following attributes describe the debug location information for + a symbol or scope. It includes the symbol percentage coverage and any + gaps within the location layout; ranges determining the code sections + attached to a function. When descriptors are used, the target processor + registers are displayed. + + .. code-block:: text + + =coverage: Symbol location coverage. + =gaps: Missing debug location (gaps). + =location: Symbol debug location. + =range: Debug location ranges. + =register: Processor register names. + + The following attributes are associated with low level details, such + as: offsets in the binary file; discriminators added to the lines of + inlined functions in order to distinguish specific instances; debug + lines state machine registers; elements discarded by the compiler + (inlining) or by the linker optimizations (dead-stripping); system + compile units generated by the MS toolchain in PDBs. + + .. code-block:: text + + =discarded: Discarded elements by the linker. + =discriminator: Discriminators for inlined function instances. + =inserted: Generated inlined abstract references. + =linkage: Object file linkage name. + =offset: Debug information offset. + =qualifier: Line qualifiers (Newstatement, BasicBlock, etc). + =zero: Zero line numbers. + + The following attribute described specific information for the **PE/COFF** + file format. It includes MS runtime types. + + .. code-block:: text + + =system: Display PDB's MS system elements. + + The above attributes are grouped into *standard* and *extended* + categories that can be enabled. + + The *standard* group, contains those attributes that add sufficient + information to describe a logical element and that can cover the + normal situations while dealing with debug information. + + .. code-block:: text + + =base + =coverage + =directories + =discriminator + =filename + =files + =format + =level + =producer + =publics + =range + =reference + =zero + + The *extended* group, contains those attributes that require a more + extended knowledge about debug information. They are intended to be + used when a more low level detail is required. + + .. code-block:: text + + =argument + =discarded + =encoded + =gaps + =generated + =global + =inserted + =linkage + =local + =location + =offset + =operation + =pathname + =qualified + =qualifier + =register + =subrange + =system + =typename + +.. _print_: + +PRINT +~~~~~ +The following options describe the elements to print. The layout used +is determined by the :option:`--report`. In the tree layout, all the +elements have their enclosing lexical scopes printed, even when not +explicitly specified. + +.. option:: --print= + + With **value** being one the options in the following lists. + + .. code-block:: text + + =all: Include all the below attributes. + + The following options print the requested elements; in the case of any + given select conditions (:option:`--select`), only those elements that + match them, will be printed. The **elements** value is a convenient + way to specify instructions, lines, scopes, symbols and types all at + once. + + .. code-block:: text + + =elements: Instructions, lines, scopes, symbols and types. + =instructions: Assembler instructions for code sections. + =lines: Source lines referenced in the debug information. + =scopes: Lexical blocks (function, class, namespace, etc). + =symbols: Symbols (variable, member, parameter, etc). + =types: Types (pointer, reference, type alias, etc). + + The following options print information, collected during the creation + of the elements, such as: scope contributions to the debug information; + summary of elements created, printed or matched (:option:`--select`); + warnings produced during the view creation. + + .. code-block:: text + + =sizes: Debug Information scopes contributions. + =summary: Summary of elements allocated, selected or printed. + =warnings: Warnings detected. + + Note: The **--print=sizes** option is ELF specific. + +.. _output_: + +OUTPUT +~~~~~~ +The following options describe how to control the output generated when +printing the logical elements. + +.. option:: --output-file= + + Redirect the output to a file specified by , where - is the + standard output stream. + +:program:`llvm-dva` has the concept of **split view**. When +redirecting the output from a complex binary format, it is **divided** +into individual files, each one containing the logical view output for +a single compilation unit. + +.. option:: --output-folder= + + The folder to write a file per compilation unit when **--output=split** + is specified. + +.. option:: --output-level= + + Only print elements up to the given **lexical level** value. The input + file is at lexical level zero and a compilation unit is at lexical level + one. + +.. option:: --output= + + With **value** being one the options in the following lists. + + .. code-block:: text + + =all: Include all the below outputs. + + .. code-block:: text + + =json: Use JSON as the output format (Not implemented). + =split: Split the output by Compile Units. + =text: Use a free form text output. + +.. option:: --output-sort= + + Primary key when ordering the elements in the output (default: line). + Sorting by logical element kind, requires be familiarity with the + element kind selection options (:option:`--select-lines`, + :option:`--select-scopes`, :option:`--select-symbols`, + :option:`--select-types`), as those options describe the different + logical element kinds. + + .. code-block:: text + + =kind: Sort by element kind. + =line: Sort by element line number. + =name: Sort by element name. + =offset: Sort by element offset. + +.. _report_: + +REPORT +~~~~~~ +Depending on the task being executed (print, compare, select), several +layouts are supported to display the elements in a more suitable way, +to make the output easier to understand. + +.. option:: --report= + + With **value** being one the options in the following list. + + .. code-block:: text + + =all: Include all the below reports. + + .. code-block:: text + + =children: Elements and children are displayed in a tree format. + =list: Elements are displayed in a tabular format. + =parents: Elements and parents are displayed in a tree format. + =view: Elements, parents and children are displayed in a tree format. + +The **list** layout presents the logical elements in a tabular form +without any parent-child relationship. This may be the preferred way to +display elements that match specific conditions when comparing logical +views, making it easier to find differences. + +The **children**, **parents** and **view** layout displays the elements +in a tree format, with the scopes representing their nodes, and types, +symbols, lines and other scopes representing the children. The layout +shows the lexical scoping relationship between elements, with the binary +file being the tree root (level 0) and each compilation unit being a +child (level 1). + +The **children** layout includes the elements that match any given +criteria (:option:`--select`) or (:option:`--compare`) and its children. + +The **parents** layout includes the elements that match any given +criteria (:option:`--select`) or (:option:`--compare`) and its parents. + +The combined **view** layout includes the elements that match any given +criteria (:option:`--select`) or (:option:`--compare`), its parents +and children. + +**Notes**: + +1. When a selection criteria (:option:`--select`) is specified with no + report option, the **list** layout is selected. +2. The comparison mode always uses the **view** layout. + +.. _select_: + +SELECTION +~~~~~~~~~ +When printing an element, different data can be included and it varies +(:option:`--attribute`) from data directly associated with the binary +file (offset) to high level details such as coverage, lexical scope +level, location. As the printed output can reach a considerable size, +several selection options, enable printing of specific elements. + +The pattern matching can ignore the case (:option:`--select-nocase`) +and be extended to use regular expressions (:option:`--select-regex`). + +ELEMENTS +^^^^^^^^ +The following options allow printing of elements that match the given +, offset or an element . + +.. option:: --select= + + Print all elements whose name or line number matches the given . + +.. option:: --select-offsets= + + Print all elements whose offset matches the given values. See + :option:`--attribute` option. + +.. option:: --select-elements= + + Print all elements that satisfy the given . With **condition** + being one the options in the following list. + + .. code-block:: text + + =discarded: Discarded elements by the linker. + =global: Element referenced across Compile Units. + =optimized: Optimized inlined abstract references. + +.. option:: --select-nocase + + Pattern matching is case-insensitive when using :option:`--select`. + +.. option:: --select-regex + + Treat any strings as regular expressions when selecting with + :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: +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 +of element. + +LINES +^^^^^ +The following options allow printing of lines that match the given . +The given criteria describes the debug line state machine registers. + +.. option:: --select-lines= + + With **kind** being one the options in the following list. + + .. code-block:: text + + =AlwaysStepInto: marks an always step into. + =BasicBlock: Marks a new basic block. + =Discriminator: Line that has a discriminator. + =EndSequence: Marks the end in the sequence of lines. + =EpilogueBegin: Marks the start of a function epilogue. + =LineDebug: Lines that correspond to debug lines. + =LineAssembler: Lines that correspond to disassembly text. + =NeverStepInto: marks a never step into. + =NewStatement: Marks a new statement. + =PrologueEnd: Marks the end of a function prologue. + +SCOPES +^^^^^^ +The following options allow printing of scopes that match the given . + +.. option:: --select-scopes= + + With **kind** being one the options in the following list. + + .. code-block:: text + + =Aggregate: A class, structure or union. + =Array: An array. + =Block: A generic block (lexical block or exception block). + =CallSite: A call site. + =CatchBlock: An exception block. + =Class: A Class. + =CompileUnit: A Compile unit. + =EntryPoint: A subroutine entry point. + =Enumeration: An enumeration. + =Function: A function. + =FunctionType: A function pointer. + =InlinedFunction: An inlined function. + =Label: A label. + =LexicalBlock: A lexical block. + =Namespace: A namespace. + =Root: The element representing the main scope. + =Structure: A structure. + =Subprogram: A subprogram. + =Template: A template definition. + =TemplateAlias: A template alias. + =TemplatePack: A template pack. + =TryBlock: An exception try block. + =Union: An union. + +SYMBOLS +^^^^^^^ +The following options allow printing of symbols that match the given . + +.. option:: --select-symbols= + + With **kind** being one the options in the following list. + + .. code-block:: text + + =CallSiteParameter: A call site parameter. + =Constant: A constant symbol. + =Inheritance: A base class. + =Member: A member class. + =Parameter: A parameter to function. + =Unspecified: Unspecified parameters to function. + =Variable: A variable. + +TYPES +^^^^^ +The following options allow printing of types that match the given . + +.. option:: --select-types= + + With **kind** being one the options in the following list. + + .. code-block:: text + + =Base: Base type (integer, boolean, etc). + =Const: Constant specifier. + =Enumerator: Enumerator. + =Import: Import declaration. + =ImportDeclaration: Import declaration. + =ImportModule: Import Module. + =Pointer: Pointer Type. + =PointerMember: Pointer to member function. + =Reference: Reference type. + =Restrict: Restrict specifier. + =RvalueReference: R-value reference. + =Subrange: Array subrange. + =TemplateParam: Template parameter. + =TemplateTemplateParam: Template template parameter. + =TemplateTypeParam: Template type parameter. + =TemplateValueParam: Template value parameter. + =Typedef: Type definition. + =Unspecified: Unspecified type. + =Volatile: Volatile specifier. + +.. _compare_: + +COMPARE +~~~~~~~ +When dealing with debug information, there are situations when the +printing of the elements is not the correct approach. That is the case, +when we are interested in the effects caused by different versions of +the same toolchain, or the impact of specific compiler optimizations. + +For those cases, we are looking to see which elements have been added +or removed. Due to the complicated debug information format, it is very +difficult to use a regular diff tool to find those elements; even +impossible when dealing with different debug formats. + +:program:`llvm-dva` supports a logical element comparison, allowing +to find semantic differences between logical views, produced by +different toolchain versions or even debug information formats. + +When comparing logical views created from different debug formats, its +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. + +The following options describe the elements to compare. + +.. option:: --compare= + + With **value** being one of the options in the following list. + + .. code-block:: text + + =all: Include all the below elements. + + .. code-block:: text + + =lines: Include lines. + =scopes: Include scopes. + =symbols: Include symbols. + =types: Include types. + +:program:`llvm-dva` takes the first binary file on the command line +as the **reference** and the second one as the **target**. +To get a more descriptive report, the comparison is done twice. The +reference and target views are swapped, in order to produce those +**missing** elements from the target view and those **added** elements +to the reference view. + +See :option:`--report` options on how to describe the comparison +reports. + +.. _warning_: + +WARNING +~~~~~~~ +When reading the input object files, :program:`llvm-dva` can detected +issues in the raw debug information. These may not be considered fatal +to the purpose of printing a logical view but they can give an indication +about the quality and potentially expose issues with the generated debug +information. + +The following options describe the warnings to be recorded for later +printing, if they are requested by :option:`--print`. + +.. option:: --warning= + + With **value** being one the options in the following list. + + .. code-block:: text + + =all: Include all the below warnings. + + The following options collect additional information during the creation + of the logical view, to include invalid coverage values and locations + for symbols; invalid code ranges; lines that are zero. + + .. code-block:: text + + =coverages: Invalid symbol coverages values. + =lines: Debug lines that are zero. + =locations: Invalid symbol locations. + =ranges: Invalid code ranges. + +.. _internal_: + +INTERNAL +~~~~~~~~ + For a better understanding of the logical view, access to more detailed + internal information is needed. Such data would help to identify debug + information processed or incorrect logical element management. Typically + these kind of options are available only in *debug* builds. + + :program:`llvm-dva` supports these advanced options in both *release* + and *debug* builds, with the exception of the unique ID that is + generated only in *debug* builds. + +.. option:: --internal= + + With **value** being one the options in the following list. + + .. code-block:: text + + =all: Include all the below options. + + The following options allow to check the integrity of the logical view; + collect the debug tags that are processed or not implemented; ignore the + logical element line number, to facilitate the logical view comparison + when using external comparison tools; print the command line options + used to invoke :program:`llvm-dva`. + + .. code-block:: text + + =id: Print unique element ID. + =cmdline: Print command line. + =integrity: Check elements integrity. + =none: Ignore element line number. + =tag: Debug information tags. + + **Note:** For ELF format, the collected tags represent the debug tags + that are not processed. For PE/COFF format, they represent the tags + that are processed. + +EXAMPLES +-------- +This section includes some real binary files to show how to use +:program:`llvm-dva` to print a logical view and to diagnose possible +debug information issues. + +TEST CASE 1 - GENERAL OPTIONS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The below example is used to show different output generated by +:program:`llvm-dva`. We compiled the example for an X86 ELF target with +a recent version of Clang (-O0 -g): + +.. code-block:: c++ + + 1 using INTPTR = const int *; + 2 int foo(INTPTR ParamPtr, unsigned ParamUnsigned, bool ParamBool) { + 3 if (ParamBool) { + 4 typedef int INTEGER; + 5 const INTEGER CONSTANT = 7; + 6 return CONSTANT; + 7 } + 8 return ParamUnsigned; + 9 } + +PRINTING MODE +^^^^^^^^^^^^^ +In this mode :program:`llvm-dva` prints the *logical view* or portions +of it, based on criteria patterns (including regular expressions) to +select the kind of *logical elements* to be included in the output. + +BASIC DETAILS +""""""""""""" +The following command prints basic details for all the logical elements +sorted by the debug information internal offset; it includes its lexical +level and debug info format. + +.. code-block:: none + + llvm-dva --attribute=level,format + --output-sort=offset + --print=scopes,symbols,types,lines,instructions + test-dwarf-clang.o + +or + +.. code-block:: none + + llvm-dva --attribute=level,format + --output-sort=offset + --print=elements + test-dwarf-clang.o + +Each row represents an element that is present within the debug +information. The first column represents the scope level, followed by +the associated line number (if any), and finally the description of +the element. + +.. code-block:: none + + Logical View: + [000] {File} 'test-dwarf-clang.o' -> elf64-x86-64 + + [001] {CompileUnit} 'test.cpp' + [002] 2 {Function} extern not_inlined 'foo' -> 'int' + [003] 2 {Parameter} 'ParamPtr' -> 'INTPTR' + [003] 2 {Parameter} 'ParamUnsigned' -> 'unsigned int' + [003] 2 {Parameter} 'ParamBool' -> 'bool' + [003] {Block} + [004] 5 {Variable} 'CONSTANT' -> 'const INTEGER' + [004] 5 {Line} + [004] {Code} 'movl $0x7, -0x1c(%rbp)' + [004] 6 {Line} + [004] {Code} 'movl $0x7, -0x4(%rbp)' + [004] {Code} 'jmp 0x6' + [004] 8 {Line} + [004] {Code} 'movl -0x14(%rbp), %eax' + [003] 4 {TypeAlias} 'INTEGER' -> 'int' + [003] 2 {Line} + [003] {Code} 'pushq %rbp' + [003] {Code} 'movq %rsp, %rbp' + [003] {Code} 'movb %dl, %al' + [003] {Code} 'movq %rdi, -0x10(%rbp)' + [003] {Code} 'movl %esi, -0x14(%rbp)' + [003] {Code} 'andb $0x1, %al' + [003] {Code} 'movb %al, -0x15(%rbp)' + [003] 3 {Line} + [003] {Code} 'testb $0x1, -0x15(%rbp)' + [003] {Code} 'je 0x13' + [003] 8 {Line} + [003] {Code} 'movl %eax, -0x4(%rbp)' + [003] 9 {Line} + [003] {Code} 'movl -0x4(%rbp), %eax' + [003] {Code} 'popq %rbp' + [003] {Code} 'retq' + [003] 9 {Line} + [002] 1 {TypeAlias} 'INTPTR' -> '* const int' + +On closer inspection, we can see what could be a potential debug issue: + +.. code-block:: none + + [003] {Block} + [003] 4 {TypeAlias} 'INTEGER' -> 'int' + +The **'INTEGER'** definition is at level **[003]**, the same lexical +scope as the anonymous **{Block}** ('true' branch for the 'if' statement) +whereas in the original source code the typedef statement is clearly +inside that block, so the **'INTEGER'** definition should also be at +level **[004]** inside the block. + +SELECT LOGICAL ELEMENTS +""""""""""""""""""""""" +The following prints all *instructions*, *symbols* and *types* that +contain **'inte'** or **'movl'** in their names or types, using a tab +layout and given the number of matches. + +.. code-block:: none + + llvm-dva --attribute=level + --select-nocase --select-regex --select=INTe --select=movl + --report=list + --print=symbols,types,instructions,summary + test-dwarf-clang.o + + Logical View: + [000] {File} 'test-dwarf-clang.o' + + [001] {CompileUnit} 'test.cpp' + [003] {Code} 'movl $0x7, -0x1c(%rbp)' + [003] {Code} 'movl $0x7, -0x4(%rbp)' + [003] {Code} 'movl %eax, -0x4(%rbp)' + [003] {Code} 'movl %esi, -0x14(%rbp)' + [003] {Code} 'movl -0x14(%rbp), %eax' + [003] {Code} 'movl -0x4(%rbp), %eax' + [003] 4 {TypeAlias} 'INTEGER' -> 'int' + [004] 5 {Variable} 'CONSTANT' -> 'const INTEGER' + + ----------------------------- + Element Total Found + ----------------------------- + Scopes 3 0 + Symbols 4 1 + Types 2 1 + Lines 17 6 + ----------------------------- + Total 26 8 + +COMPARISON MODE +^^^^^^^^^^^^^^^ +In this mode :program:`llvm-dva` compares logical views to produce a +report with the logical elements that are missing or added. This a very +powerful aid in finding semantic differences in the debug information +produced by different toolchain versions or even completely different +toolchains altogether (For example a compiler producing DWARF can be +directly compared against a completely different compiler that produces +CodeView). + +Given the previous example we found the above debug information issue +(related to the previous invalid scope location for the **'typedef int +INTEGER'**) by comparing against another compiler. + +Using GCC to generate test-dwarf-gcc.o, we can apply a selection pattern +with the printing mode to obtain the following logical view output. + +.. code-block:: none + + llvm-dva --attribute=level + --select-regex --select-nocase --select=INTe + --report=list + --print=symbols,types + test-dwarf-clang.o test-dwarf-gcc.o + + Logical View: + [000] {File} 'test-dwarf-clang.o' + + [001] {CompileUnit} 'test.cpp' + [003] 4 {TypeAlias} 'INTEGER' -> 'int' + [004] 5 {Variable} 'CONSTANT' -> 'const INTEGER' + + Logical View: + [000] {File} 'test-dwarf-gcc.o' + + [001] {CompileUnit} 'test.cpp' + [004] 4 {TypeAlias} 'INTEGER' -> 'int' + [004] 5 {Variable} 'CONSTANT' -> 'const INTEGER' + +The output shows that both objects contain the same elements. But the +**'typedef INTEGER'** is located at different scope level. The GCC +generated object, shows **'4'**, which is the correct value. + +Note that there is no requirement that GCC must produce identical or +similar DWARF to Clang to allow the comparison. We're only comparing +the semantics. The same case when comparing CodeView debug information +generated by MSVC and Clang. + +There are 2 comparison methods: logical view and logical elements. + +LOGICAL VIEW +"""""""""""" +It compares the logical view as a whole unit; for a match, each compared +logical element must have the same parents and children. + +Using the :program:`llvm-dva` comparison functionality, that issue can +be seen in a more global context, that can include the logical view. + +The output shows in view form the **missing (-), added (+)** elements, +giving more context by swapping the reference and target object files. + +.. code-block:: none + + llvm-dva --attribute=level + --compare=types + --report=view + --print=symbols,types + test-dwarf-clang.o test-dwarf-gcc.o + + Reference: 'test-dwarf-clang.o' + Target: 'test-dwarf-gcc.o' + + Logical View: + [000] {File} 'test-dwarf-clang.o' + + [001] {CompileUnit} 'test.cpp' + [002] 1 {TypeAlias} 'INTPTR' -> '* const int' + [002] 2 {Function} extern not_inlined 'foo' -> 'int' + [003] {Block} + [004] 5 {Variable} 'CONSTANT' -> 'const INTEGER' + +[004] 4 {TypeAlias} 'INTEGER' -> 'int' + [003] 2 {Parameter} 'ParamBool' -> 'bool' + [003] 2 {Parameter} 'ParamPtr' -> 'INTPTR' + [003] 2 {Parameter} 'ParamUnsigned' -> 'unsigned int' + -[003] 4 {TypeAlias} 'INTEGER' -> 'int' + +The output shows the merging view path (reference and target) with the +missing and added elements. + +LOGICAL ELEMENTS +"""""""""""""""" +It compares individual logical elements without considering if their +parents are the same. For both comparison methods, the equal criteria +includes the name, source code location, type, lexical scope level. + +.. code-block:: none + + llvm-dva --attribute=level + --compare=types + --report=list + --print=symbols,types,summary + test-dwarf-clang.o test-dwarf-gcc.o + + Reference: 'test-dwarf-clang.o' + Target: 'test-dwarf-gcc.o' + + (1) Missing Types: + -[003] 4 {TypeAlias} 'INTEGER' -> 'int' + + (1) Added Types: + +[004] 4 {TypeAlias} 'INTEGER' -> 'int' + + ---------------------------------------- + Element Expected Missing Added + ---------------------------------------- + Scopes 4 0 0 + Symbols 0 0 0 + Types 2 1 1 + Lines 0 0 0 + ---------------------------------------- + Total 6 1 1 + +Changing the *Reference* and *Target* order: + +.. code-block:: none + + llvm-dva --attribute=level + --compare=types + --report=list + --print=symbols,types,summary + test-dwarf-gcc.o test-dwarf-clang.o + + Reference: 'test-dwarf-gcc.o' + Target: 'test-dwarf-clang.o' + + (1) Missing Types: + -[004] 4 {TypeAlias} 'INTEGER' -> 'int' + + (1) Added Types: + +[003] 4 {TypeAlias} 'INTEGER' -> 'int' + + ---------------------------------------- + Element Expected Missing Added + ---------------------------------------- + Scopes 4 0 0 + Symbols 0 0 0 + Types 2 1 1 + Lines 0 0 0 + ---------------------------------------- + Total 6 1 1 + +As the *Reference* and *Target* are switched, the *Added Types* from +the first case now are listed as *Missing Types*. + +TEST CASE 2 - ASSEMBLER INSTRUCTIONS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The below example is used to show different output generated by +:program:`llvm-dva`. We compiled the example for an X86 Codeview and +ELF targets with recent versions of Clang, GCC and MSVC (-O0 -g) for +Windows and Linux. + +.. code-block:: c++ + + 1 extern int printf(const char * format, ... ); + 2 + 3 int main() + 4 { + 5 printf("Hello, World\n"); + 6 return 0; + 7 } + +These are the logical views that :program:`llvm-dva` generates for 3 +different compilers (MSVC, Clang and GCC), emitting different debug +information formats (CodeView, DWARF) on Windows and Linux. + +.. code-block:: none + + llvm-dva --attribute=level,format,producer + --print=lines,instructions + hello-world-codeview-clang.o + hello-world-codeview-msvc.o + hello-world-dwarf-clang.o + hello-world-dwarf-gcc.o + +CodeView - Clang (Windows) +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: none + + Logical View: + [000] {File} 'hello-world-codeview-clang.o' -> COFF-x86-64 + + [001] {CompileUnit} 'hello-world.cpp' + [002] {Producer} 'clang version 14.0.0' + [002] {Function} extern not_inlined 'main' -> 'int' + [003] 4 {Line} + [003] {Code} 'subq $0x28, %rsp' + [003] {Code} 'movl $0x0, 0x24(%rsp)' + [003] 5 {Line} + [003] {Code} 'leaq (%rip), %rcx' + [003] {Code} 'callq 0x0' + [003] 6 {Line} + [003] {Code} 'xorl %eax, %eax' + [003] {Code} 'addq $0x28, %rsp' + [003] {Code} 'retq' + +CodeView - MSVC (Windows) +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: none + + Logical View: + [000] {File} 'hello-world-codeview-msvc.o' -> COFF-i386 + + [001] {CompileUnit} 'hello-world.cpp' + [002] {Producer} 'Microsoft (R) Optimizing Compiler' + [002] {Function} extern not_inlined 'main' -> 'int' + [003] 4 {Line} + [003] {Code} 'pushl %ebp' + [003] {Code} 'movl %esp, %ebp' + [003] 5 {Line} + [003] {Code} 'pushl $0x0' + [003] {Code} 'calll 0x0' + [003] {Code} 'addl $0x4, %esp' + [003] 6 {Line} + [003] {Code} 'xorl %eax, %eax' + [003] 7 {Line} + [003] {Code} 'popl %ebp' + [003] {Code} 'retl' + +DWARF - Clang (Linux) +^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: none + + Logical View: + [000] {File} 'hello-world-dwarf-clang.o' -> elf64-x86-64 + + [001] {CompileUnit} 'hello-world.cpp' + [002] {Producer} 'clang version 14.0.0' + [002] 3 {Function} extern not_inlined 'main' -> 'int' + [003] 4 {Line} + [003] {Code} 'pushq %rbp' + [003] {Code} 'movq %rsp, %rbp' + [003] {Code} 'subq $0x10, %rsp' + [003] {Code} 'movl $0x0, -0x4(%rbp)' + [003] 5 {Line} + [003] {Code} 'movabsq $0x0, %rdi' + [003] {Code} 'movb $0x0, %al' + [003] {Code} 'callq 0x0' + [003] 6 {Line} + [003] {Code} 'xorl %eax, %eax' + [003] {Code} 'addq $0x10, %rsp' + [003] {Code} 'popq %rbp' + [003] {Code} 'retq' + [003] 6 {Line} + +DWARF - GCC (Linux) +^^^^^^^^^^^^^^^^^^^ + +.. code-block:: none + + Logical View: + [000] {File} 'hello-world-dwarf-gcc.o' -> elf64-x86-64 + + [001] {CompileUnit} 'hello-world.cpp' + [002] {Producer} 'GNU C++14 9.3.0' + [002] 3 {Function} extern not_inlined 'main' -> 'int' + [003] 4 {Line} + [003] {Code} 'endbr64' + [003] {Code} 'pushq %rbp' + [003] {Code} 'movq %rsp, %rbp' + [003] 5 {Line} + [003] {Code} 'leaq (%rip), %rdi' + [003] {Code} 'movl $0x0, %eax' + [003] {Code} 'callq 0x0' + [003] 6 {Line} + [003] {Code} 'movl $0x0, %eax' + [003] 7 {Line} + [003] {Code} 'popq %rbp' + [003] {Code} 'retq' + [003] 7 {Line} + +The logical views shows the intermixed lines and assembler instructions, +allowing to compare the code generated by the different toolchains. + +TEST CASE 3 - INCORRECT LEXICAL SCOPE FOR TYPEDEF +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The below example is used to show different output generated by +:program:`llvm-dva`. We compiled the example for an X86 Codeview and +ELF targets with recent versions of Clang, GCC and MSVC (-O0 -g). + +.. code-block:: c++ + + 1 int bar(float Input) { return (int)Input; } + 2 + 3 unsigned foo(char Param) { + 4 typedef int INT; // ** Definition for INT ** + 5 INT Value = Param; + 6 { + 7 typedef float FLOAT; // ** Definition for FLOAT ** + 8 { + 9 FLOAT Added = Value + Param; + 10 Value = bar(Added); + 11 } + 12 } + 13 return Value + Param; + 14 } + +The above test is used to illustrate a scope issue found in the Clang +compiler: +`PR44884 (Bugs LLVM) `_ / +`PR44229 (GitHub LLVM) `_ + +The lines 4 and 7 contains 2 typedefs, defined at different lexical +scopes. + +.. code-block:: c++ + + 4 typedef int INT; + 7 typedef float FLOAT; + +These are the logical views that :program:`llvm-dva` generates for 3 +different compilers (MSVC, Clang and GCC), emitting different debug +information formats (CodeView, DWARF) on different platforms. + +.. code-block:: none + + llvm-dva --attribute=level,format,producer + --print=symbols,types,lines + --output-sort=kind + pr-44884-codeview-clang.o + pr-44884-codeview-msvc.o + pr-44884-dwarf-clang.o + pr-44884-dwarf-gcc.o + +CodeView - Clang (Windows) +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: none + + Logical View: + [000] {File} 'pr-44884-codeview-clang.o' -> COFF-x86-64 + + [001] {CompileUnit} 'pr-44884.cpp' + [002] {Producer} 'clang version 14.0.0' + [002] {Function} extern not_inlined 'bar' -> 'int' + [003] {Parameter} 'Input' -> 'float' + [003] 1 {Line} + [002] {Function} extern not_inlined 'foo' -> 'unsigned' + [003] {Block} + [004] {Variable} 'Added' -> 'float' + [004] 9 {Line} + [004] 10 {Line} + [003] {Parameter} 'Param' -> 'char' + [003] {TypeAlias} 'FLOAT' -> 'float' + [003] {TypeAlias} 'INT' -> 'int' + [003] {Variable} 'Value' -> 'int' + [003] 3 {Line} + [003] 5 {Line} + [003] 13 {Line} + +CodeView - MSVC (Windows) +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: none + + Logical View: + [000] {File} 'pr-44884-codeview-msvc.o' -> COFF-i386 + + [001] {CompileUnit} 'pr-44884.cpp' + [002] {Producer} 'Microsoft (R) Optimizing Compiler' + [002] {Function} extern not_inlined 'bar' -> 'int' + [003] {Variable} 'Input' -> 'float' + [003] 1 {Line} + [002] {Function} extern not_inlined 'foo' -> 'unsigned' + [003] {Block} + [004] {Block} + [005] {Variable} 'Added' -> 'float' + [004] {TypeAlias} 'FLOAT' -> 'float' + [004] 9 {Line} + [004] 10 {Line} + [003] {TypeAlias} 'INT' -> 'int' + [003] {Variable} 'Param' -> 'char' + [003] {Variable} 'Value' -> 'int' + [003] 3 {Line} + [003] 5 {Line} + [003] 13 {Line} + [003] 14 {Line} + +DWARF - Clang (Linux) +^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: none + + Logical View: + [000] {File} 'pr-44884-dwarf-clang.o' -> elf64-x86-64 + + [001] {CompileUnit} 'pr-44884.cpp' + [002] {Producer} 'clang version 14.0.0' + [002] 1 {Function} extern not_inlined 'bar' -> 'int' + [003] 1 {Parameter} 'Input' -> 'float' + [003] 1 {Line} + [003] 1 {Line} + [003] 1 {Line} + [002] 3 {Function} extern not_inlined 'foo' -> 'unsigned int' + [003] {Block} + [004] 9 {Variable} 'Added' -> 'FLOAT' + [004] 9 {Line} + [004] 9 {Line} + [004] 9 {Line} + [004] 9 {Line} + [004] 9 {Line} + [004] 10 {Line} + [004] 10 {Line} + [004] 10 {Line} + [004] 13 {Line} + [003] 3 {Parameter} 'Param' -> 'char' + [003] 7 {TypeAlias} 'FLOAT' -> 'float' + [003] 4 {TypeAlias} 'INT' -> 'int' + [003] 5 {Variable} 'Value' -> 'INT' + [003] 3 {Line} + [003] 5 {Line} + [003] 5 {Line} + [003] 13 {Line} + [003] 13 {Line} + [003] 13 {Line} + [003] 13 {Line} + +DWARF - GCC (Linux) +^^^^^^^^^^^^^^^^^^^ + +.. code-block:: none + + Logical View: + [000] {File} 'pr-44884-dwarf-gcc.o' -> elf32-littlearm + + [001] {CompileUnit} 'pr-44884.cpp' + [002] {Producer} 'GNU C++14 10.2.1 20201103' + [002] 1 {Function} extern not_inlined 'bar' -> 'int' + [003] 1 {Parameter} 'Input' -> 'float' + [003] 1 {Line} + [003] 1 {Line} + [003] 1 {Line} + [002] 3 {Function} extern not_inlined 'foo' -> 'unsigned int' + [003] {Block} + [004] {Block} + [005] 9 {Variable} 'Added' -> 'FLOAT' + [005] 9 {Line} + [005] 9 {Line} + [005] 9 {Line} + [005] 10 {Line} + [005] 13 {Line} + [004] 7 {TypeAlias} 'FLOAT' -> 'float' + [003] 3 {Parameter} 'Param' -> 'char' + [003] 4 {TypeAlias} 'INT' -> 'int' + [003] 5 {Variable} 'Value' -> 'INT' + [003] 3 {Line} + [003] 5 {Line} + [003] 13 {Line} + [003] 14 {Line} + [003] 14 {Line} + +From the previous logical views, we can see that the Clang compiler +emits **both typedefs at the same lexical scope (3)**, which is wrong. +GCC and MSVC emit correct lexical scope for both typedefs. + +Using the :program:`llvm-dva` selection facilities, we can produce a +simple tabular output showing just the logical types that are **Typedef**. + +.. code-block:: none + + llvm-dva --attribute=level,format + --output-sort=name + --select-types=Typedef + --report=list + --print=types + pr-44884-*.o + + Logical View: + [000] {File} 'pr-44884-codeview-clang.o' -> COFF-x86-64 + + [001] {CompileUnit} 'pr_44884.cpp' + [003] {TypeAlias} 'FLOAT' -> 'float' + [003] {TypeAlias} 'INT' -> 'int' + + Logical View: + [000] {File} 'pr-44884-codeview-msvc.o' -> COFF-i386 + + [001] {CompileUnit} 'pr_44884.cpp' + [004] {TypeAlias} 'FLOAT' -> 'float' + [003] {TypeAlias} 'INT' -> 'int' + + Logical View: + [000] {File} 'pr-44884-dwarf-clang.o' -> elf64-x86-64 + + [001] {CompileUnit} 'pr_44884.cpp' + [003] 7 {TypeAlias} 'FLOAT' -> 'float' + [003] 4 {TypeAlias} 'INT' -> 'int' + + Logical View: + [000] {File} 'pr-44884-dwarf-gcc.o' -> elf32-littlearm + + [001] {CompileUnit} 'pr_44884.cpp' + [004] 7 {TypeAlias} 'FLOAT' -> 'float' + [003] 4 {TypeAlias} 'INT' -> 'int' + +It also shows, that the CodeView debug information does not generate +source code line numbers for the those logical types. The logical view +is sorted by the types name. + +TEST CASE 4 - MISSING NESTED ENUMERATIONS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The below example is used to show different output generated by +:program:`llvm-dva`. We compiled the example for an X86 Codeview and +ELF targets with recent versions of Clang, GCC and MSVC (-O0 -g). + +.. code-block:: c++ + + 1 struct Struct { + 2 union Union { + 3 enum NestedEnum { RED, BLUE }; + 4 }; + 5 Union U; + 6 }; + 7 + 8 Struct S; + 9 int test() { + 10 return S.U.BLUE; + 11 } + +The above test is used to illustrate a scope issue found in the Clang +compiler: +`PR46466 (Bugs LLVM) `_ / +`PR45811 (GitHub LLVM) `_ + +These are the logical views that :program:`llvm-dva` generates for 3 +different compilers (MSVC, Clang and GCC), emitting different debug +information formats (CodeView, DWARF) on different platforms. + +.. code-block:: none + + llvm-dva --attribute=level,format,producer + --output-sort=name + --print=symbols,types + pr-46466-codeview-clang.o + pr-46466-codeview-msvc.o + pr-46466-dwarf-clang.o + pr-46466-dwarf-gcc.o + +CodeView - Clang (Windows) +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: none + + Logical View: + [000] {File} 'pr-46466-codeview-clang.o' -> COFF-x86-64 + + [001] {CompileUnit} 'pr-46466.cpp' + [002] {Producer} 'clang version 14.0.0' + [002] {Variable} extern 'S' -> 'Struct' + [002] 1 {Struct} 'Struct' + [003] {Member} public 'U' -> 'Union' + [003] 2 {Union} 'Union' + [004] 3 {Enumeration} 'NestedEnum' -> 'int' + [005] {Enumerator} 'BLUE' = '0x1' + [005] {Enumerator} 'RED' = '0x0' + +CodeView - MSVC (Windows) +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: none + + Logical View: + [000] {File} 'pr-46466-codeview-msvc.o' -> COFF-i386 + + [001] {CompileUnit} 'pr-46466.cpp' + [002] {Producer} 'Microsoft (R) Optimizing Compiler' + [002] {Variable} extern 'S' -> 'Struct' + [002] 1 {Struct} 'Struct' + [003] {Member} public 'U' -> 'Union' + [003] 2 {Union} 'Union' + [004] 3 {Enumeration} 'NestedEnum' -> 'int' + [005] {Enumerator} 'BLUE' = '0x1' + [005] {Enumerator} 'RED' = '0x0' + +DWARF - Clang (Linux) +^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: none + + Logical View: + [000] {File} 'pr-46466-dwarf-clang.o' -> elf64-x86-64 + + [001] {CompileUnit} 'pr-46466.cpp' + [002] {Producer} 'clang version 14.0.0' + [002] 8 {Variable} extern 'S' -> 'Struct' + [002] 1 {Struct} 'Struct' + [003] 5 {Member} public 'U' -> 'Union' + +DWARF - GCC (Linux) +^^^^^^^^^^^^^^^^^^^ + +.. code-block:: none + + Logical View: + [000] {File} 'pr-46466-dwarf-gcc.o' -> elf64-x86-64 + + [001] {CompileUnit} 'pr-46466.cpp' + [002] {Producer} 'GNU C++14 9.3.0' + [002] 8 {Variable} extern 'S' -> 'Struct' + [002] 1 {Struct} 'Struct' + [003] 5 {Member} public 'U' -> 'Union' + [003] 2 {Union} 'Union' + [004] 3 {Enumeration} 'NestedEnum' -> 'unsigned int' + [005] {Enumerator} 'BLUE' = '0x1' + [005] {Enumerator} 'RED' = '0x0' + +From the previous logical views, we can see that the DWARF debug +information generated by the Clang compiler does not include any +references to the enumerators **RED** and **BLUE**. The DWARF +generated by GCC, CodeView generated by Clang and MSVC, it does +include such references. + +Using the :program:`llvm-dva` selection facilities, we can produce a +logical view showing just the logical types that are **Enumerator** +and its parents. The logical view is sorted by the types name. + +.. code-block:: none + + llvm-dva --attribute=format,level + --output-sort=name + --select-types=Enumerator + --report=parents + --print=types + pr-46466-*.o + +.. code-block:: none + + Logical View: + [000] {File} 'pr-46466-codeview-clang.o' -> COFF-x86-64 + + [001] {CompileUnit} 'pr-46466.cpp' + [002] 1 {Struct} 'Struct' + [003] 2 {Union} 'Union' + [004] 3 {Enumeration} 'NestedEnum' -> 'int' + [005] {Enumerator} 'BLUE' = '0x1' + [005] {Enumerator} 'RED' = '0x0' + + Logical View: + [000] {File} 'pr-46466-codeview-msvc.o' -> COFF-i386 + + [001] {CompileUnit} 'pr-46466.cpp' + [002] 1 {Struct} 'Struct' + [003] 2 {Union} 'Union' + [004] 3 {Enumeration} 'NestedEnum' -> 'int' + [005] {Enumerator} 'BLUE' = '0x1' + [005] {Enumerator} 'RED' = '0x0' + + Logical View: + [000] {File} 'pr-46466-dwarf-clang.o' -> elf64-x86-64 + + [001] {CompileUnit} 'pr-46466.cpp' + + Logical View: + [000] {File} 'pr-46466-dwarf-gcc.o' -> elf64-x86-64 + + [001] {CompileUnit} 'pr-46466.cpp' + [002] 1 {Struct} 'Struct' + [003] 2 {Union} 'Union' + [004] 3 {Enumeration} 'NestedEnum' -> 'unsigned int' + [005] {Enumerator} 'BLUE' = '0x1' + [005] {Enumerator} 'RED' = '0x0' + +Using the :program:`llvm-dva` selection facilities, we can produce a +simple tabular output including a summary for the logical types that +are **Enumerator**. The logical view is sorted by the types name. + +.. code-block:: none + + llvm-dva --attribute=format,level + --output-sort=name + --select-types=Enumerator + --print=types,summary + pr-46466-*.o + +.. code-block:: none + + Logical View: + [000] {File} 'pr-46466-codeview-clang.o' -> COFF-x86-64 + + [001] {CompileUnit} 'pr-46466.cpp' + [005] {Enumerator} 'BLUE' = '0x1' + [005] {Enumerator} 'RED' = '0x0' + + ----------------------------- + Element Total Found + ----------------------------- + Scopes 5 0 + Symbols 2 0 + Types 6 2 + Lines 0 0 + ----------------------------- + Total 13 2 + + Logical View: + [000] {File} 'pr-46466-codeview-msvc.o' -> COFF-i386 + + [001] {CompileUnit} 'pr-46466.cpp' + [005] {Enumerator} 'BLUE' = '0x1' + [005] {Enumerator} 'RED' = '0x0' + + ----------------------------- + Element Total Found + ----------------------------- + Scopes 5 0 + Symbols 2 0 + Types 7 2 + Lines 0 0 + ----------------------------- + Total 14 2 + + Logical View: + [000] {File} 'pr-46466-dwarf-clang.o' -> elf64-x86-64 + + [001] {CompileUnit} 'pr-46466.cpp' + + ----------------------------- + Element Total Found + ----------------------------- + Scopes 4 0 + Symbols 0 0 + Types 0 0 + Lines 0 0 + ----------------------------- + Total 4 0 + + Logical View: + [000] {File} 'pr-46466-dwarf-gcc.o' -> elf64-x86-64 + + [001] {CompileUnit} 'pr-46466.cpp' + [005] {Enumerator} 'BLUE' = '0x1' + [005] {Enumerator} 'RED' = '0x0' + + ----------------------------- + Element Total Found + ----------------------------- + Scopes 5 0 + Symbols 0 0 + Types 2 2 + Lines 0 0 + ----------------------------- + Total 7 2 + +From the values printed under the **Found** column, we can see that no +**Types** were found in the DWARF debug information generated by Clang. + +TEST CASE 5 - INCORRECT LEXICAL SCOPE FOR VARIABLE +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The below example is used to show different output generated by +:program:`llvm-dva`. We compiled the example for an X86 Codeview and +ELF targets with recent versions of Clang, GCC and MSVC (-O0 -g). + +.. code-block:: c++ + + // definitions.h + #ifdef _MSC_VER + #define forceinline __forceinline + #elif defined(__clang__) + #if __has_attribute(__always_inline__) + #define forceinline inline __attribute__((__always_inline__)) + #else + #define forceinline inline + #endif + #elif defined(__GNUC__) + #define forceinline inline __attribute__((__always_inline__)) + #else + #define forceinline inline + #error + #endif + +As the test is dependent on inline compiler options, the above header +file defines *forceinline*. + +.. code-block:: c++ + + #include "definitions.h" + +.. code-block:: c++ + + 1 #include "definitions.h" + 2 forceinline int InlineFunction(int Param) { + 3 int Var_1 = Param; + 4 { + 5 int Var_2 = Param + Var_1; + 6 Var_1 = Var_2; + 7 } + 8 return Var_1; + 9 } + 10 + 11 int test(int Param_1, int Param_2) { + 12 int A = Param_1; + 13 A += InlineFunction(Param_2); + 14 return A; + 15 } + +The above test is used to illustrate a variable issue found in the Clang +compiler: +`PR43860 (Bugs LLVM) `_ / +`PR43205 (GitHub) `_ + +These are the logical views that :program:`llvm-dva` generates for 3 +different compilers (MSVC, Clang and GCC), emitting different debug +information formats (CodeView, DWARF) on different platforms. + +.. code-block:: none + + llvm-dva --attribute=level,format,producer + --output-sort=name + --print=symbols + pr-43860-codeview-clang.o + pr-43860-codeview-msvc.o + pr-43860-dwarf-clang.o + pr-43860-dwarf-gcc.o + +CODEVIEW - Clang (Windows) +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: none + + Logical View: + [000] {File} 'pr-43860-codeview-clang.o' -> COFF-x86-64 + + [001] {CompileUnit} 'pr-43860.cpp' + [002] {Producer} 'clang version 14.0.0' + [002] 2 {Function} inlined 'InlineFunction' -> 'int' + [003] {Parameter} '' -> 'int' + [002] {Function} extern not_inlined 'test' -> 'int' + [003] {Variable} 'A' -> 'int' + [003] {InlinedFunction} inlined 'InlineFunction' -> 'int' + [004] {Parameter} 'Param' -> 'int' + [004] {Variable} 'Var_1' -> 'int' + [004] {Variable} 'Var_2' -> 'int' + [003] {Parameter} 'Param_1' -> 'int' + [003] {Parameter} 'Param_2' -> 'int' + +CODEVIEW - MSVC (Windows) +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: none + + Logical View: + [000] {File} 'pr-43860-codeview-msvc.o' -> COFF-i386 + + [001] {CompileUnit} 'pr-43860.cpp' + [002] {Producer} 'Microsoft (R) Optimizing Compiler' + [002] {Function} extern not_inlined 'InlineFunction' -> 'int' + [003] {Block} + [004] {Variable} 'Var_2' -> 'int' + [003] {Variable} 'Param' -> 'int' + [003] {Variable} 'Var_1' -> 'int' + [002] {Function} extern not_inlined 'test' -> 'int' + [003] {Variable} 'A' -> 'int' + [003] {Variable} 'Param_1' -> 'int' + [003] {Variable} 'Param_2' -> 'int' + +DWARF - Clang (Linux) +^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: none + + Logical View: + [000] {File} 'pr-43860-dwarf-clang.o' -> elf64-x86-64 + + [001] {CompileUnit} 'pr-43860.cpp' + [002] {Producer} 'clang version 14.0.0' + [002] 2 {Function} extern inlined 'InlineFunction' -> 'int' + [003] {Block} + [004] 5 {Variable} 'Var_2' -> 'int' + [003] 2 {Parameter} 'Param' -> 'int' + [003] 3 {Variable} 'Var_1' -> 'int' + [002] 11 {Function} extern not_inlined 'test' -> 'int' + [003] 12 {Variable} 'A' -> 'int' + [003] 14 {InlinedFunction} inlined 'InlineFunction' -> 'int' + [004] {Block} + [005] {Variable} 'Var_2' -> 'int' + [004] {Parameter} 'Param' -> 'int' + [004] {Variable} 'Var_1' -> 'int' + [003] 11 {Parameter} 'Param_1' -> 'int' + [003] 11 {Parameter} 'Param_2' -> 'int' + +DWARF - GCC (Linux) +^^^^^^^^^^^^^^^^^^^ + +.. code-block:: none + + Logical View: + [000] {File} 'pr-43860-dwarf-gcc.o' -> elf64-x86-64 + + [001] {CompileUnit} 'pr-43860.cpp' + [002] {Producer} 'GNU C++14 9.3.0' + [002] 2 {Function} extern declared_inlined 'InlineFunction' -> 'int' + [003] {Block} + [004] 5 {Variable} 'Var_2' -> 'int' + [003] 2 {Parameter} 'Param' -> 'int' + [003] 3 {Variable} 'Var_1' -> 'int' + [002] 11 {Function} extern not_inlined 'test' -> 'int' + [003] 12 {Variable} 'A' -> 'int' + [003] 13 {InlinedFunction} declared_inlined 'InlineFunction' -> 'int' + [004] {Block} + [005] {Variable} 'Var_2' -> 'int' + [004] {Parameter} 'Param' -> 'int' + [004] {Variable} 'Var_1' -> 'int' + [003] 11 {Parameter} 'Param_1' -> 'int' + [003] 11 {Parameter} 'Param_2' -> 'int' + +From the previous logical views, we can see that the CodeView debug +information generated by the Clang compiler shows the variables **Var_1** +and **Var_2** are at the same lexical scope (**4**) in the function +**InlineFuction**. The DWARF generated by GCC/Clang and CodeView +generated by MSVC, show those variables at the correct lexical scope: +**3** and **4** respectively. + +Using the :program:`llvm-dva` selection facilities, we can produce a +simple tabular output showing just the logical elements that have in +their name the *var* pattern. The logical view is sorted by the +variables name. + +.. code-block:: none + + llvm-dva --attribute=level,format + --output-sort=name + --select-regex --select-nocase --select=Var + --report=list + --print=symbols + pr-43860-*.o + +.. code-block:: none + + Logical View: + [000] {File} 'pr-43860-codeview-clang.o' -> COFF-x86-64 + + [001] {CompileUnit} 'pr-43860.cpp' + [004] {Variable} 'Var_1' -> 'int' + [004] {Variable} 'Var_2' -> 'int' + + Logical View: + [000] {File} 'pr-43860-codeview-msvc.o' -> COFF-i386 + + [001] {CompileUnit} 'pr-43860.cpp' + [003] {Variable} 'Var_1' -> 'int' + [004] {Variable} 'Var_2' -> 'int' + + Logical View: + [000] {File} 'pr-43860-dwarf-clang.o' -> elf64-x86-64 + + [001] {CompileUnit} 'pr-43860.cpp' + [004] {Variable} 'Var_1' -> 'int' + [003] 3 {Variable} 'Var_1' -> 'int' + [005] {Variable} 'Var_2' -> 'int' + [004] 5 {Variable} 'Var_2' -> 'int' + + Logical View: + [000] {File} 'pr-43860-dwarf-gcc.o' -> elf64-x86-64 + + [001] {CompileUnit} 'pr-43860.cpp' + [004] {Variable} 'Var_1' -> 'int' + [003] 3 {Variable} 'Var_1' -> 'int' + [005] {Variable} 'Var_2' -> 'int' + [004] 5 {Variable} 'Var_2' -> 'int' + +It also shows, that the CodeView debug information does not generate +source code line numbers for the those logical symbols. The logical +view is sorted by the types name. + +TEST CASE 6 - FULL LOGICAL VIEW +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +For advanced users, :program:`llvm-dva` can display low level information +that includes offsets within the debug information section, debug location +operands, linkage names, etc. + +.. code-block:: none + + llvm-dva --attribute=all + --print=all + test-dwarf-clang.o + + Logical View: + [0x0000000000][000] {File} 'test-dwarf-clang.o' -> elf64-x86-64 + + [0x000000000b][001] {CompileUnit} 'test.cpp' + [0x000000000b][002] {Producer} 'clang version 12.0.0' + {Directory} '' + {File} 'test.cpp' + {Public} 'foo' [0x0000000000:0x000000003a] + [0x000000000b][002] {Range} Lines 2:9 [0x0000000000:0x000000003a] + [0x00000000bc][002] {BaseType} 'bool' + [0x0000000099][002] {BaseType} 'int' + [0x00000000b5][002] {BaseType} 'unsigned int' + + [0x00000000a0][002] {Source} '/test.cpp' + [0x00000000a0][002] 1 {TypeAlias} 'INTPTR' -> [0x00000000ab]'* const int' + [0x000000002a][002] 2 {Function} extern not_inlined 'foo' -> [0x0000000099]'int' + [0x000000002a][003] {Range} Lines 2:9 [0x0000000000:0x000000003a] + [0x000000002a][003] {Linkage} 0x2 '_Z3fooPKijb' + [0x0000000071][003] {Block} + [0x0000000071][004] {Range} Lines 5:8 [0x000000001c:0x000000002f] + [0x000000007e][004] 5 {Variable} 'CONSTANT' -> [0x00000000c3]'const INTEGER' + [0x000000007e][005] {Coverage} 100.00% + [0x000000007f][005] {Location} + [0x000000007f][006] {Entry} Stack Offset: -28 (0xffffffffffffffe4) [DW_OP_fbreg] + [0x000000001c][004] 5 {Line} {NewStatement} '/test.cpp' + [0x000000001c][004] {Code} 'movl $0x7, -0x1c(%rbp)' + [0x0000000023][004] 6 {Line} {NewStatement} '/test.cpp' + [0x0000000023][004] {Code} 'movl $0x7, -0x4(%rbp)' + [0x000000002a][004] {Code} 'jmp 0x6' + [0x000000002f][004] 8 {Line} {NewStatement} '/test.cpp' + [0x000000002f][004] {Code} 'movl -0x14(%rbp), %eax' + [0x0000000063][003] 2 {Parameter} 'ParamBool' -> [0x00000000bc]'bool' + [0x0000000063][004] {Coverage} 100.00% + [0x0000000064][004] {Location} + [0x0000000064][005] {Entry} Stack Offset: -21 (0xffffffffffffffeb) [DW_OP_fbreg] + [0x0000000047][003] 2 {Parameter} 'ParamPtr' -> [0x00000000a0]'INTPTR' + [0x0000000047][004] {Coverage} 100.00% + [0x0000000048][004] {Location} + [0x0000000048][005] {Entry} Stack Offset: -16 (0xfffffffffffffff0) [DW_OP_fbreg] + [0x0000000055][003] 2 {Parameter} 'ParamUnsigned' -> [0x00000000b5]'unsigned int' + [0x0000000055][004] {Coverage} 100.00% + [0x0000000056][004] {Location} + [0x0000000056][005] {Entry} Stack Offset: -20 (0xffffffffffffffec) [DW_OP_fbreg] + [0x000000008d][003] 4 {TypeAlias} 'INTEGER' -> [0x0000000099]'int' + [0x0000000000][003] 2 {Line} {NewStatement} '/test.cpp' + [0x0000000000][003] {Code} 'pushq %rbp' + [0x0000000001][003] {Code} 'movq %rsp, %rbp' + [0x0000000004][003] {Code} 'movb %dl, %al' + [0x0000000006][003] {Code} 'movq %rdi, -0x10(%rbp)' + [0x000000000a][003] {Code} 'movl %esi, -0x14(%rbp)' + [0x000000000d][003] {Code} 'andb $0x1, %al' + [0x000000000f][003] {Code} 'movb %al, -0x15(%rbp)' + [0x0000000012][003] 3 {Line} {NewStatement} {PrologueEnd} '/test.cpp' + [0x0000000012][003] {Code} 'testb $0x1, -0x15(%rbp)' + [0x0000000016][003] {Code} 'je 0x13' + [0x0000000032][003] 8 {Line} '/test.cpp' + [0x0000000032][003] {Code} 'movl %eax, -0x4(%rbp)' + [0x0000000035][003] 9 {Line} {NewStatement} '/test.cpp' + [0x0000000035][003] {Code} 'movl -0x4(%rbp), %eax' + [0x0000000038][003] {Code} 'popq %rbp' + [0x0000000039][003] {Code} 'retq' + [0x000000003a][003] 9 {Line} {NewStatement} {EndSequence} '/test.cpp' + + ----------------------------- + Element Total Printed + ----------------------------- + Scopes 3 3 + Symbols 4 4 + Types 5 5 + Lines 25 25 + ----------------------------- + Total 37 37 + + Scope Sizes: + 189 (100.00%) : [0x000000000b][001] {CompileUnit} 'test.cpp' + 110 ( 58.20%) : [0x000000002a][002] 2 {Function} extern not_inlined 'foo' -> [0x0000000099]'int' + 27 ( 14.29%) : [0x0000000071][003] {Block} + + Totals by lexical level: + [001]: 189 (100.00%) + [002]: 110 ( 58.20%) + [003]: 27 ( 14.29%) + +The **Scope Sizes** table shows the contribution in bytes to the debug +information by each scope, which can be used to determine unexpected +sizes changes in the DWARF sections between different versions of the +same toolchain. + +.. code-block:: none + + [0x000000002a][002] 2 {Function} extern not_inlined 'foo' -> [0x0000000099]'int' + [0x000000002a][003] {Range} Lines 2:9 [0x0000000000:0x000000003a] + [0x000000002a][003] {Linkage} 0x2 '_Z3fooPKijb' + [0x0000000071][003] {Block} + [0x0000000071][004] {Range} Lines 5:8 [0x000000001c:0x000000002f] + [0x000000007e][004] 5 {Variable} 'CONSTANT' -> [0x00000000c3]'const INTEGER' + [0x000000007e][005] {Coverage} 100.00% + [0x000000007f][005] {Location} + [0x000000007f][006] {Entry} Stack Offset: -28 (0xffffffffffffffe4) [DW_OP_fbreg] + +The **{Range}** attribute describe the line ranges for a logical scope. +For this case, the function **foo** is within the lines **2** and **9**. + +The **{Coverage}** and **{Location}** attributes describe the debug +location and coverage for logical symbols. For optimized code, the +coverage value decreases and it affects the program debuggability. + +EXIT STATUS +----------- +:program:`llvm-dva` returns 0 if the input files were parsed and printed +successfully. Otherwise, it returns 1. + +SEE ALSO +-------- +:manpage:`llvm-dwarfdump` Index: llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h =================================================================== --- /dev/null +++ llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h @@ -0,0 +1,52 @@ +//===-- LVElement.h ---------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the LVElement class, which is used to describe a debug +// information element. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVELEMENT_H +#define LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVELEMENT_H + +#include "llvm/DebugInfo/LogicalView/Core/LVObject.h" +#include "llvm/DebugInfo/LogicalView/Core/LVStringPool.h" +#include + +namespace llvm { +namespace logicalview { + +enum class LVElementKind { Discarded, Global, Optimized, LastEntry }; +using LVElementKindSet = std::set; + +class LVElement : public LVObject { + // Indexes in the String Pool. + size_t NameIndex = 0; + size_t FilenameIndex = 0; + +public: + bool isNamed() const override { return NameIndex != 0; } + + StringRef getName() const override { + return getStringPool().getString(NameIndex); + } + + // Get pathname associated with the Element. + StringRef getPathname() const { + return getStringPool().getString(getFilenameIndex()); + } + + // Element type name. + StringRef getTypeName() const; + size_t getFilenameIndex() const { return FilenameIndex; } +}; + +} // end namespace logicalview +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVELEMENT_H Index: llvm/include/llvm/DebugInfo/LogicalView/Core/LVLine.h =================================================================== --- /dev/null +++ llvm/include/llvm/DebugInfo/LogicalView/Core/LVLine.h @@ -0,0 +1,40 @@ +//===-- LVLine.h ------------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the LVLine class, which is used to describe a debug +// information line. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVLINE_H +#define LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVLINE_H + +#include "llvm/DebugInfo/LogicalView/Core/LVElement.h" + +namespace llvm { +namespace logicalview { + +enum class LVLineKind { + IsBasicBlock, + IsDiscriminator, + IsEndSequence, + IsEpilogueBegin, + IsLineDebug, + IsLineAssembler, + IsNewStatement, // Shared with CodeView 'IsStatement' flag. + IsPrologueEnd, + IsAlwaysStepInto, // CodeView + IsNeverStepInto, // CodeView + LastEntry +}; +using LVLineKindSet = std::set; + +} // end namespace logicalview +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVLINE_H Index: llvm/include/llvm/DebugInfo/LogicalView/Core/LVObject.h =================================================================== --- /dev/null +++ llvm/include/llvm/DebugInfo/LogicalView/Core/LVObject.h @@ -0,0 +1,58 @@ +//===-- LVObject.h ----------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the LVObject class, which is used to describe a debug +// information object. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVOBJECT_H +#define LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVOBJECT_H + +#include "llvm/DebugInfo/LogicalView/Core/LVSupport.h" + +namespace llvm { +namespace logicalview { + +using LVHalf = uint16_t; +using LVOffset = uint64_t; + +class LVObject { + LVOffset Offset = 0; + +protected: + // Get a string representation for the given number and discriminator. + std::string lineAsString(uint32_t LineNumber, LVHalf Discriminator, + bool ShowZero) const; + + // Get a string representation for the given number. + std::string referenceAsString(uint32_t LineNumber, bool Spaces) const; + + // Print the Filename or Pathname. + // Empty implementation for those objects that do not have any user + // source file references, such as debug locations. + virtual void printFileIndex(raw_ostream &OS, bool Full = true) const {} + +public: + // True if the scope has not been named or typed or no line number. + virtual bool isNamed() const { return false; } + +public: + // DIE offset. + LVOffset getOffset() const { return Offset; } + + virtual StringRef getName() const { return StringRef(); } + +public: + std::string lineNumberAsStringStripped(bool ShowZero = false) const; +}; + +} // end namespace logicalview +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVOBJECT_H Index: llvm/include/llvm/DebugInfo/LogicalView/Core/LVOptions.h =================================================================== --- /dev/null +++ llvm/include/llvm/DebugInfo/LogicalView/Core/LVOptions.h @@ -0,0 +1,454 @@ +//===-- LVOptions.h ---------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the LVOptions class, which is used to record the command +// line options. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVOPTIONS_H +#define LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVOPTIONS_H + +#include "llvm/ADT/StringSet.h" +#include "llvm/DebugInfo/LogicalView/Core/LVLine.h" +#include "llvm/DebugInfo/LogicalView/Core/LVOptions.h" +#include "llvm/DebugInfo/LogicalView/Core/LVScope.h" +#include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h" +#include "llvm/DebugInfo/LogicalView/Core/LVType.h" + +namespace llvm { +namespace logicalview { + +// Generate get and set 'bool' functions. +#define BOOL_FUNCTION(FAMILY, FIELD) \ + bool get##FAMILY##FIELD() const { return FAMILY.FIELD; } \ + void set##FAMILY##FIELD() { FAMILY.FIELD = true; } \ + void reset##FAMILY##FIELD() { FAMILY.FIELD = false; } + +// Generate get and set 'unsigned' functions. +#define UNSIGNED_FUNCTION(FAMILY, FIELD) \ + unsigned get##FAMILY##FIELD() const { return FAMILY.FIELD; } \ + void set##FAMILY##FIELD(unsigned Value) { FAMILY.FIELD = Value; } \ + void reset##FAMILY##FIELD() { FAMILY.FIELD = -1U; } + +// Generate get and set 'std::string' functions. +#define STD_STRING_FUNCTION(FAMILY, FIELD) \ + std::string get##FAMILY##FIELD() const { return FAMILY.FIELD; } \ + void set##FAMILY##FIELD(std::string FIELD) { FAMILY.FIELD = FIELD; } \ + void reset##FAMILY##FIELD() { FAMILY.FIELD = ""; } + +// Generate get and set 'std::set' functions. +#define STDSET_FUNCTION_4(FAMILY, FIELD, TYPE, SET) \ + bool get##FAMILY##FIELD() const { \ + return FAMILY.SET.find(TYPE::FIELD) != FAMILY.SET.end(); \ + } \ + void set##FAMILY##FIELD() { FAMILY.SET.insert(TYPE::FIELD); } \ + void reset##FAMILY##FIELD() { \ + std::set::iterator Iter = FAMILY.SET.find(TYPE::FIELD); \ + if (Iter != FAMILY.SET.end()) \ + FAMILY.SET.erase(Iter); \ + } + +#define STDSET_FUNCTION_5(FAMILY, FIELD, ENTRY, TYPE, SET) \ + bool get##FAMILY##FIELD##ENTRY() const { \ + return FAMILY.SET.find(TYPE::ENTRY) != FAMILY.SET.end(); \ + } \ + void set##FAMILY##FIELD##ENTRY() { FAMILY.SET.insert(TYPE::ENTRY); } + +// Generate get and set functions for '--attribute' +#define ATTRIBUTE_OPTION(FIELD) \ + STDSET_FUNCTION_4(Attribute, FIELD, LVAttributeKind, Kinds) + +// Generate get and set functions for '--output' +#define OUTPUT_OPTION(FIELD) \ + STDSET_FUNCTION_4(Output, FIELD, LVOutputKind, Kinds) + +// Generate get and set functions for '--print' +#define PRINT_OPTION(FIELD) STDSET_FUNCTION_4(Print, FIELD, LVPrintKind, Kinds) + +// Generate get and set functions for '--warning' +#define WARNING_OPTION(FIELD) \ + STDSET_FUNCTION_4(Warning, FIELD, LVWarningKind, Kinds) + +// Generate get and set functions for '--compare' +#define COMPARE_OPTION(FIELD) \ + STDSET_FUNCTION_4(Compare, FIELD, LVCompareKind, Elements) + +// Generate get and set functions for '--report' +#define REPORT_OPTION(FIELD) \ + STDSET_FUNCTION_4(Report, FIELD, LVReportKind, Kinds) + +// Generate get and set functions for '--internal' +#define INTERNAL_OPTION(FIELD) \ + STDSET_FUNCTION_4(Internal, FIELD, LVInternalKind, Kinds) + +using LVOffsetSet = std::set; + +enum class LVAttributeKind { + All, // --attribute=all + Argument, // --attribute=argument + Base, // --attribute=base + Coverage, // --attribute=coverage + Directories, // --attribute=directories + Discarded, // --attribute=discarded + Discriminator, // --attribute=discriminator + Encoded, // --attribute=encoded + Extended, // --attribute=extended + Filename, // --attribute=filename + Files, // --attribute=files + Format, // --attribute=format + Gaps, // --attribute=gaps + Generated, // --attribute=generated + Global, // --attribute=global + Inserted, // --attribute=inserted + Level, // --attribute=level + Linkage, // --attribute=linkage + Local, // --attribute=local + Location, // --attribute=location + Offset, // --attribute=offset + Pathname, // --attribute=pathname + Producer, // --attribute=producer + Publics, // --attribute=publics + Qualified, // --attribute=qualified + Qualifier, // --attribute=qualifier + Range, // --attribute=range + Reference, // --attribute=reference + Register, // --attribute=register + Standard, // --attribute=standard + Subrange, // --attribute=subrange + System, // --attribute=system + Typename, // --attribute=typename + Underlying, // --attribute=underlying + Zero // --attribute=zero +}; +using LVAttributeKindSet = std::set; + +enum class LVCompareKind { + All, // --compare=all + Lines, // --compare=lines + Scopes, // --compare=scopes + Symbols, // --compare=symbols + Types // --compare=types +}; +using LVCompareKindSet = std::set; + +enum class LVOutputKind { + All, // --output=all + Split, // --output=split + Json, // --output=json + Text // --output=text +}; +using LVOutputKindSet = std::set; + +enum class LVPrintKind { + All, // --print=all + Elements, // --print=elements + Instructions, // --print=instructions + Lines, // --print=lines + Scopes, // --print=scopes + Sizes, // --print=sizes + Symbols, // --print=symbols + Summary, // --print=summary + Types, // --print=types + Warnings // --print=warnings +}; +using LVPrintKindSet = std::set; + +enum class LVReportKind { + All, // --report=all + Children, // --report=children + List, // --report=list + Parents, // --report=parents + View // --report=view +}; +using LVReportKindSet = std::set; + +enum class LVWarningKind { + All, // --warning=all + Coverages, // --warning=coverages + Lines, // --warning=lines + Locations, // --warning=locations + Ranges // --warning=ranges +}; +using LVWarningKindSet = std::set; + +enum class LVInternalKind { + All, // --internal=all + Cmdline, // --internal=cmdline + ID, // --internal=id + Integrity, // --internal=integrity + None, // --internal=none + Tag // --internal=tag +}; +using LVInternalKindSet = std::set; + +// The 'Kinds' members are a one-to-one mapping to the associated command +// options that supports comma separated values. There are other 'bool' +// members that in very few cases point to a command option (see associated +// comment. Other cases for 'bool' refers to internal values derivated from +// the command options. +class LVOptions { + class LVAttribute { + public: + LVAttributeKindSet Kinds; // --attribute= + bool Added = false; // Added elements found during comparison. + bool AnyLocation = false; // Any kind of location information. + bool AnySource = false; // Any kind of source information. + bool Missing = false; // Missing elements found during comparison. + }; + + class LVCompare { + public: + LVCompareKindSet Elements; // --compare= + bool Context = false; // --compare-context + bool Execute = false; // Compare requested. + bool Print = false; // Enable any printing. + }; + + class LVPrint { + public: + LVPrintKindSet Kinds; // --print= + bool AnyElement = false; // Request to print any element. + bool AnyLine = false; // Print 'lines' or 'instructions'. + bool Execute = false; // Print requested. + bool Formatting = true; // Disable formatting during printing. + bool Offset = false; // Print offsets while formatting is disable. + bool SizesSummary = false; // Print 'sizes' or 'summary'. + }; + + class LVReport { + public: + LVReportKindSet Kinds; // --report= + bool AnyView = false; // View, Parents or Children. + bool Execute = false; // Report requested. + }; + + 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 kind. + 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= + }; + + class LVOutput { + public: + LVOutputKindSet Kinds; // --output= + LVSortMode SortMode = LVSortMode::None; // --output-sort= + std::string Folder; // --output-folder= + unsigned Level = -1U; // --output-level= + }; + + class LVWarning { + public: + LVWarningKindSet Kinds; // --warning= + }; + + class LVInternal { + public: + LVInternalKindSet Kinds; // --internal= + }; + + class LVGeneral { + public: + bool CollectRanges = false; // Collect ranges information. + }; + + // Filters the output of the filename associated with the element being + // printed in order to see clearly which logical elements belongs to + // a particular filename. It is value is reset after the element + // that represents the Compile Unit is printed. + size_t LastFilenameIndex = 0; + + // Controls the amount of additional spaces to insert when printing + // object attributes, in order to get a consistent printing layout. + size_t IndentationSize = 0; + + // Calculate the indentation size, so we can use that value when printing + // additional attributes to objects, such as location. + void calculateIndentationSize(); + +public: + void resetFilenameIndex() { LastFilenameIndex = 0; } + bool changeFilenameIndex(size_t Index) { + bool IndexChanged = (Index != LastFilenameIndex); + if (IndexChanged) + LastFilenameIndex = Index; + return IndexChanged; + } + +public: + // Access to command line options, pattern and printing information. + static LVOptions *getOptions(); + static void setOptions(LVOptions *Options); + +public: + LVOptions() = default; + LVOptions(const LVOptions &) = default; + LVOptions &operator=(LVOptions const &) = default; + ~LVOptions() = default; + + // Some command line options support shortcuts. For example: + // The command line option '--print=elements' is a shortcut for: + // '--print=instructions,lines,scopes,symbols,types'. + // In the case of logical view comparison, some options related to + // attributes must be set or reset for a proper comparison. + // Resolve any dependencies between command line options. + void resolveDependencies(); + size_t indentationSize() const { return IndentationSize; } + +public: + LVAttribute Attribute; + LVCompare Compare; + LVOutput Output; + LVPrint Print; + LVReport Report; + LVSelect Select; + LVWarning Warning; + LVInternal Internal; + LVGeneral General; + +public: + // --attribute. + ATTRIBUTE_OPTION(All); + ATTRIBUTE_OPTION(Argument); + ATTRIBUTE_OPTION(Base); + ATTRIBUTE_OPTION(Coverage); + ATTRIBUTE_OPTION(Directories); + ATTRIBUTE_OPTION(Discarded); + ATTRIBUTE_OPTION(Discriminator); + ATTRIBUTE_OPTION(Encoded); + ATTRIBUTE_OPTION(Extended); + ATTRIBUTE_OPTION(Filename); + ATTRIBUTE_OPTION(Files); + ATTRIBUTE_OPTION(Format); + ATTRIBUTE_OPTION(Gaps); + ATTRIBUTE_OPTION(Generated); + ATTRIBUTE_OPTION(Global); + ATTRIBUTE_OPTION(Inserted); + ATTRIBUTE_OPTION(Level); + ATTRIBUTE_OPTION(Linkage); + ATTRIBUTE_OPTION(Location); + ATTRIBUTE_OPTION(Local); + ATTRIBUTE_OPTION(Offset); + ATTRIBUTE_OPTION(Pathname); + ATTRIBUTE_OPTION(Producer); + ATTRIBUTE_OPTION(Publics); + ATTRIBUTE_OPTION(Qualified); + ATTRIBUTE_OPTION(Qualifier); + ATTRIBUTE_OPTION(Range); + ATTRIBUTE_OPTION(Reference); + ATTRIBUTE_OPTION(Register); + ATTRIBUTE_OPTION(Standard); + ATTRIBUTE_OPTION(Subrange); + ATTRIBUTE_OPTION(System); + ATTRIBUTE_OPTION(Typename); + ATTRIBUTE_OPTION(Underlying); + ATTRIBUTE_OPTION(Zero); + BOOL_FUNCTION(Attribute, Added); + BOOL_FUNCTION(Attribute, AnyLocation); + BOOL_FUNCTION(Attribute, AnySource); + BOOL_FUNCTION(Attribute, Missing); + + // --compare. + COMPARE_OPTION(All); + COMPARE_OPTION(Lines); + COMPARE_OPTION(Scopes); + COMPARE_OPTION(Symbols); + COMPARE_OPTION(Types); + BOOL_FUNCTION(Compare, Context); + BOOL_FUNCTION(Compare, Execute); + BOOL_FUNCTION(Compare, Print); + + // --output. + OUTPUT_OPTION(All); + OUTPUT_OPTION(Split); + OUTPUT_OPTION(Text); + OUTPUT_OPTION(Json); + STD_STRING_FUNCTION(Output, Folder); + UNSIGNED_FUNCTION(Output, Level); + LVSortMode getSortMode() const { return Output.SortMode; } + void setSortMode(LVSortMode SortMode) { Output.SortMode = SortMode; } + + // --print. + PRINT_OPTION(All); + PRINT_OPTION(Elements); + PRINT_OPTION(Instructions); + PRINT_OPTION(Lines); + PRINT_OPTION(Scopes); + PRINT_OPTION(Sizes); + PRINT_OPTION(Symbols); + PRINT_OPTION(Summary); + PRINT_OPTION(Types); + PRINT_OPTION(Warnings); + BOOL_FUNCTION(Print, AnyElement); + BOOL_FUNCTION(Print, AnyLine); + BOOL_FUNCTION(Print, Execute); + BOOL_FUNCTION(Print, Formatting); + BOOL_FUNCTION(Print, Offset); + BOOL_FUNCTION(Print, SizesSummary); + + // --report. + REPORT_OPTION(All); + REPORT_OPTION(Children); + REPORT_OPTION(List); + REPORT_OPTION(Parents); + REPORT_OPTION(View); + BOOL_FUNCTION(Report, AnyView); + BOOL_FUNCTION(Report, Execute); + + // --select. + BOOL_FUNCTION(Select, IgnoreCase); + BOOL_FUNCTION(Select, UseRegex); + BOOL_FUNCTION(Select, Execute); + BOOL_FUNCTION(Select, GenericKind); + BOOL_FUNCTION(Select, GenericPattern); + BOOL_FUNCTION(Select, OffsetPattern); + + // --warning. + WARNING_OPTION(All); + WARNING_OPTION(Coverages); + WARNING_OPTION(Lines); + WARNING_OPTION(Locations); + WARNING_OPTION(Ranges); + + // --internal. + INTERNAL_OPTION(All); + INTERNAL_OPTION(Cmdline); + INTERNAL_OPTION(ID); + INTERNAL_OPTION(Integrity); + INTERNAL_OPTION(None); + INTERNAL_OPTION(Tag); + + // General shortcuts to some combinations. + BOOL_FUNCTION(General, CollectRanges); + +public: + void print(raw_ostream &OS) const; + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) + void dump() const { print(dbgs()); } +#endif +}; + +inline LVOptions &options() { return (*LVOptions::getOptions()); } +inline void setOptions(LVOptions *Options) { LVOptions::setOptions(Options); } + +} // namespace logicalview +} // namespace llvm + +#endif // LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVOPTIONS_H Index: llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h =================================================================== --- /dev/null +++ llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h @@ -0,0 +1,55 @@ +//===-- LVScope.h -----------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the LVScope class, which is used to describe a debug +// information scope. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVSCOPE_H +#define LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVSCOPE_H + +#include "llvm/DebugInfo/LogicalView/Core/LVElement.h" +#include "llvm/DebugInfo/LogicalView/Core/LVSort.h" + +namespace llvm { +namespace logicalview { + +enum class LVScopeKind { + IsAggregate, + IsArray, + IsBlock, + IsCallSite, + IsCatchBlock, + IsClass, + IsCompileUnit, + IsEntryPoint, + IsEnumeration, + IsFunction, + IsFunctionType, + IsInlinedFunction, + IsLabel, + IsLexicalBlock, + IsMember, + IsNamespace, + IsRoot, + IsStructure, + IsSubprogram, + IsTemplate, + IsTemplateAlias, + IsTemplatePack, + IsTryBlock, + IsUnion, + LastEntry +}; +using LVScopeKindSet = std::set; + +} // end namespace logicalview +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVSCOPE_H Index: llvm/include/llvm/DebugInfo/LogicalView/Core/LVSort.h =================================================================== --- /dev/null +++ llvm/include/llvm/DebugInfo/LogicalView/Core/LVSort.h @@ -0,0 +1,31 @@ +//===-- LVSort.h ------------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the sort algorithms. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVSORT_H +#define LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVSORT_H + +namespace llvm { +namespace logicalview { + +// Object Sorting Mode. +enum class LVSortMode { + None = 0, // No given sort. + Kind, // Sort by kind. + Line, // Sort by line. + Name, // Sort by name. + Offset // Sort by offset. +}; + +} // end namespace logicalview +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVSORT_H Index: llvm/include/llvm/DebugInfo/LogicalView/Core/LVStringPool.h =================================================================== --- /dev/null +++ llvm/include/llvm/DebugInfo/LogicalView/Core/LVStringPool.h @@ -0,0 +1,101 @@ +//===-- LVStringPool.h ------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the LVStringPool class, which is used to implement a +// basic string pool table. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVSTRINGPOOL_H +#define LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVSTRINGPOOL_H + +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include +#include + +namespace llvm { +namespace logicalview { + +class LVStringPool { + const size_t BadIndex = std::numeric_limits::max(); + using TableType = StringMap; + using ValueType = TableType::value_type; + BumpPtrAllocator Allocator; + TableType StringTable; + std::vector Entries; + +public: + LVStringPool() { getIndex(""); } + LVStringPool(LVStringPool const &other) = delete; + LVStringPool(LVStringPool &&other) = delete; + ~LVStringPool() = default; + +public: + bool isValidIndex(size_t Index) { return Index != BadIndex; } + + // Return number of strings in the pool. The empty string is allocated + // at the slot zero. We substract 1 to indicate the number of non empty + // strings. + size_t getSize() { return Entries.size() - 1; } + + // Return the index for the specified key, otherwise 'BadIndex'. + size_t findIndex(StringRef Key) { + TableType::const_iterator Iter = StringTable.find(Key); + if (Iter != StringTable.end()) + return Iter->second; + return BadIndex; + } + + // Return an index for the specified key. + size_t getIndex(StringRef Key) { + size_t Index = findIndex(Key); + if (isValidIndex(Index)) + return Index; + size_t Value = Entries.size(); + ValueType *Entry = ValueType::Create(Key, Allocator, std::move(Value)); + StringTable.insert(Entry); + Entries.push_back(Entry); + return Value; + } + + // Given the index, return its corresponding string. + StringRef getString(size_t Index) { + assert(Index < Entries.size() && "Invalid string pool index."); + return (Index >= Entries.size()) ? StringRef() : Entries[Index]->getKey(); + } + + static LVStringPool &getInstance() { + static LVStringPool Instance; + return Instance; + } + +public: + void print(raw_ostream &OS) const { + if (!Entries.empty()) { + OS << "\nString Pool:\n"; + for (const ValueType *Entry : Entries) + OS << "Index: " << Entry->getValue() << ", " + << "Key: '" << Entry->getKey() << "'\n"; + } + } + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) + virtual void dump() const { print(dbgs()); } +#endif +}; + +inline LVStringPool &getStringPool() { return LVStringPool::getInstance(); } + +} // namespace logicalview +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVSTRINGPOOL_H Index: llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h =================================================================== --- /dev/null +++ llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h @@ -0,0 +1,51 @@ +//===-- LVSupport.h ---------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines support functions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVSUPPORT_H +#define LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVSUPPORT_H + +#include "llvm/ADT/SmallBitVector.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" +#include +#include + +namespace llvm { +namespace logicalview { + +const int HEX_WIDTH = 12; +inline FormattedNumber hexValue(uint64_t N, unsigned Width = HEX_WIDTH, + bool Upper = false) { + return format_hex(N, Width, Upper); +} + +// Output the hexadecimal representation of 'Value' using '[0x%08x]' format. +inline std::string hexString(uint64_t Value, size_t Width = HEX_WIDTH) { + std::string String; + raw_string_ostream Stream(String); + Stream << hexValue(Value, Width, false); + return Stream.str(); +} + +// Get a hexadecimal string representation for the given value. +inline std::string hexSquareString(uint64_t Value) { + return (Twine("[") + Twine(hexString(Value)) + Twine("]")).str(); +} + +} // end namespace logicalview +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVSUPPORT_H Index: llvm/include/llvm/DebugInfo/LogicalView/Core/LVSymbol.h =================================================================== --- /dev/null +++ llvm/include/llvm/DebugInfo/LogicalView/Core/LVSymbol.h @@ -0,0 +1,37 @@ +//===-- LVSymbol.h ----------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the LVSymbol class, which is used to describe a debug +// information symbol. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVSYMBOL_H +#define LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVSYMBOL_H + +#include "llvm/DebugInfo/LogicalView/Core/LVElement.h" + +namespace llvm { +namespace logicalview { + +enum class LVSymbolKind { + IsCallSiteParameter, + IsConstant, + IsInheritance, + IsMember, + IsParameter, + IsUnspecified, + IsVariable, + LastEntry +}; +using LVSymbolKindSet = std::set; + +} // end namespace logicalview +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVSYMBOL_H Index: llvm/include/llvm/DebugInfo/LogicalView/Core/LVType.h =================================================================== --- /dev/null +++ llvm/include/llvm/DebugInfo/LogicalView/Core/LVType.h @@ -0,0 +1,51 @@ +//===-- LVType.h ------------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the LVType class, which is used to describe a debug +// information type. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVTYPE_H +#define LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVTYPE_H + +#include "llvm/DebugInfo/LogicalView/Core/LVElement.h" + +namespace llvm { +namespace logicalview { + +enum class LVTypeKind { + IsBase, + IsConst, + IsEnumerator, + IsImport, + IsImportDeclaration, + IsImportModule, + IsPointer, + IsPointerMember, + IsReference, + IsRestrict, + IsRvalueReference, + IsSubrange, + IsTemplateParam, + IsTemplateTemplateParam, + IsTemplateTypeParam, + IsTemplateValueParam, + IsTypedef, + IsUnaligned, + IsUnspecified, + IsVolatile, + IsModifier, // CodeView - LF_MODIFIER + LastEntry +}; +using LVTypeKindSelection = std::set; + +} // end namespace logicalview +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVTYPE_H Index: llvm/lib/DebugInfo/CMakeLists.txt =================================================================== --- llvm/lib/DebugInfo/CMakeLists.txt +++ llvm/lib/DebugInfo/CMakeLists.txt @@ -1,5 +1,6 @@ add_subdirectory(DWARF) add_subdirectory(GSYM) +add_subdirectory(LogicalView) add_subdirectory(MSF) add_subdirectory(CodeView) add_subdirectory(PDB) Index: llvm/lib/DebugInfo/LogicalView/CMakeLists.txt =================================================================== --- /dev/null +++ llvm/lib/DebugInfo/LogicalView/CMakeLists.txt @@ -0,0 +1,31 @@ +set(LLVM_LINK_COMPONENTS + BinaryFormat + DebugInfoDWARF + DebugInfoCodeView + DebugInfoPDB + Demangle + MC + Object + Support + ) + +macro(add_lv_impl_folder group) + list(APPEND LV_IMPL_SOURCES ${ARGN}) + source_group(${group} FILES ${ARGN}) +endmacro() + +add_lv_impl_folder(Core + Core/LVOptions.cpp + ) + +list(APPEND LIBLV_ADDITIONAL_HEADER_DIRS + "${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/LogicalView" + "${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/LogicalView/Core" + ) + +add_llvm_library(LLVMDebugInfoLogicalView + ${LV_IMPL_SOURCES} + + ADDITIONAL_HEADER_DIRS + ${LIBLV_ADDITIONAL_HEADER_DIRS} + ) Index: llvm/lib/DebugInfo/LogicalView/Core/LVOptions.cpp =================================================================== --- /dev/null +++ llvm/lib/DebugInfo/LogicalView/Core/LVOptions.cpp @@ -0,0 +1,396 @@ +//===-- LVOptions.cpp -----------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This implements the LVOptions class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/LogicalView/Core/LVOptions.h" + +using namespace llvm; +using namespace llvm::logicalview; + +#define DEBUG_TYPE "Options" + +//===----------------------------------------------------------------------===// +// Options extracted from the command line. +//===----------------------------------------------------------------------===// +static LVOptions Options; +LVOptions *LVOptions::getOptions() { return &Options; } +void LVOptions::setOptions(LVOptions *CmdOptions) { Options = *CmdOptions; } + +void LVOptions::resolveDependencies() { + // Attributes that are classified as standard options. + auto standardAttributes = [&]() { + // Set the 'standard' attribute to indicate its associated attributes. + setAttributeStandard(); + + setAttributeBase(); + setAttributeCoverage(); + setAttributeDirectories(); + setAttributeDiscriminator(); + setAttributeFilename(); + setAttributeFiles(); + setAttributeFormat(); + setAttributeLevel(); + setAttributeProducer(); + setAttributePublics(); + setAttributeRange(); + setAttributeReference(); + setAttributeZero(); + }; + + // Attributes that are classified as extended options. + auto extendedAttributes = [&]() { + // Set the 'extended' attribute to indicate its associated attributes. + setAttributeExtended(); + + setAttributeArgument(); + setAttributeDiscarded(); + setAttributeEncoded(); + setAttributeGaps(); + setAttributeGenerated(); + setAttributeGlobal(); + setAttributeInserted(); + setAttributeLinkage(); + setAttributeLocal(); + setAttributeLocation(); + setAttributeOffset(); + setAttributePathname(); + setAttributeQualified(); + setAttributeQualifier(); + setAttributeRegister(); + setAttributeSubrange(); + setAttributeSystem(); + setAttributeTypename(); + }; + + // '--Attribute=standard' settings. + if (getAttributeStandard()) + standardAttributes(); + + // '--Attribute=extended' settings. + if (getAttributeExtended()) + extendedAttributes(); + + // '--Attribute=all' settings. + if (getAttributeAll()) { + standardAttributes(); + extendedAttributes(); + } + + // '--attribute=pathname' supersedes '--attribute=filename'. + if (getAttributePathname()) + resetAttributeFilename(); + + // Assume '--output=text' as default + if (!getOutputText() && !getOutputJson()) + setOutputText(); + + // '--output=all' settings. + if (getOutputAll()) { + setOutputJson(); + setOutputSplit(); + setOutputText(); + } + + // A view split folder was specified. + if (getOutputFolder().length()) + setOutputSplit(); + + // Always use the full pathname with splitted output. + if (getOutputSplit()) + setAttributePathname(); + + // '--print=elements' settings. + if (getPrintElements()) { + setPrintInstructions(); + setPrintLines(); + setPrintScopes(); + setPrintSymbols(); + setPrintTypes(); + } + + // '--print=all' settings. + if (getPrintAll()) { + setPrintInstructions(); + setPrintLines(); + setPrintScopes(); + setPrintSizes(); + setPrintSymbols(); + setPrintSummary(); + setPrintTypes(); + setPrintWarnings(); + } + + // '--warning=all' settings. + if (getWarningAll()) { + setWarningCoverages(); + setWarningLines(); + setWarningLocations(); + setWarningRanges(); + } + + // '--internal=all' settings. + if (getInternalAll()) { + setInternalCmdline(); + setInternalID(); + setInternalIntegrity(); + setInternalNone(); + setInternalTag(); + } + + // '--compare=all' settings. + if (getCompareAll()) { + setCompareLines(); + setCompareScopes(); + setCompareSymbols(); + setCompareTypes(); + } + + // Compare the scopes if a request for compare symbols, types, lines. + if (getCompareLines() || getCompareSymbols() || getCompareTypes()) + setCompareScopes(); + + // Generic request for comparison. + if (getCompareScopes()) + setCompareExecute(); + + // Print any logical line (debug or instruction). + if (getPrintInstructions() || getPrintLines()) + setPrintAnyLine(); + + // Print any logical element (line, scope, symbol or type). + if (getPrintAnyLine() || getPrintScopes() || getPrintSymbols() || + getPrintTypes()) + setPrintAnyElement(); + + // Print 'sizes' or 'summary'. + if (getPrintSizes() && getPrintSummary()) + setPrintSizesSummary(); + + // Generic request for printing. + if (getPrintAll() || getPrintAnyElement() || getPrintSizesSummary() || + getPrintWarnings()) + setPrintExecute(); + + // '--reports=all' settings. + if (getReportAll()) { + setReportChildren(); + setReportList(); + setReportParents(); + setReportView(); + } + + // '--report=view' is a shortcut for '--report=parents,children'. + if (getReportView()) { + setReportChildren(); + setReportParents(); + } + + // The report will include: Parents or Children. + if (getReportParents() || getReportChildren() || getReportView()) + setReportAnyView(); + + // The report will include: List or Parents or Children. + if (getReportList() || getReportAnyView()) + setReportExecute(); + + // If a view or element comparison has been requested, the following options + // must be set, in order to get a correct compare: + // 1) Sort the CUs, to get a fast compare. + // 2) Encode template instantiations, so the names include template + // parameter information. + // 3) Include qualified types. + // 4) Include any inserted abstract references. + // 5) For added/missing elements add the '+' or '-' tags. + if (getCompareExecute()) { + resetPrintExecute(); + setComparePrint(); + setSortMode(LVSortMode::Line); + setAttributeAdded(); + setAttributeArgument(); + setAttributeEncoded(); + setAttributeInserted(); + setAttributeMissing(); + setAttributeQualified(); + } + + // Enable formatting for printing (indentation, print children). + setPrintFormatting(); + + // These attributes are dependent on the capture of location information. + if (getAttributeCoverage() || getAttributeGaps() || getAttributeRegister()) + setAttributeLocation(); + + // Location information is only relevant when printing symbols. + if (!getPrintSymbols()) { + resetAttributeCoverage(); + resetAttributeGaps(); + resetAttributeLocation(); + resetAttributeRegister(); + } + + // Quick check for printing any element source information. + if (getAttributeFilename() || getAttributePathname()) + setAttributeAnySource(); + + // Quick check for printing any location information. + if (getAttributeLocation() || getAttributeRange()) + setAttributeAnyLocation(); + + if (getAttributeRange() || getPrintAnyLine()) + setGeneralCollectRanges(); + + calculateIndentationSize(); + + // Print collected command line options. + LLVM_DEBUG({ dump(); }); +} + +void LVOptions::calculateIndentationSize() { +#ifndef NDEBUG + if (getInternalID()) { + std::string String = hexSquareString(0); + IndentationSize += String.length(); + } +#endif + if (getCompareExecute() && (getAttributeAdded() || getAttributeMissing())) + ++IndentationSize; + if (getAttributeOffset()) { + std::string String = hexSquareString(0); + IndentationSize += String.length(); + } + if (getAttributeLevel()) { + std::stringstream Stream; + Stream.str(std::string()); + Stream << "[" << std::setfill('0') << std::setw(3) << 0 << "]"; + IndentationSize += Stream.tellp(); + } + if (getAttributeGlobal()) + ++IndentationSize; +} + +// Print the current values for all the options, after the dependencies +// has been resolved. +void LVOptions::print(raw_ostream &OS) const { + // --attribute + OS << "** Attributes **\n" + << "All: " << getAttributeAll() << ", " + << "Argument: " << getAttributeArgument() << ", " + << "Base: " << getAttributeBase() << ", " + << "Coverage: " << getAttributeCoverage() << "\n" + << "Directories: " << getAttributeDirectories() << ", " + << "Discarded: " << getAttributeDiscarded() << ", " + << "Discriminator: " << getAttributeDiscriminator() << ", " + << "Encoded: " << getAttributeEncoded() << "\n" + << "Extended: " << getAttributeExtended() << ", " + << "Filename: " << getAttributeFilename() << ", " + << "Files: " << getAttributeFiles() << ", " + << "Format: " << getAttributeFormat() << "\n" + << "Gaps: " << getAttributeGaps() << ", " + << "Generated: " << getAttributeGenerated() << ", " + << "Global: " << getAttributeGlobal() << ", " + << "Inserted: " << getAttributeInserted() << "\n" + << "Level: " << getAttributeLevel() << ", " + << "Linkage: " << getAttributeLinkage() << ", " + << "Local: " << getAttributeLocal() << ", " + << "Location: " << getAttributeLocation() << "\n" + << "Offset: " << getAttributeOffset() << ", " + << "Pathname: " << getAttributePathname() << ", " + << "Producer: " << getAttributeProducer() << ", " + << "Publics: " << getAttributePublics() << "\n" + << "Qualified: " << getAttributeQualified() << ", " + << "Qualifier: " << getAttributeQualifier() << ", " + << "Range: " << getAttributeRange() << ", " + << "Reference: " << getAttributeReference() << "\n" + << "Register: " << getAttributeRegister() << ", " + << "Standard: " << getAttributeStandard() << ", " + << "Subrange: " << getAttributeSubrange() << ", " + << "System: " << getAttributeSystem() << "\n" + << "Typename: " << getAttributeTypename() << ", " + << "Underlying: " << getAttributeUnderlying() << ", " + << "Zero: " << getAttributeZero() << "\n"; + OS << "Added: " << getAttributeAdded() << ", " + << "AnyLocation: " << getAttributeAnyLocation() << ", " + << "AnySource: " << getAttributeAnySource() << ", " + << "Missing: " << getAttributeMissing() << "\n" + << "\n"; + + // --compare + OS << "** Compare **\n" + << "All: " << getCompareAll() << ", " + << "Lines: " << getCompareLines() << ", " + << "Scopes: " << getCompareScopes() << ", " + << "Symbols: " << getCompareSymbols() << ", " + << "Types: " << getCompareTypes() << "\n"; + OS << "Context: " << getCompareContext() << ", " + << "Execute: " << getCompareExecute() << ", " + << "Print: " << getComparePrint() << "\n" + << "\n"; + + // --print + OS << "** Print **\n" + << "All: " << getPrintAll() << ", " + << "Elements: " << getPrintElements() << ", " + << "Instructions: " << getPrintInstructions() << ", " + << "Lines: " << getPrintLines() << "\n" + << "Scopes: " << getPrintScopes() << ", " + << "Sizes: " << getPrintSizes() << ", " + << "Summary: " << getPrintSummary() << ", " + << "Symbols: " << getPrintSymbols() << "\n" + << "Types: " << getPrintTypes() << ", " + << "Warnings: " << getPrintWarnings() << "\n"; + OS << "AnyElemeny: " << getPrintAnyElement() << ", " + << "AnyLine: " << getPrintAnyLine() << ", " + << "Execute: " << getPrintExecute() << ", " + << "Formatting: " << getPrintFormatting() << "\n" + << "Offset: " << getPrintOffset() << ", " + << "SizesSummary: " << getPrintSizesSummary() << "\n" + << "\n"; + + // --report + OS << "** Report **\n" + << "All: " << getReportAll() << ", " + << "Children: " << getReportChildren() << ", " + << "List: " << getReportList() << ", " + << "Parents: " << getReportParents() << ", " + << "View: " << getReportView() << "\n"; + OS << "AnyView: " << getReportAnyView() << ", " + << "Execute: " << getReportExecute() << "\n" + << "\n"; + + // --select + OS << "** Select **\n" + << "IgnoreCase: " << getSelectIgnoreCase() << ", " + << "UseRegex: " << getSelectUseRegex() << ", " + << "Execute: " << getSelectExecute() << ", " + << "GenericKind: " << getSelectGenericKind() << "\n" + << "GenericPattern: " << getSelectGenericPattern() << ", " + << "OffsetPattern: " << getSelectOffsetPattern() << "\n" + << "\n"; + + // --warning + OS << "** Warning **\n" + << "All: " << getWarningAll() << ", " + << "Coverage: " << getWarningCoverages() << ", " + << "Lines: " << getWarningLines() << ", " + << "Locations: " << getWarningLocations() << ", " + << "Ranges: " << getWarningRanges() << "\n" + << "\n"; + + // --internal + OS << "** Internal **\n" + << "All: " << Options.getInternalAll() << ", " + << "Cmdline: " << Options.getInternalCmdline() << ", " + << "ID: " << Options.getInternalID() << ", " + << "Integrity: " << Options.getInternalIntegrity() << ", " + << "None: " << Options.getInternalNone() << "\n" + << "Tag: " << Options.getInternalTag() << "\n" + << "\n"; +} Index: llvm/lib/DebugInfo/LogicalView/LLVMBuild.txt =================================================================== --- /dev/null +++ llvm/lib/DebugInfo/LogicalView/LLVMBuild.txt @@ -0,0 +1,21 @@ +;===- ./lib/DebugInfo/LogicalView/LLVMBuild.txt ----------------*- Conf -*--===; +; +; Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +; See https://llvm.org/LICENSE.txt for license information. +; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = DebugInfoLogicalView +parent = DebugInfo +required_libraries = Object Support DebugInfoDWARF DebugInfoCodeView DebugInfoPDB \ No newline at end of file Index: llvm/test/CMakeLists.txt =================================================================== --- llvm/test/CMakeLists.txt +++ llvm/test/CMakeLists.txt @@ -80,6 +80,7 @@ llvm-dis llvm-dlltool dsymutil + llvm-dva llvm-dwarfdump llvm-dwp llvm-exegesis Index: llvm/test/tools/llvm-dva/cmdline.test =================================================================== --- /dev/null +++ llvm/test/tools/llvm-dva/cmdline.test @@ -0,0 +1,221 @@ +RUN: llvm-dva --version 2>&1 | FileCheck --check-prefix=VERSION %s +VERSION: {{ version }} + +RUN: llvm-dva -h > %t 2>&1 +RUN: FileCheck -input-file=%t %s --check-prefix=HELP --implicit-check-not=out-file +RUN: llvm-dva --help > %t 2>&1 +RUN: FileCheck -input-file=%t %s --check-prefix=HELP --implicit-check-not=out-file +HELP: OVERVIEW: Printing a logical representation of low-level debug information. +HELP: USAGE: llvm-dva{{[^ ]*}} [options] +HELP: OPTIONS: +HELP: Generic Options: +HELP: --help - Display available options (--help-hidden for more) +HELP: --help-list - Display list of available options (--help-list-hidden for more) +HELP: --version - Display the version of this program +HELP: Print Options: +HELP: These control which elements are printed. +HELP: --print= - Element to print. +HELP: =all - All elements. +HELP: =elements - Instructions, lines, scopes, symbols and types. +HELP: =instructions - Assembler instructions. +HELP: =lines - Lines referenced in the debug information. +HELP: =scopes - A lexical block (Function, Class, etc.). +HELP: =sizes - Scope contributions to the debug information. +HELP: =summary - Summary of elements missing/added/matched/printed. +HELP: =symbols - Symbols (Variable, Members, etc.). +HELP: =types - Types (Pointer, Reference, etc.). +HELP: =warnings - Warnings detected. +HELP: Pass @FILE as argument to read options from FILE. + +RUN: llvm-dva --help-hidden > %t 2>&1 +RUN: FileCheck -input-file=%t %s --check-prefix=HELP-ALL --implicit-check-not=out-file +HELP-ALL: OVERVIEW: Printing a logical representation of low-level debug information. +HELP-ALL: USAGE: llvm-dva{{[^ ]*}} [options] +HELP-ALL: OPTIONS: +HELP-ALL: Attribute Options: +HELP-ALL: These control extra attributes that are added when the element is printed. +HELP-ALL: --attribute= - Element attributes. +HELP-ALL: =all - Include all attributes. +HELP-ALL: =argument - Template parameters replaced by its arguments. +HELP-ALL: =base - Base types (int, bool, etc.). +HELP-ALL: =coverage - Symbol location coverage. +HELP-ALL: =directories - Directories referenced in the debug information. +HELP-ALL: =discarded - Discarded elements by the linker. +HELP-ALL: =discriminator - Discriminators for inlined function instances. +HELP-ALL: =encoded - Template arguments encoded in the template name. +HELP-ALL: =extended - Advanced attributes alias. +HELP-ALL: =filename - Filename where the element is defined. +HELP-ALL: =files - Files referenced in the debug information. +HELP-ALL: =format - Objet file format name. +HELP-ALL: =gaps - Missing debug location (gaps). +HELP-ALL: =generated - Compiler generated elements. +HELP-ALL: =global - Element referenced across Compile Units. +HELP-ALL: =inserted - Generated inlined abstract references. +HELP-ALL: =level - Lexical scope level (File=0, Compile Unit=1). +HELP-ALL: =linkage - Linkage name. +HELP-ALL: =local - Element referenced only in the Compile Unit. +HELP-ALL: =location - Element debug location. +HELP-ALL: =offset - Debug information offset. +HELP-ALL: =pathname - Pathname where the element is defined. +HELP-ALL: =producer - Toolchain identification name. +HELP-ALL: =publics - Function names that are public. +HELP-ALL: =qualified - The element type include parents in its name. +HELP-ALL: =qualifier - Line qualifiers (Newstatement, BasicBlock, etc.). +HELP-ALL: =range - Debug location ranges. +HELP-ALL: =reference - Element declaration and definition references. +HELP-ALL: =register - Processor register names. +HELP-ALL: =standard - Basic attributes alias. +HELP-ALL: =subrange - Subrange encoding information for arrays. +HELP-ALL: =system - Display PDB's MS system elements. +HELP-ALL: =typename - Include Parameters in templates. +HELP-ALL: =underlying - Underlying type for type definitions. +HELP-ALL: =zero - Zero line numbers. +HELP-ALL: Color Options: +HELP-ALL: This option category has no options. +HELP-ALL: Compare Options: +HELP-ALL: These control the view comparison. +HELP-ALL: --compare= - Elements to compare. +HELP-ALL: =all - Compare all elements. +HELP-ALL: =lines - Lines. +HELP-ALL: =scopes - Scopes. +HELP-ALL: =symbols - Symbols. +HELP-ALL: =types - Types. +HELP-ALL: --compare-context - Add the View as compare context. +HELP-ALL: General options: +HELP-ALL: This option category has no options. +HELP-ALL: Generic Options: +HELP-ALL: -h - Alias for --help +HELP-ALL: --help - Display available options (--help-hidden for more) +HELP-ALL: --help-hidden - Display all available options +HELP-ALL: --help-list - Display list of available options (--help-list-hidden for more) +HELP-ALL: --help-list-hidden - Display list of all available options +HELP-ALL: --print-all-options - Print all option values after command line parsing +HELP-ALL: --print-options - Print non-default options after command line parsing +HELP-ALL: --version - Display the version of this program +HELP-ALL: Internal Options: +HELP-ALL: Internal traces and extra debugging code. +HELP-ALL: --internal= - Traces to enable. +HELP-ALL: =all - Enable all traces. +HELP-ALL: =cmdline - Print command line. +HELP-ALL: =id - Print unique element ID +HELP-ALL: =integrity - Check elements integrity. +HELP-ALL: =none - Ignore element line number. +HELP-ALL: =tag - Debug information tags. +HELP-ALL: Output Options: +HELP-ALL: These control the output generated. +HELP-ALL: --output= - Outputs for view. +HELP-ALL: =all - All outputs. +HELP-ALL: =split - Split the output by Compile Units. +HELP-ALL: =text - Use a free form text output. +HELP-ALL: =json - Use JSON as the output format. +HELP-ALL: --output-file= - Redirect output to the specified file. +HELP-ALL: --output-folder= - Folder name for view splitting. +HELP-ALL: --output-level= - Only print to a depth of N elements. +HELP-ALL: --output-sort= - Primary key when ordering logical view (default: line). +HELP-ALL: =kind - Sort by element kind. +HELP-ALL: =line - Sort by element line number. +HELP-ALL: =name - Sort by element name. +HELP-ALL: =offset - Sort by element offset. +HELP-ALL: Print Options: +HELP-ALL: These control which elements are printed. +HELP-ALL: --print= - Element to print. +HELP-ALL: =all - All elements. +HELP-ALL: =elements - Instructions, lines, scopes, symbols and types. +HELP-ALL: =instructions - Assembler instructions. +HELP-ALL: =lines - Lines referenced in the debug information. +HELP-ALL: =scopes - A lexical block (Function, Class, etc.). +HELP-ALL: =sizes - Scope contributions to the debug information. +HELP-ALL: =summary - Summary of elements missing/added/matched/printed. +HELP-ALL: =symbols - Symbols (Variable, Members, etc.). +HELP-ALL: =types - Types (Pointer, Reference, etc.). +HELP-ALL: =warnings - Warnings detected. +HELP-ALL: Report Options: +HELP-ALL: These control how the elements are printed. +HELP-ALL: --report= - Reports layout used for print, compare and select. +HELP-ALL: =all - Generate all reports. +HELP-ALL: =children - Selected elements are displayed in a tree View (Include children) +HELP-ALL: =list - Selected elements are displayed in a tabular format. +HELP-ALL: =parents - Selected elements are displayed in a tree view. (Include parents) +HELP-ALL: =view - Selected elements are displayed in a tree View (Include parents and children. +HELP-ALL: Select Options: +HELP-ALL: These control which elements are selected. +HELP-ALL: --select= - Search elements matching the given pattern. +HELP-ALL: --select-elements= - Conditions to use when printing elements. +HELP-ALL: =Discarded - Discarded elements by the linker. +HELP-ALL: =Global - Element referenced across Compile Units. +HELP-ALL: =Optimized - Generated inlined abstract references. +HELP-ALL: --select-lines= - Line kind to use when printing lines. +HELP-ALL: =AlwaysStepInto - Always Step Into. +HELP-ALL: =BasicBlock - Basic block. +HELP-ALL: =Discriminator - Discriminator. +HELP-ALL: =EndSequence - End sequence. +HELP-ALL: =EpilogueBegin. - Epilogue begin. +HELP-ALL: =LineDebug - Debug line. +HELP-ALL: =LineAssembler - Assembler line. +HELP-ALL: =NeverStepInto - Never Step Into. +HELP-ALL: =NewStatement - New statement. +HELP-ALL: =PrologueEnd - Prologue end. +HELP-ALL: --select-nocase - Ignore case distinctions when searching. +HELP-ALL: --select-offsets= - Offset element to print. +HELP-ALL: --select-regex - Treat any strings as regular expressions when selecting instead of just as an exact string match. +HELP-ALL: --select-scopes= - Scope kind to use when printing scopes. +HELP-ALL: =Aggregate - Class, Structure or Union. +HELP-ALL: =Array - Array. +HELP-ALL: =Block - Lexical block. +HELP-ALL: =CallSite - Call site block. +HELP-ALL: =CatchBlock - Exception catch block. +HELP-ALL: =Class - Class. +HELP-ALL: =CompileUnit - Compile unit. +HELP-ALL: =EntryPoint - Function entry point. +HELP-ALL: =Enumeration - Enumeration. +HELP-ALL: =Function - Function. +HELP-ALL: =FunctionType - Function type. +HELP-ALL: =InlinedFunction - Inlined function. +HELP-ALL: =Label - Label. +HELP-ALL: =LexicalBlock - Lexical block. +HELP-ALL: =Namespace - Namespace. +HELP-ALL: =Root - Root. +HELP-ALL: =Structure - Structure. +HELP-ALL: =Subprogram - Subprogram. +HELP-ALL: =Template - Template. +HELP-ALL: =TemplateAlias - Template alias. +HELP-ALL: =TemplatePack - Template pack. +HELP-ALL: =TryBlock - Exception try block. +HELP-ALL: =Union - Union. +HELP-ALL: --select-symbols= - Symbol kind to use when printing symbols. +HELP-ALL: =CallSiteParameter - Call site parameter. +HELP-ALL: =Constant - Constant. +HELP-ALL: =Inheritance - Inheritance. +HELP-ALL: =Member - Member. +HELP-ALL: =Parameter - Parameter. +HELP-ALL: =Unspecified - Unspecified parameter. +HELP-ALL: =Variable - Variable. +HELP-ALL: --select-types= - Type kind to use when printing types. +HELP-ALL: =Base - Base Type (int, bool, etc.). +HELP-ALL: =Const - Constant specifier. +HELP-ALL: =Enumerator - Enumerator. +HELP-ALL: =Import - Import declaration. +HELP-ALL: =ImportDeclaration - Import declaration. +HELP-ALL: =ImportModule - Import module. +HELP-ALL: =Pointer - Pointer. +HELP-ALL: =PointerMember - Pointer to member. +HELP-ALL: =Reference - Reference type. +HELP-ALL: =Restrict - Restrict specifier. +HELP-ALL: =RvalueReference - Rvalue reference. +HELP-ALL: =Subrange - Array subrange. +HELP-ALL: =TemplateParam - Template Parameter. +HELP-ALL: =TemplateTemplateParam - Template template parameter. +HELP-ALL: =TemplateTypeParam - Template type parameter. +HELP-ALL: =TemplateValueParam - Template value parameter. +HELP-ALL: =Typedef - Type definition. +HELP-ALL: =Unspecified - Unspecified type. +HELP-ALL: =Volatile - Volatile specifier. +HELP-ALL: Warning Options: +HELP-ALL: These control the generated warnings. +HELP-ALL: --warning= - Warnings to generate. +HELP-ALL: =all - All warnings. +HELP-ALL: =coverages - Invalid symbol coverages values. +HELP-ALL: =lines - Debug lines that are zero. +HELP-ALL: =locations - Invalid symbol locations. +HELP-ALL: =ranges - Invalid code ranges. +HELP-ALL: Pass @FILE as argument to read options from FILE. Index: llvm/tools/llvm-dva/CMakeLists.txt =================================================================== --- /dev/null +++ llvm/tools/llvm-dva/CMakeLists.txt @@ -0,0 +1,19 @@ +set(LLVM_LINK_COMPONENTS + AllTargetsDescs + AllTargetsInfos + AllTargetsDisassemblers + BinaryFormat + DebugInfoLogicalView + DebugInfoCodeView + DebugInfoDWARF + DebugInfoPDB + MC + MCDisassembler + Object + Support + ) + +add_llvm_tool(llvm-dva + llvm-dva.cpp + Options.cpp + ) Index: llvm/tools/llvm-dva/LLVMBuild.txt =================================================================== --- /dev/null +++ llvm/tools/llvm-dva/LLVMBuild.txt @@ -0,0 +1,21 @@ +;===- ./tools/llvm-dva/LLVMBuild.txt ---------------------------*- Conf -*--===; +; +; Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +; See https://llvm.org/LICENSE.txt for license information. +; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Tool +name = llvm-dva +parent = Tools +required_libraries = DebugInfoLogicalView DebugInfoDWARF DebugInfoCodeView DebugInfoPDB Object Index: llvm/tools/llvm-dva/Options.h =================================================================== --- /dev/null +++ llvm/tools/llvm-dva/Options.h @@ -0,0 +1,81 @@ +//===-- Options.h -----------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines command line options used by llvm-dva. +// +//===----------------------------------------------------------------------===// + +#ifndef OPTIONS_H +#define OPTIONS_H + +#include "llvm/DebugInfo/LogicalView/Core/LVLine.h" +#include "llvm/DebugInfo/LogicalView/Core/LVOptions.h" +#include "llvm/DebugInfo/LogicalView/Core/LVScope.h" +#include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h" +#include "llvm/DebugInfo/LogicalView/Core/LVType.h" +#include "llvm/Support/CommandLine.h" + +namespace llvm { +namespace logicalview { +namespace cmdline { + +class OffsetParser : public llvm::cl::parser { +public: + OffsetParser(llvm::cl::Option &O); + ~OffsetParser() override; + + // Parse an argument representing an offset. Return true on error. + // If the prefix is 0, the base is octal, if the prefix is 0x or 0X, the + // base is hexadecimal, otherwise the base is decimal. + bool parse(llvm::cl::Option &O, StringRef ArgName, StringRef ArgValue, + unsigned long long &Val); +}; + +typedef llvm::cl::list OffsetOptionList; + +extern llvm::cl::OptionCategory AttributeCategory; +extern llvm::cl::OptionCategory CompareCategory; +extern llvm::cl::OptionCategory OutputCategory; +extern llvm::cl::OptionCategory PrintCategory; +extern llvm::cl::OptionCategory ReportCategory; +extern llvm::cl::OptionCategory SelectCategory; +extern llvm::cl::OptionCategory WarningCategory; +extern llvm::cl::OptionCategory InternalCategory; + +extern llvm::cl::list InputFilenames; +extern llvm::cl::opt OutputFilename; + +extern llvm::cl::list SelectPatterns; + +extern llvm::cl::list SelectElements; +extern llvm::cl::list SelectLines; +extern llvm::cl::list SelectScopes; +extern llvm::cl::list SelectSymbols; +extern llvm::cl::list SelectTypes; +extern OffsetOptionList SelectOffsets; + +extern llvm::cl::list AttributeOptions; +extern llvm::cl::list OutputOptions; +extern llvm::cl::list PrintOptions; +extern llvm::cl::list WarningOptions; +extern llvm::cl::list InternalOptions; + +extern llvm::cl::list CompareElements; +extern llvm::cl::list ReportOptions; + +extern LVOptions ReaderOptions; + +// Perform any additional post parse command line actions. Propagate the +// values captured by the command line parser, into the generic reader. +void propagateOptions(); + +} // namespace cmdline +} // namespace logicalview +} // namespace llvm + +#endif // OPTIONS_H Index: llvm/tools/llvm-dva/Options.cpp =================================================================== --- /dev/null +++ llvm/tools/llvm-dva/Options.cpp @@ -0,0 +1,501 @@ +//===-- options.cpp - Command line options for llvm-dva -------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This handles the command line options for llvm-dva. +// +//===----------------------------------------------------------------------===// + +#include "Options.h" +#include "llvm/DebugInfo/LogicalView/Core/LVOptions.h" +#include "llvm/DebugInfo/LogicalView/Core/LVSort.h" +#include "llvm/Support/CommandLine.h" + +using namespace llvm; +using namespace llvm::logicalview; +using namespace llvm::logicalview::cmdline; + +/// @} +/// Command line options. +/// @{ + +OffsetParser::OffsetParser(cl::Option &O) : parser(O) {} +OffsetParser::~OffsetParser() = default; + +bool OffsetParser::parse(cl::Option &O, StringRef ArgName, StringRef Arg, + unsigned long long &Val) { + char *End; + std::string Argument(Arg); + Val = strtoull(Argument.c_str(), &End, 0); + if (*End) + // Print an error message if unrecognized character. + return O.error("'" + Arg + "' unrecognized character."); + return false; +} + +LVOptions cmdline::ReaderOptions; + +//===----------------------------------------------------------------------===// +// Specific options +//===----------------------------------------------------------------------===// +cl::list + cmdline::InputFilenames(cl::desc(""), + cl::Positional, cl::ZeroOrMore); + +//===----------------------------------------------------------------------===// +// '--attribute' options +//===----------------------------------------------------------------------===// +cl::OptionCategory + cmdline::AttributeCategory("Attribute Options", + "These control extra attributes that are " + "added when the element is printed."); + +// --attribute=[,,...] +cl::list cmdline::AttributeOptions( + "attribute", cl::cat(AttributeCategory), cl::desc("Element attributes."), + cl::Hidden, cl::CommaSeparated, + values(clEnumValN(LVAttributeKind::All, "all", "Include all attributes."), + clEnumValN(LVAttributeKind::Argument, "argument", + "Template parameters replaced by its arguments."), + clEnumValN(LVAttributeKind::Base, "base", + "Base types (int, bool, etc.)."), + clEnumValN(LVAttributeKind::Coverage, "coverage", + "Symbol location coverage."), + clEnumValN(LVAttributeKind::Directories, "directories", + "Directories referenced in the debug information."), + clEnumValN(LVAttributeKind::Discarded, "discarded", + "Discarded elements by the linker."), + clEnumValN(LVAttributeKind::Discriminator, "discriminator", + "Discriminators for inlined function instances."), + clEnumValN(LVAttributeKind::Encoded, "encoded", + "Template arguments encoded in the template name."), + clEnumValN(LVAttributeKind::Extended, "extended", + "Advanced attributes alias."), + clEnumValN(LVAttributeKind::Filename, "filename", + "Filename where the element is defined."), + clEnumValN(LVAttributeKind::Files, "files", + "Files referenced in the debug information."), + clEnumValN(LVAttributeKind::Format, "format", + "Objet file format name."), + clEnumValN(LVAttributeKind::Gaps, "gaps", + "Missing debug location (gaps)."), + clEnumValN(LVAttributeKind::Generated, "generated", + "Compiler generated elements."), + clEnumValN(LVAttributeKind::Global, "global", + "Element referenced across Compile Units."), + clEnumValN(LVAttributeKind::Inserted, "inserted", + "Generated inlined abstract references."), + clEnumValN(LVAttributeKind::Level, "level", + "Lexical scope level (File=0, Compile Unit=1)."), + clEnumValN(LVAttributeKind::Linkage, "linkage", "Linkage name."), + clEnumValN(LVAttributeKind::Local, "local", + "Element referenced only in the Compile Unit."), + clEnumValN(LVAttributeKind::Location, "location", + "Element debug location."), + clEnumValN(LVAttributeKind::Offset, "offset", + "Debug information offset."), + clEnumValN(LVAttributeKind::Pathname, "pathname", + "Pathname where the element is defined."), + clEnumValN(LVAttributeKind::Producer, "producer", + "Toolchain identification name."), + clEnumValN(LVAttributeKind::Publics, "publics", + "Function names that are public."), + clEnumValN(LVAttributeKind::Qualified, "qualified", + "The element type include parents in its name."), + clEnumValN(LVAttributeKind::Qualifier, "qualifier", + "Line qualifiers (Newstatement, BasicBlock, etc.)."), + clEnumValN(LVAttributeKind::Range, "range", + "Debug location ranges."), + clEnumValN(LVAttributeKind::Reference, "reference", + "Element declaration and definition references."), + clEnumValN(LVAttributeKind::Register, "register", + "Processor register names."), + clEnumValN(LVAttributeKind::Standard, "standard", + "Basic attributes alias."), + clEnumValN(LVAttributeKind::Subrange, "subrange", + "Subrange encoding information for arrays."), + clEnumValN(LVAttributeKind::System, "system", + "Display PDB's MS system elements."), + clEnumValN(LVAttributeKind::Typename, "typename", + "Include Parameters in templates."), + clEnumValN(LVAttributeKind::Underlying, "underlying", + "Underlying type for type definitions."), + clEnumValN(LVAttributeKind::Zero, "zero", "Zero line numbers."))); + +//===----------------------------------------------------------------------===// +// '--compare' options +//===----------------------------------------------------------------------===// +cl::OptionCategory + cmdline::CompareCategory("Compare Options", + "These control the view comparison."); + +// --compare-context +static cl::opt + CompareContext("compare-context", cl::cat(CompareCategory), + cl::desc("Add the View as compare context."), cl::Hidden, + cl::ZeroOrMore, cl::location(ReaderOptions.Compare.Context), + cl::init(false)); + +// --compare=[,,...] +cl::list cmdline::CompareElements( + "compare", cl::cat(CompareCategory), cl::desc("Elements to compare."), + cl::Hidden, cl::CommaSeparated, + values(clEnumValN(LVCompareKind::All, "all", "Compare all elements."), + clEnumValN(LVCompareKind::Lines, "lines", "Lines."), + clEnumValN(LVCompareKind::Scopes, "scopes", "Scopes."), + clEnumValN(LVCompareKind::Symbols, "symbols", "Symbols."), + clEnumValN(LVCompareKind::Types, "types", "Types."))); + +//===----------------------------------------------------------------------===// +// '--output' options +//===----------------------------------------------------------------------===// +cl::OptionCategory + cmdline::OutputCategory("Output Options", + "These control the output generated."); + +// --output-file= +cl::opt + cmdline::OutputFilename("output-file", cl::cat(OutputCategory), + cl::desc("Redirect output to the specified file."), + cl::Hidden, cl::value_desc("filename"), + cl::init("-")); + +// --output-folder= +static cl::opt + OutputFolder("output-folder", cl::cat(OutputCategory), + cl::desc("Folder name for view splitting."), + cl::value_desc("pathname"), cl::Hidden, cl::ZeroOrMore, + cl::location(ReaderOptions.Output.Folder)); + +// --output-level= +static cl::opt + OutputLevel("output-level", cl::cat(OutputCategory), + cl::desc("Only print to a depth of N elements."), + cl::value_desc("N"), cl::Hidden, cl::ZeroOrMore, + cl::location(ReaderOptions.Output.Level), cl::init(-1U)); + +// --ouput=[,,...] +cl::list cmdline::OutputOptions( + "output", cl::cat(OutputCategory), cl::desc("Outputs for view."), + cl::Hidden, cl::CommaSeparated, + values(clEnumValN(LVOutputKind::All, "all", "All outputs."), + clEnumValN(LVOutputKind::Split, "split", + "Split the output by Compile Units."), + clEnumValN(LVOutputKind::Text, "text", + "Use a free form text output."), + clEnumValN(LVOutputKind::Json, "json", + "Use JSON as the output format."))); + +// --output-sort +static cl::opt OutputSort( + "output-sort", cl::cat(OutputCategory), + cl::desc("Primary key when ordering logical view (default: line)."), + cl::Hidden, cl::ZeroOrMore, + values(clEnumValN(LVSortMode::Kind, "kind", "Sort by element kind."), + clEnumValN(LVSortMode::Line, "line", "Sort by element line number."), + clEnumValN(LVSortMode::Name, "name", "Sort by element name."), + clEnumValN(LVSortMode::Offset, "offset", "Sort by element offset.")), + cl::location(ReaderOptions.Output.SortMode), cl::init(LVSortMode::Line)); + +//===----------------------------------------------------------------------===// +// '--print' options +//===----------------------------------------------------------------------===// +cl::OptionCategory + cmdline::PrintCategory("Print Options", + "These control which elements are printed."); + +// --print=[,,...] +cl::list cmdline::PrintOptions( + "print", cl::cat(PrintCategory), cl::desc("Element to print."), + cl::CommaSeparated, + values(clEnumValN(LVPrintKind::All, "all", "All elements."), + clEnumValN(LVPrintKind::Elements, "elements", + "Instructions, lines, scopes, symbols and types."), + clEnumValN(LVPrintKind::Instructions, "instructions", + "Assembler instructions."), + clEnumValN(LVPrintKind::Lines, "lines", + "Lines referenced in the debug information."), + clEnumValN(LVPrintKind::Scopes, "scopes", + "A lexical block (Function, Class, etc.)."), + clEnumValN(LVPrintKind::Sizes, "sizes", + "Scope contributions to the debug information."), + clEnumValN(LVPrintKind::Summary, "summary", + "Summary of elements missing/added/matched/printed."), + clEnumValN(LVPrintKind::Symbols, "symbols", + "Symbols (Variable, Members, etc.)."), + clEnumValN(LVPrintKind::Types, "types", + "Types (Pointer, Reference, etc.)."), + clEnumValN(LVPrintKind::Warnings, "warnings", + "Warnings detected."))); + +//===----------------------------------------------------------------------===// +// '--report' options +//===----------------------------------------------------------------------===// +cl::OptionCategory + cmdline::ReportCategory("Report Options", + "These control how the elements are printed."); + +// --report=[,,...] +cl::list cmdline::ReportOptions( + "report", cl::cat(ReportCategory), + cl::desc("Reports layout used for print, compare and select."), cl::Hidden, + cl::CommaSeparated, + values(clEnumValN(LVReportKind::All, "all", "Generate all reports."), + clEnumValN(LVReportKind::Children, "children", + "Selected elements are displayed in a tree View " + "(Include children)"), + clEnumValN(LVReportKind::List, "list", + "Selected elements are displayed in a tabular format."), + clEnumValN(LVReportKind::Parents, "parents", + "Selected elements are displayed in a tree view. " + "(Include parents)"), + clEnumValN(LVReportKind::View, "view", + "Selected elements are displayed in a tree View " + "(Include parents and children."))); + +//===----------------------------------------------------------------------===// +// '--select' options +//===----------------------------------------------------------------------===// +cl::OptionCategory + cmdline::SelectCategory("Select Options", + "These control which elements are selected."); + +// --select-nocase +static cl::opt + SelectIgnoreCase("select-nocase", cl::cat(SelectCategory), + cl::desc("Ignore case distinctions when searching."), + cl::Hidden, cl::ZeroOrMore, + cl::location(ReaderOptions.Select.IgnoreCase), + cl::init(false)); + +// --select-regex +static cl::opt SelectUseRegex( + "select-regex", cl::cat(SelectCategory), + cl::desc("Treat any strings as regular expressions when " + "selecting instead of just as an exact string match."), + cl::Hidden, cl::ZeroOrMore, cl::location(ReaderOptions.Select.UseRegex), + cl::init(false)); + +// --select= +cl::list cmdline::SelectPatterns( + "select", cl::cat(SelectCategory), + cl::desc("Search elements matching the given pattern."), cl::Hidden, + cl::value_desc("pattern"), cl::CommaSeparated); + +// --select-offsets=[,,...] +OffsetOptionList cmdline::SelectOffsets("select-offsets", + cl::cat(SelectCategory), + cl::desc("Offset element to print."), + cl::Hidden, cl::value_desc("offset"), + cl::CommaSeparated, cl::ZeroOrMore); + +// --select-elements=[,,...] +cl::list cmdline::SelectElements( + "select-elements", cl::cat(SelectCategory), + cl::desc("Conditions to use when printing elements."), cl::Hidden, + cl::CommaSeparated, + values(clEnumValN(LVElementKind::Discarded, "Discarded", + "Discarded elements by the linker."), + clEnumValN(LVElementKind::Global, "Global", + "Element referenced across Compile Units."), + clEnumValN(LVElementKind::Optimized, "Optimized", + "Generated inlined abstract references."))); + +// --select-lines=[,,...] +cl::list cmdline::SelectLines( + "select-lines", cl::cat(SelectCategory), + cl::desc("Line kind to use when printing lines."), cl::Hidden, + cl::CommaSeparated, + values( + clEnumValN(LVLineKind::IsAlwaysStepInto, "AlwaysStepInto", + "Always Step Into."), + clEnumValN(LVLineKind::IsBasicBlock, "BasicBlock", "Basic block."), + clEnumValN(LVLineKind::IsDiscriminator, "Discriminator", + "Discriminator."), + clEnumValN(LVLineKind::IsEndSequence, "EndSequence", "End sequence."), + clEnumValN(LVLineKind::IsEpilogueBegin, "EpilogueBegin.", + "Epilogue begin."), + clEnumValN(LVLineKind::IsLineDebug, "LineDebug", "Debug line."), + clEnumValN(LVLineKind::IsLineAssembler, "LineAssembler", + "Assembler line."), + clEnumValN(LVLineKind::IsNeverStepInto, "NeverStepInto", + "Never Step Into."), + clEnumValN(LVLineKind::IsNewStatement, "NewStatement", + "New statement."), + clEnumValN(LVLineKind::IsPrologueEnd, "PrologueEnd", "Prologue end."))); + +// --select-scopes=[,,...] +cl::list cmdline::SelectScopes( + "select-scopes", cl::cat(SelectCategory), + cl::desc("Scope kind to use when printing scopes."), cl::Hidden, + cl::CommaSeparated, + values( + clEnumValN(LVScopeKind::IsAggregate, "Aggregate", + "Class, Structure or Union."), + clEnumValN(LVScopeKind::IsArray, "Array", "Array."), + clEnumValN(LVScopeKind::IsBlock, "Block", "Lexical block."), + clEnumValN(LVScopeKind::IsCallSite, "CallSite", "Call site block."), + clEnumValN(LVScopeKind::IsCatchBlock, "CatchBlock", + "Exception catch block."), + clEnumValN(LVScopeKind::IsClass, "Class", "Class."), + clEnumValN(LVScopeKind::IsCompileUnit, "CompileUnit", "Compile unit."), + clEnumValN(LVScopeKind::IsEntryPoint, "EntryPoint", + "Function entry point."), + clEnumValN(LVScopeKind::IsEnumeration, "Enumeration", "Enumeration."), + clEnumValN(LVScopeKind::IsFunction, "Function", "Function."), + clEnumValN(LVScopeKind::IsFunctionType, "FunctionType", + "Function type."), + clEnumValN(LVScopeKind::IsInlinedFunction, "InlinedFunction", + "Inlined function."), + clEnumValN(LVScopeKind::IsLabel, "Label", "Label."), + clEnumValN(LVScopeKind::IsLexicalBlock, "LexicalBlock", + "Lexical block."), + clEnumValN(LVScopeKind::IsNamespace, "Namespace", "Namespace."), + clEnumValN(LVScopeKind::IsRoot, "Root", "Root."), + clEnumValN(LVScopeKind::IsStructure, "Structure", "Structure."), + clEnumValN(LVScopeKind::IsSubprogram, "Subprogram", "Subprogram."), + clEnumValN(LVScopeKind::IsTemplate, "Template", "Template."), + clEnumValN(LVScopeKind::IsTemplateAlias, "TemplateAlias", + "Template alias."), + clEnumValN(LVScopeKind::IsTemplatePack, "TemplatePack", + "Template pack."), + clEnumValN(LVScopeKind::IsTryBlock, "TryBlock", "Exception try block."), + clEnumValN(LVScopeKind::IsUnion, "Union", "Union."))); + +// --select-symbols=[,,...] +cl::list cmdline::SelectSymbols( + "select-symbols", cl::cat(SelectCategory), + cl::desc("Symbol kind to use when printing symbols."), cl::Hidden, + cl::CommaSeparated, + values(clEnumValN(LVSymbolKind::IsCallSiteParameter, "CallSiteParameter", + "Call site parameter."), + clEnumValN(LVSymbolKind::IsConstant, "Constant", "Constant."), + clEnumValN(LVSymbolKind::IsInheritance, "Inheritance", + "Inheritance."), + clEnumValN(LVSymbolKind::IsMember, "Member", "Member."), + clEnumValN(LVSymbolKind::IsParameter, "Parameter", "Parameter."), + clEnumValN(LVSymbolKind::IsUnspecified, "Unspecified", + "Unspecified parameter."), + clEnumValN(LVSymbolKind::IsVariable, "Variable", "Variable."))); + +// --select-types=[,,...] +cl::list cmdline::SelectTypes( + "select-types", cl::cat(SelectCategory), + cl::desc("Type kind to use when printing types."), cl::Hidden, + cl::CommaSeparated, + values( + clEnumValN(LVTypeKind::IsBase, "Base", "Base Type (int, bool, etc.)."), + clEnumValN(LVTypeKind::IsConst, "Const", "Constant specifier."), + clEnumValN(LVTypeKind::IsEnumerator, "Enumerator", "Enumerator."), + clEnumValN(LVTypeKind::IsImport, "Import", "Import declaration."), + clEnumValN(LVTypeKind::IsImportDeclaration, "ImportDeclaration", + "Import declaration."), + clEnumValN(LVTypeKind::IsImportModule, "ImportModule", + "Import module."), + clEnumValN(LVTypeKind::IsPointer, "Pointer", "Pointer."), + clEnumValN(LVTypeKind::IsPointerMember, "PointerMember", + "Pointer to member."), + clEnumValN(LVTypeKind::IsReference, "Reference", "Reference type."), + clEnumValN(LVTypeKind::IsRestrict, "Restrict", "Restrict specifier."), + clEnumValN(LVTypeKind::IsRvalueReference, "RvalueReference", + "Rvalue reference."), + clEnumValN(LVTypeKind::IsSubrange, "Subrange", "Array subrange."), + clEnumValN(LVTypeKind::IsTemplateParam, "TemplateParam", + "Template Parameter."), + clEnumValN(LVTypeKind::IsTemplateTemplateParam, "TemplateTemplateParam", + "Template template parameter."), + clEnumValN(LVTypeKind::IsTemplateTypeParam, "TemplateTypeParam", + "Template type parameter."), + clEnumValN(LVTypeKind::IsTemplateValueParam, "TemplateValueParam", + "Template value parameter."), + clEnumValN(LVTypeKind::IsTypedef, "Typedef", "Type definition."), + clEnumValN(LVTypeKind::IsUnspecified, "Unspecified", + "Unspecified type."), + clEnumValN(LVTypeKind::IsVolatile, "Volatile", "Volatile specifier."))); + +//===----------------------------------------------------------------------===// +// '--warning' options +//===----------------------------------------------------------------------===// +cl::OptionCategory + cmdline::WarningCategory("Warning Options", + "These control the generated warnings."); + +// --warning=[,,...] +cl::list cmdline::WarningOptions( + "warning", cl::cat(WarningCategory), cl::desc("Warnings to generate."), + cl::Hidden, cl::CommaSeparated, + values( + clEnumValN(LVWarningKind::All, "all", "All warnings."), + clEnumValN(LVWarningKind::Coverages, "coverages", + "Invalid symbol coverages values."), + clEnumValN(LVWarningKind::Lines, "lines", "Debug lines that are zero."), + clEnumValN(LVWarningKind::Locations, "locations", + "Invalid symbol locations."), + clEnumValN(LVWarningKind::Ranges, "ranges", "Invalid code ranges."))); + +//===----------------------------------------------------------------------===// +// '--internal' options +//===----------------------------------------------------------------------===// +cl::OptionCategory + cmdline::InternalCategory("Internal Options", + "Internal traces and extra debugging code."); + +// --internal=[,,...] +cl::list cmdline::InternalOptions( + "internal", cl::cat(InternalCategory), cl::desc("Traces to enable."), + cl::Hidden, cl::CommaSeparated, + values( + clEnumValN(LVInternalKind::All, "all", "Enable all traces."), + clEnumValN(LVInternalKind::Cmdline, "cmdline", "Print command line."), + clEnumValN(LVInternalKind::ID, "id", "Print unique element ID"), + clEnumValN(LVInternalKind::Integrity, "integrity", + "Check elements integrity."), + clEnumValN(LVInternalKind::None, "none", "Ignore element line number."), + clEnumValN(LVInternalKind::Tag, "tag", "Debug information tags."))); + +/// @} + +// Copy local options into a globally accessible data structure. +void llvm::logicalview::cmdline::propagateOptions() { + // Traverse list of options and update the given set (Using case and Regex). + auto updatePattern = [&](auto &List, auto &Set, bool &Case, bool &Regex) { + if (!List.empty()) + for (std::string &Pattern : List) + Set.insert((Case && !Regex) ? StringRef(Pattern).lower() : Pattern); + }; + + // Handle --select. + updatePattern(SelectPatterns, ReaderOptions.Select.Generic, + ReaderOptions.Select.IgnoreCase, ReaderOptions.Select.UseRegex); + + // Traverse list of options and update the given set. + auto updateSet = [&](auto &List, auto &Set) { + if (!List.empty()) + for (auto &Kind : List) + Set.insert(Kind); + }; + + // Handle options sets. + updateSet(AttributeOptions, ReaderOptions.Attribute.Kinds); + updateSet(PrintOptions, ReaderOptions.Print.Kinds); + updateSet(OutputOptions, ReaderOptions.Output.Kinds); + updateSet(ReportOptions, ReaderOptions.Report.Kinds); + updateSet(WarningOptions, ReaderOptions.Warning.Kinds); + updateSet(InternalOptions, ReaderOptions.Internal.Kinds); + + updateSet(SelectElements, ReaderOptions.Select.Elements); + updateSet(SelectLines, ReaderOptions.Select.Lines); + updateSet(SelectScopes, ReaderOptions.Select.Scopes); + updateSet(SelectSymbols, ReaderOptions.Select.Symbols); + updateSet(SelectTypes, ReaderOptions.Select.Types); + updateSet(SelectOffsets, ReaderOptions.Select.Offsets); + updateSet(CompareElements, ReaderOptions.Compare.Elements); + + // Resolve any options dependencies (ie. --print=all should set other + // print options, etc.). + ReaderOptions.resolveDependencies(); +} Index: llvm/tools/llvm-dva/llvm-dva.cpp =================================================================== --- /dev/null +++ llvm/tools/llvm-dva/llvm-dva.cpp @@ -0,0 +1,127 @@ +//===-- llvm-dva.cpp - Debug info analysis utility for llvm ---------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This program is a utility that display the logical view for the debug +// information. +// +//===----------------------------------------------------------------------===// + +#include "Options.h" +#include "llvm/DebugInfo/LogicalView/Core/LVOptions.h" +#include "llvm/Object/Archive.h" +#include "llvm/Support/COM.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/InitLLVM.h" +#include "llvm/Support/ScopedPrinter.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Support/ToolOutputFile.h" +#include "llvm/Support/WithColor.h" + +using namespace llvm; +using namespace logicalview; +using namespace cmdline; + +/// Create formatted StringError object. +static StringRef ToolName = "llvm-dva"; +template +static void error(std::error_code EC, char const *Fmt, const Ts &...Vals) { + if (!EC) + return; + std::string Buffer; + raw_string_ostream Stream(Buffer); + Stream << format(Fmt, Vals...); + WithColor::error(errs(), ToolName) << Stream.str() << "\n"; + exit(1); +} + +/// If the input path is a .dSYM bundle (as created by the dsymutil tool), +/// replace it with individual entries for each of the object files inside the +/// bundle otherwise return the input path. +static std::vector expandBundle(const std::string &InputPath) { + std::vector BundlePaths; + SmallString<256> BundlePath(InputPath); + // Normalize input path. This is necessary to accept `bundle.dSYM/`. + sys::path::remove_dots(BundlePath); + // Manually open up the bundle to avoid introducing additional dependencies. + if (sys::fs::is_directory(BundlePath) && + sys::path::extension(BundlePath) == ".dSYM") { + std::error_code EC; + sys::path::append(BundlePath, "Contents", "Resources", "DWARF"); + for (sys::fs::directory_iterator Dir(BundlePath, EC), DirEnd; + Dir != DirEnd && !EC; Dir.increment(EC)) { + const std::string &Path = Dir->path(); + sys::fs::file_status Status; + EC = sys::fs::status(Path, Status); + error(EC, "%s", Path.c_str()); + switch (Status.type()) { + case sys::fs::file_type::regular_file: + case sys::fs::file_type::symlink_file: + case sys::fs::file_type::type_unknown: + BundlePaths.push_back(Path); + break; + default: /*ignore*/; + } + } + } + if (!BundlePaths.size()) + BundlePaths.push_back(InputPath); + return BundlePaths; +} + +int main(int argc, char **argv) { + InitLLVM X(argc, argv); + + // Initialize targets and assembly printers/parsers. + llvm::InitializeAllTargetInfos(); + llvm::InitializeAllTargetMCs(); + InitializeAllDisassemblers(); + + llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::MultiThreaded); + + cl::extrahelp HelpResponse( + "\nPass @FILE as argument to read options from FILE.\n"); + + cl::HideUnrelatedOptions( + {&AttributeCategory, &CompareCategory, &InternalCategory, &OutputCategory, + &PrintCategory, &ReportCategory, &SelectCategory, &WarningCategory}); + cl::ParseCommandLineOptions(argc, argv, + "Printing a logical representation of low-level " + "debug information.\n"); + cl::PrintOptionValues(); + + std::error_code EC; + ToolOutputFile OutputFile(OutputFilename, EC, sys::fs::OF_None); + error(EC, "Unable to open output file %s", OutputFilename.c_str()); + // Don't remove output file if we exit with an error. + OutputFile.keep(); + + // Defaults to a.out if no filenames specified. + if (InputFilenames.empty()) + InputFilenames.push_back("a.out"); + + // Expand any .dSYM bundles to the individual object files contained therein. + std::vector Objects; + for (const std::string &Filename : InputFilenames) { + std::vector Objs = expandBundle(Filename); + Objects.insert(Objects.end(), Objs.begin(), Objs.end()); + } + + propagateOptions(); + ScopedPrinter W(OutputFile.os()); + + // Print the command line. + if (options().getInternalCmdline()) { + raw_ostream &Stream = W.getOStream(); + Stream << "\nCommand line:\n"; + for (int Index = 0; Index < argc; ++Index) + Stream << " " << argv[Index] << "\n"; + Stream << "\n"; + } + + return EXIT_SUCCESS; +} Index: llvm/unittests/DebugInfo/CMakeLists.txt =================================================================== --- llvm/unittests/DebugInfo/CMakeLists.txt +++ llvm/unittests/DebugInfo/CMakeLists.txt @@ -1,5 +1,6 @@ add_subdirectory(CodeView) add_subdirectory(DWARF) add_subdirectory(GSYM) +add_subdirectory(LogicalView) add_subdirectory(MSF) add_subdirectory(PDB) Index: llvm/unittests/DebugInfo/LogicalView/CMakeLists.txt =================================================================== --- /dev/null +++ llvm/unittests/DebugInfo/LogicalView/CMakeLists.txt @@ -0,0 +1,10 @@ +set(LLVM_LINK_COMPONENTS + DebugInfoLogicalView + ) + +add_llvm_unittest(DebugInfoLogicalViewTests + CommandLineOptionsTest.cpp + StringPoolTest.cpp + ) + +target_link_libraries(DebugInfoLogicalViewTests PRIVATE LLVMTestingSupport) Index: llvm/unittests/DebugInfo/LogicalView/CommandLineOptionsTest.cpp =================================================================== --- /dev/null +++ llvm/unittests/DebugInfo/LogicalView/CommandLineOptionsTest.cpp @@ -0,0 +1,276 @@ +//===- llvm/unittest/DebugInfo/LogicalView/CommandLineOptionsTest.cpp -----===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/LogicalView/Core/LVOptions.h" + +#include "gtest/gtest.h" + +using namespace llvm; +using namespace llvm::logicalview; + +namespace { + +// '--attribute' options. +TEST(CommandLineOptionsTest, attributeOptions) { + auto checkStandardAttributes = [&](LVOptions &Options, bool Value) { + EXPECT_EQ(Options.getAttributeBase(), 1); + EXPECT_EQ(Options.getAttributeCoverage(), Value); + EXPECT_EQ(Options.getAttributeDirectories(), 1); + EXPECT_EQ(Options.getAttributeDiscriminator(), 1); + EXPECT_EQ(Options.getAttributeFilename(), 0); + EXPECT_EQ(Options.getAttributeFiles(), 1); + EXPECT_EQ(Options.getAttributeFormat(), 1); + EXPECT_EQ(Options.getAttributeLevel(), 1); + EXPECT_EQ(Options.getAttributeProducer(), 1); + EXPECT_EQ(Options.getAttributePublics(), 1); + EXPECT_EQ(Options.getAttributeRange(), 1); + EXPECT_EQ(Options.getAttributeReference(), 1); + EXPECT_EQ(Options.getAttributeZero(), 1); + }; + + auto checkExtendedAttributes = [&](LVOptions &Options, bool Value) { + EXPECT_EQ(Options.getAttributeArgument(), 1); + EXPECT_EQ(Options.getAttributeDiscarded(), 1); + EXPECT_EQ(Options.getAttributeEncoded(), 1); + EXPECT_EQ(Options.getAttributeGaps(), Value); + EXPECT_EQ(Options.getAttributeGenerated(), 1); + EXPECT_EQ(Options.getAttributeGlobal(), 1); + EXPECT_EQ(Options.getAttributeInserted(), 1); + EXPECT_EQ(Options.getAttributeLinkage(), 1); + EXPECT_EQ(Options.getAttributeLocal(), 1); + EXPECT_EQ(Options.getAttributeLocation(), Value); + EXPECT_EQ(Options.getAttributeOffset(), 1); + EXPECT_EQ(Options.getAttributePathname(), 1); + EXPECT_EQ(Options.getAttributeQualified(), 1); + EXPECT_EQ(Options.getAttributeQualifier(), 1); + EXPECT_EQ(Options.getAttributeRegister(), Value); + EXPECT_EQ(Options.getAttributeSubrange(), 1); + EXPECT_EQ(Options.getAttributeSystem(), 1); + EXPECT_EQ(Options.getAttributeTypename(), 1); + }; + + // Location information is only relevant when printing symbols. + // It means the following attributes are dependent on --print=symbols: + // Coverage, gaps, location and register attributes. + // '--attribute=pathname' supersedes '--attribute=filename'. + + // Set standard and extended attributes. + LVOptions OptionsOne; + OptionsOne.setAttributeStandard(); + OptionsOne.setAttributeExtended(); + OptionsOne.resolveDependencies(); + checkStandardAttributes(OptionsOne, false); + checkExtendedAttributes(OptionsOne, false); + + // Set standard and extended attributes; enable location attributes. + LVOptions OptionsTwo; + OptionsTwo.setAttributeStandard(); + OptionsTwo.setAttributeExtended(); + OptionsTwo.setPrintSymbols(); + OptionsTwo.resolveDependencies(); + checkStandardAttributes(OptionsTwo, true); + checkExtendedAttributes(OptionsTwo, true); + + // Set all attributes. + LVOptions OptionsThree; + OptionsThree.setAttributeAll(); + OptionsThree.resolveDependencies(); + EXPECT_EQ(OptionsThree.getAttributeExtended(), 1); + EXPECT_EQ(OptionsThree.getAttributeStandard(), 1); + + // Set filename attribute. + LVOptions OptionsFour; + OptionsFour.setAttributeFilename(); + OptionsFour.resolveDependencies(); + EXPECT_EQ(OptionsFour.getAttributeFilename(), 1); + EXPECT_EQ(OptionsFour.getAttributePathname(), 0); + + // Set pathname attribute. + OptionsFour.setAttributePathname(); + OptionsFour.resolveDependencies(); + EXPECT_EQ(OptionsFour.getAttributeFilename(), 0); + EXPECT_EQ(OptionsFour.getAttributePathname(), 1); + + // The location attribute depends on: coverage, gaps or register. + LVOptions OptionsFive; + OptionsFive.setPrintSymbols(); + OptionsFive.resetAttributeLocation(); + OptionsFive.resolveDependencies(); + EXPECT_EQ(OptionsFive.getAttributeLocation(), 0); + + OptionsFive.resetAttributeLocation(); + OptionsFive.setAttributeCoverage(); + OptionsFive.resolveDependencies(); + EXPECT_EQ(OptionsFive.getAttributeLocation(), 1); + + OptionsFive.resetAttributeLocation(); + OptionsFive.setAttributeGaps(); + OptionsFive.resolveDependencies(); + EXPECT_EQ(OptionsFive.getAttributeLocation(), 1); + + OptionsFive.resetAttributeLocation(); + OptionsFive.setAttributeRegister(); + OptionsFive.resolveDependencies(); + EXPECT_EQ(OptionsFive.getAttributeLocation(), 1); +} + +// '--compare' options. +TEST(CommandLineOptionsTest, compareOptions) { + LVOptions OptionsOne; + OptionsOne.setCompareAll(); + OptionsOne.resolveDependencies(); + EXPECT_EQ(OptionsOne.getCompareLines(), 1); + EXPECT_EQ(OptionsOne.getCompareScopes(), 1); + EXPECT_EQ(OptionsOne.getCompareSymbols(), 1); + EXPECT_EQ(OptionsOne.getCompareTypes(), 1); + + // The compare scopes attribute depends on: symbols, types or lines. + LVOptions OptionsTwo; + OptionsTwo.resetCompareScopes(); + OptionsTwo.resolveDependencies(); + EXPECT_EQ(OptionsTwo.getCompareScopes(), 0); + + OptionsTwo.resetCompareScopes(); + OptionsTwo.setCompareLines(); + OptionsTwo.resolveDependencies(); + EXPECT_EQ(OptionsTwo.getCompareScopes(), 1); + + OptionsTwo.resetCompareScopes(); + OptionsTwo.setCompareSymbols(); + OptionsTwo.resolveDependencies(); + EXPECT_EQ(OptionsTwo.getCompareScopes(), 1); + + OptionsTwo.resetCompareScopes(); + OptionsTwo.setCompareTypes(); + OptionsTwo.resolveDependencies(); + EXPECT_EQ(OptionsTwo.getCompareScopes(), 1); + + // The compare option, set/reset other attributes. + LVOptions OptionsThree; + OptionsThree.setCompareAll(); + OptionsThree.resolveDependencies(); + EXPECT_EQ(OptionsThree.getAttributeArgument(), 1); + EXPECT_EQ(OptionsThree.getAttributeEncoded(), 1); + EXPECT_EQ(OptionsThree.getAttributeInserted(), 1); + EXPECT_EQ(OptionsThree.getAttributeMissing(), 1); + EXPECT_EQ(OptionsThree.getAttributeQualified(), 1); +} + +// '--internal' options. +TEST(CommandLineOptionsTest, internalOptions) { + LVOptions OptionsOne; + OptionsOne.setInternalAll(); + OptionsOne.resolveDependencies(); + EXPECT_EQ(OptionsOne.getInternalCmdline(), 1); + EXPECT_EQ(OptionsOne.getInternalID(), 1); + EXPECT_EQ(OptionsOne.getInternalIntegrity(), 1); + EXPECT_EQ(OptionsOne.getInternalNone(), 1); + EXPECT_EQ(OptionsOne.getInternalTag(), 1); +} + +// '--output' options. +TEST(CommandLineOptionsTest, outputOptions) { + LVOptions OptionsOne; + OptionsOne.setOutputAll(); + OptionsOne.resolveDependencies(); + EXPECT_EQ(OptionsOne.getOutputJson(), 1); + EXPECT_EQ(OptionsOne.getOutputSplit(), 1); + EXPECT_EQ(OptionsOne.getOutputText(), 1); + + // The pathname attribute is set with split output. + LVOptions OptionsTwo; + OptionsTwo.resetAttributePathname(); + OptionsTwo.setOutputSplit(); + OptionsTwo.resolveDependencies(); + EXPECT_EQ(OptionsTwo.getAttributePathname(), 1); + + // Setting an output folder, it sets split option. + LVOptions OptionsThree; + OptionsThree.resolveDependencies(); + EXPECT_EQ(OptionsThree.getOutputSplit(), 0); + + OptionsThree.setOutputFolder("folder-name"); + OptionsThree.resolveDependencies(); + EXPECT_EQ(OptionsThree.getOutputSplit(), 1); + EXPECT_STREQ(OptionsThree.getOutputFolder().c_str(), "folder-name"); + + // Assume '--output=text' as default. + LVOptions OptionsFour; + OptionsFour.resolveDependencies(); + EXPECT_EQ(OptionsFour.getOutputText(), 1); +} + +// '--print' options. +TEST(CommandLineOptionsTest, printOptions) { + LVOptions OptionsOne; + OptionsOne.setPrintAll(); + OptionsOne.resolveDependencies(); + EXPECT_EQ(OptionsOne.getPrintInstructions(), 1); + EXPECT_EQ(OptionsOne.getPrintLines(), 1); + EXPECT_EQ(OptionsOne.getPrintScopes(), 1); + EXPECT_EQ(OptionsOne.getPrintSizes(), 1); + EXPECT_EQ(OptionsOne.getPrintSymbols(), 1); + EXPECT_EQ(OptionsOne.getPrintSummary(), 1); + EXPECT_EQ(OptionsOne.getPrintTypes(), 1); + EXPECT_EQ(OptionsOne.getPrintWarnings(), 1); + + // '--print=elements' is a shortcut for: + // '--print=instructions,lines,scopes,symbols,types'. + LVOptions OptionsTwo; + OptionsTwo.setPrintElements(); + OptionsTwo.resolveDependencies(); + EXPECT_EQ(OptionsTwo.getPrintInstructions(), 1); + EXPECT_EQ(OptionsTwo.getPrintLines(), 1); + EXPECT_EQ(OptionsTwo.getPrintScopes(), 1); + EXPECT_EQ(OptionsTwo.getPrintSizes(), 0); + EXPECT_EQ(OptionsTwo.getPrintSymbols(), 1); + EXPECT_EQ(OptionsTwo.getPrintSummary(), 0); + EXPECT_EQ(OptionsTwo.getPrintTypes(), 1); + EXPECT_EQ(OptionsTwo.getPrintWarnings(), 0); +} + +// '--report' options. +TEST(CommandLineOptionsTest, reportOptions) { + LVOptions OptionsOne; + OptionsOne.setReportAll(); + OptionsOne.resolveDependencies(); + EXPECT_EQ(OptionsOne.getReportChildren(), 1); + EXPECT_EQ(OptionsOne.getReportList(), 1); + EXPECT_EQ(OptionsOne.getReportParents(), 1); + EXPECT_EQ(OptionsOne.getReportView(), 1); + + // '--report=view' is a shortcut for '--report=parents,children'. + LVOptions OptionsTwo; + OptionsTwo.setReportView(); + OptionsTwo.resolveDependencies(); + EXPECT_EQ(OptionsTwo.getReportChildren(), 1); + EXPECT_EQ(OptionsTwo.getReportParents(), 1); +} + +// '--select' options. +TEST(CommandLineOptionsTest, selectOptions) { + LVOptions OptionsOne; + OptionsOne.setSelectIgnoreCase(); + OptionsOne.setSelectUseRegex(); + OptionsOne.resolveDependencies(); + EXPECT_EQ(OptionsOne.getSelectIgnoreCase(), 1); + EXPECT_EQ(OptionsOne.getSelectUseRegex(), 1); +} + +// '--warning' options. +TEST(CommandLineOptionsTest, warningOptions) { + LVOptions OptionsOne; + OptionsOne.setWarningAll(); + OptionsOne.resolveDependencies(); + EXPECT_EQ(OptionsOne.getWarningCoverages(), 1); + EXPECT_EQ(OptionsOne.getWarningLines(), 1); + EXPECT_EQ(OptionsOne.getWarningLocations(), 1); + EXPECT_EQ(OptionsOne.getWarningRanges(), 1); +} + +} // namespace Index: llvm/unittests/DebugInfo/LogicalView/StringPoolTest.cpp =================================================================== --- /dev/null +++ llvm/unittests/DebugInfo/LogicalView/StringPoolTest.cpp @@ -0,0 +1,60 @@ +//===- llvm/unittest/DebugInfo/LogicalView/StringPoolTest.cpp -------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/LogicalView/Core/LVStringPool.h" +#include + +#include "gtest/gtest.h" + +using namespace llvm; +using namespace llvm::logicalview; + +namespace { + +TEST(StringPoolTest, AddStrings) { + LVStringPool PoolInstance; + EXPECT_EQ(0u, PoolInstance.getSize()); + + // Get indexes for the initial strings. + EXPECT_EQ(1u, PoolInstance.getIndex("one")); + EXPECT_EQ(2u, PoolInstance.getIndex("two")); + EXPECT_EQ(3u, PoolInstance.getIndex("three")); + EXPECT_EQ(4u, PoolInstance.getIndex("four")); + EXPECT_EQ(5u, PoolInstance.getIndex("five")); + EXPECT_EQ(5u, PoolInstance.getSize()); + + // Verify the string returned by the given index. + EXPECT_EQ("one", PoolInstance.getString(1)); + EXPECT_EQ("two", PoolInstance.getString(2)); + EXPECT_EQ("three", PoolInstance.getString(3)); + EXPECT_EQ("four", PoolInstance.getString(4)); + EXPECT_EQ("five", PoolInstance.getString(5)); + EXPECT_EQ(5u, PoolInstance.getSize()); + + // Get indexes for the same initial strings. + EXPECT_EQ(5u, PoolInstance.getIndex("five")); + EXPECT_EQ(4u, PoolInstance.getIndex("four")); + EXPECT_EQ(3u, PoolInstance.getIndex("three")); + EXPECT_EQ(2u, PoolInstance.getIndex("two")); + EXPECT_EQ(1u, PoolInstance.getIndex("one")); + EXPECT_EQ(5u, PoolInstance.getSize()); + + // Empty string gets the index zero. + EXPECT_EQ(0u, PoolInstance.getIndex("")); + EXPECT_EQ(5u, PoolInstance.getSize()); + + // Empty string for invalid index. + EXPECT_EQ("", PoolInstance.getString(620)); + + // Lookup for strings + EXPECT_EQ(5u, PoolInstance.findIndex("five")); + EXPECT_TRUE(PoolInstance.isValidIndex(PoolInstance.findIndex("five"))); + EXPECT_FALSE(PoolInstance.isValidIndex(PoolInstance.findIndex("FIVE"))); +} + +} // namespace