mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-27 03:16:07 +00:00

Add support for the WebAssembly binary format and be able to generate logical views. https://github.com/llvm/llvm-project/issues/69181 The README.txt includes information about how to build the test cases.
2273 lines
80 KiB
ReStructuredText
2273 lines
80 KiB
ReStructuredText
llvm-debuginfo-analyzer - Print a logical representation of low-level debug information.
|
|
========================================================================================
|
|
|
|
.. program:: llvm-debuginfo-analyzer
|
|
|
|
.. contents::
|
|
:local:
|
|
|
|
SYNOPSIS
|
|
--------
|
|
:program:`llvm-debuginfo-analyzer` [*options*] [*filename ...*]
|
|
|
|
DESCRIPTION
|
|
-----------
|
|
:program:`llvm-debuginfo-analyzer` 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, Mach-O, WebAssembly, 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-debuginfo-analyzer`
|
|
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-debuginfo-analyzer` 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-debuginfo-analyzer` 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-debuginfo-analyzer` 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:: @<FILE>
|
|
|
|
Read command-line options from `<FILE>`.
|
|
|
|
If no input file is specified, :program:`llvm-debuginfo-analyzer`
|
|
defaults to read `a.out` and return an error when no input file is found.
|
|
|
|
If `-` is used as the input file, :program:`llvm-debuginfo-analyzer`
|
|
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=<value[,value,...]>
|
|
|
|
With **value** being one of 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 when a
|
|
lower level of 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=<value[,value,...]>
|
|
|
|
With **value** being one of 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=<path>
|
|
|
|
Redirect the output to a file specified by <path>, where - is the
|
|
standard output stream.
|
|
|
|
:program:`llvm-debuginfo-analyzer` 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=<name>
|
|
|
|
The folder to write a file per compilation unit when **--output=split**
|
|
is specified.
|
|
|
|
.. option:: --output-level=<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=<value[,value,...]>
|
|
|
|
With **value** being one of 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=<key>
|
|
|
|
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=<value[,value,...]>
|
|
|
|
With **value** being one of 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
|
|
<pattern>, offset <value> or an element <condition>.
|
|
|
|
.. option:: --select=<pattern>
|
|
|
|
Print all elements whose name or line number matches the given <pattern>.
|
|
|
|
.. option:: --select-offsets=<value[,value,...]>
|
|
|
|
Print all elements whose offset matches the given values. See
|
|
:option:`--attribute` option.
|
|
|
|
.. option:: --select-elements=<condition[,condition,...]>
|
|
|
|
Print all elements that satisfy the given <condition>. With **condition**
|
|
being one of 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 <pattern> strings as regular expressions when selecting with
|
|
:option:`--select` option. If :option:`--select-nocase` is specified,
|
|
the regular expression becomes case-insensitive.
|
|
|
|
If the <pattern> 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), as the given **kind** describes a very specific type
|
|
of element.
|
|
|
|
LINES
|
|
^^^^^
|
|
The following options allow printing of lines that match the given <kind>.
|
|
The given criteria describes the debug line state machine registers.
|
|
|
|
.. option:: --select-lines=<kind[,kind,...]>
|
|
|
|
With **kind** being one of 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 <kind>.
|
|
|
|
.. option:: --select-scopes=<kind[,kind,...]>
|
|
|
|
With **kind** being one of 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: A union.
|
|
|
|
SYMBOLS
|
|
^^^^^^^
|
|
The following options allow printing of symbols that match the given <kind>.
|
|
|
|
.. option:: --select-symbols=<kind[,kind,...]>
|
|
|
|
With **kind** being one of 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 <kind>.
|
|
|
|
.. option:: --select-types=<kind[,kind,...]>
|
|
|
|
With **kind** being one of 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-debuginfo-analyzer` 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 debug information.
|
|
|
|
The following options describe the elements to compare.
|
|
|
|
.. option:: --compare=<value[,value,...]>
|
|
|
|
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-debuginfo-analyzer` 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-debuginfo-analyzer`
|
|
can detect 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=<value[,value,...]>
|
|
|
|
With **value** being one of 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 could be 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-debuginfo-analyzer` 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=<value[,value,...]>
|
|
|
|
With **value** being one of 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-debuginfo-analyzer`.
|
|
|
|
.. 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-debuginfo-analyzer` 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-debuginfo-analyzer`. We compiled the example for an X86
|
|
ELF target with 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-debuginfo-analyzer` 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-debuginfo-analyzer --attribute=level,format
|
|
--output-sort=offset
|
|
--print=scopes,symbols,types,lines,instructions
|
|
test-dwarf-clang.o
|
|
|
|
or
|
|
|
|
.. code-block:: none
|
|
|
|
llvm-debuginfo-analyzer --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-debuginfo-analyzer --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-debuginfo-analyzer` 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-debuginfo-analyzer --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-debuginfo-analyzer` 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-debuginfo-analyzer --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-debuginfo-analyzer --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-debuginfo-analyzer --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-debuginfo-analyzer`. 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-debuginfo-analyzer`
|
|
generates for 3 different compilers (MSVC, Clang and GCC), emitting
|
|
different debug information formats (CodeView, DWARF) on Windows and
|
|
Linux.
|
|
|
|
.. code-block:: none
|
|
|
|
llvm-debuginfo-analyzer --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-debuginfo-analyzer`. 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) <https://bugs.llvm.org/show_bug.cgi?id=44884>`_ /
|
|
`PR44229 (GitHub LLVM) <https://github.com/llvm/llvm-project/issues/44229>`_
|
|
|
|
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-debuginfo-analyzer`
|
|
generates for 3 different compilers (MSVC, Clang and GCC), emitting
|
|
different debug information formats (CodeView, DWARF) on different
|
|
platforms.
|
|
|
|
.. code-block:: none
|
|
|
|
llvm-debuginfo-analyzer --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-debuginfo-analyzer` selection facilities, we
|
|
can produce a simple tabular output showing just the logical types that
|
|
are **Typedef**.
|
|
|
|
.. code-block:: none
|
|
|
|
llvm-debuginfo-analyzer --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-debuginfo-analyzer`. 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) <https://bugs.llvm.org/show_bug.cgi?id=46466>`_ /
|
|
`PR45811 (GitHub LLVM) <https://github.com/llvm/llvm-project/issues/45811>`_
|
|
|
|
These are the logical views that :program:`llvm-debuginfo-analyzer`
|
|
generates for 3 different compilers (MSVC, Clang and GCC), emitting
|
|
different debug information formats (CodeView, DWARF) on different
|
|
platforms.
|
|
|
|
.. code-block:: none
|
|
|
|
llvm-debuginfo-analyzer --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, they do
|
|
include such references.
|
|
|
|
Using the :program:`llvm-debuginfo-analyzer` 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-debuginfo-analyzer --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-debuginfo-analyzer` 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-debuginfo-analyzer --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-debuginfo-analyzer`. 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) <https://bugs.llvm.org/show_bug.cgi?id=43860>`_ /
|
|
`PR43205 (GitHub) <https://github.com/llvm/llvm-project/issues/43205>`_
|
|
|
|
These are the logical views that :program:`llvm-debuginfo-analyzer`
|
|
generates for 3 different compilers (MSVC, Clang and GCC), emitting
|
|
different debug information formats (CodeView, DWARF) on different
|
|
platforms.
|
|
|
|
.. code-block:: none
|
|
|
|
llvm-debuginfo-analyzer --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-debuginfo-analyzer` 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-debuginfo-analyzer --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-debuginfo-analyzer` can display low
|
|
level information that includes offsets within the debug information
|
|
section, debug location operands, linkage names, etc.
|
|
|
|
.. code-block:: none
|
|
|
|
llvm-debuginfo-analyzer --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
|
|
size 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.
|
|
|
|
WEBASSEMBLY SUPPORT
|
|
~~~~~~~~~~~~~~~~~~~
|
|
The below example is used to show the WebAssembly output generated by
|
|
:program:`llvm-debuginfo-analyzer`. We compiled the example for a
|
|
WebAssembly 32-bit target with Clang (-O0 -g --target=wasm32):
|
|
|
|
.. 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 }
|
|
|
|
PRINT 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-debuginfo-analyzer --attribute=level,format
|
|
--output-sort=offset
|
|
--print=scopes,symbols,types,lines,instructions
|
|
test-clang.wasm
|
|
|
|
or
|
|
|
|
.. code-block:: none
|
|
|
|
llvm-debuginfo-analyzer --attribute=level,format
|
|
--output-sort=offset
|
|
--print=elements
|
|
test-clang.wasm
|
|
|
|
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-clang.wasm' -> WASM
|
|
|
|
[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} 'i32.const 7'
|
|
[004] {Code} 'local.set 10'
|
|
[004] {Code} 'local.get 5'
|
|
[004] {Code} 'local.get 10'
|
|
[004] {Code} 'i32.store 12'
|
|
[004] 6 {Line}
|
|
[004] {Code} 'i32.const 7'
|
|
[004] {Code} 'local.set 11'
|
|
[004] {Code} 'local.get 5'
|
|
[004] {Code} 'local.get 11'
|
|
[004] {Code} 'i32.store 28'
|
|
[004] {Code} 'br 1'
|
|
[004] - {Line}
|
|
[004] {Code} 'end'
|
|
[003] 4 {TypeAlias} 'INTEGER' -> 'int'
|
|
[003] 2 {Line}
|
|
[003] {Code} 'nop'
|
|
[003] {Code} 'end'
|
|
[003] {Code} 'i64.div_s'
|
|
[003] {Code} 'global.get 0'
|
|
[003] {Code} 'local.set 3'
|
|
[003] {Code} 'i32.const 32'
|
|
[003] {Code} 'local.set 4'
|
|
[003] {Code} 'local.get 3'
|
|
[003] {Code} 'local.get 4'
|
|
[003] {Code} 'i32.sub'
|
|
[003] {Code} 'local.set 5'
|
|
[003] {Code} 'local.get 5'
|
|
[003] {Code} 'local.get 0'
|
|
[003] {Code} 'i32.store 24'
|
|
[003] {Code} 'local.get 5'
|
|
[003] {Code} 'local.get 1'
|
|
[003] {Code} 'i32.store 20'
|
|
[003] {Code} 'local.get 2'
|
|
[003] {Code} 'local.set 6'
|
|
[003] {Code} 'local.get 5'
|
|
[003] {Code} 'local.get 6'
|
|
[003] {Code} 'i32.store8 19'
|
|
[003] 3 {Line}
|
|
[003] {Code} 'local.get 5'
|
|
[003] {Code} 'i32.load8_u 19'
|
|
[003] {Code} 'local.set 7'
|
|
[003] 3 {Line}
|
|
[003] {Code} 'i32.const 1'
|
|
[003] {Code} 'local.set 8'
|
|
[003] {Code} 'local.get 7'
|
|
[003] {Code} 'local.get 8'
|
|
[003] {Code} 'i32.and'
|
|
[003] {Code} 'local.set 9'
|
|
[003] {Code} 'block'
|
|
[003] {Code} 'block'
|
|
[003] {Code} 'local.get 9'
|
|
[003] {Code} 'i32.eqz'
|
|
[003] {Code} 'br_if 0'
|
|
[003] 8 {Line}
|
|
[003] {Code} 'local.get 5'
|
|
[003] {Code} 'i32.load 20'
|
|
[003] {Code} 'local.set 12'
|
|
[003] 8 {Line}
|
|
[003] {Code} 'local.get 5'
|
|
[003] {Code} 'local.get 12'
|
|
[003] {Code} 'i32.store 28'
|
|
[003] - {Line}
|
|
[003] {Code} 'end'
|
|
[003] 9 {Line}
|
|
[003] {Code} 'local.get 5'
|
|
[003] {Code} 'i32.load 28'
|
|
[003] {Code} 'local.set 13'
|
|
[003] {Code} 'local.get 13'
|
|
[003] {Code} 'return'
|
|
[003] {Code} 'end'
|
|
[003] 9 {Line}
|
|
[003] {Code} 'unreachable'
|
|
[002] 1 {TypeAlias} 'INTPTR' -> '* const int'
|
|
|
|
SELECT LOGICAL ELEMENTS
|
|
^^^^^^^^^^^^^^^^^^^^^^^
|
|
The following prints all *instructions*, *symbols* and *types* that
|
|
contain **'block'** or **'.store'** in their names or types, using a tab
|
|
layout and given the number of matches.
|
|
|
|
.. code-block:: none
|
|
|
|
llvm-debuginfo-analyzer --attribute=level
|
|
--select-nocase --select-regex
|
|
--select=BLOCK --select=.store
|
|
--report=list
|
|
--print=symbols,types,instructions,summary
|
|
test-clang.wasm
|
|
|
|
Logical View:
|
|
[000] {File} 'test-clang.wasm'
|
|
|
|
[001] {CompileUnit} 'test.cpp'
|
|
[003] {Code} 'block'
|
|
[003] {Code} 'block'
|
|
[004] {Code} 'i32.store 12'
|
|
[003] {Code} 'i32.store 20'
|
|
[003] {Code} 'i32.store 24'
|
|
[004] {Code} 'i32.store 28'
|
|
[003] {Code} 'i32.store 28'
|
|
[003] {Code} 'i32.store8 19'
|
|
|
|
-----------------------------
|
|
Element Total Printed
|
|
-----------------------------
|
|
Scopes 3 0
|
|
Symbols 4 0
|
|
Types 2 0
|
|
Lines 62 8
|
|
-----------------------------
|
|
Total 71 8
|
|
|
|
COMPARISON MODE
|
|
^^^^^^^^^^^^^^^
|
|
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-debuginfo-analyzer --attribute=level
|
|
--select-regex --select-nocase --select=INTe
|
|
--report=list
|
|
--print=symbols,types
|
|
test-clang.wasm test-dwarf-gcc.o
|
|
|
|
Logical View:
|
|
[000] {File} 'test-clang.wasm'
|
|
|
|
[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.
|
|
|
|
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.
|
|
|
|
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-debuginfo-analyzer --attribute=level
|
|
--compare=types
|
|
--report=view
|
|
--print=symbols,types
|
|
test-clang.wasm test-dwarf-gcc.o
|
|
|
|
Reference: 'test-clang.wasm'
|
|
Target: 'test-dwarf-gcc.o'
|
|
|
|
Logical View:
|
|
[000] {File} 'test-clang.wasm'
|
|
|
|
[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-debuginfo-analyzer --attribute=level
|
|
--compare=types
|
|
--report=list
|
|
--print=symbols,types,summary
|
|
test-clang.wasm test-dwarf-gcc.o
|
|
|
|
Reference: 'test-clang.wasm'
|
|
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-debuginfo-analyzer --attribute=level
|
|
--compare=types
|
|
--report=list
|
|
--print=symbols,types,summary
|
|
test-dwarf-gcc.o test-clang.wasm
|
|
|
|
Reference: 'test-dwarf-gcc.o'
|
|
Target: 'test-clang.wasm'
|
|
|
|
(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*.
|
|
|
|
EXIT STATUS
|
|
-----------
|
|
:program:`llvm-debuginfo-analyzer` returns 0 if the input files were
|
|
parsed and printed successfully. Otherwise, it returns 1.
|
|
|
|
SEE ALSO
|
|
--------
|
|
:manpage:`llvm-dwarfdump`
|