|
# llvm-debuginfo-analyzer - Print a logical representation of low-level debug information. |
|
|
|
```{program} llvm-debuginfo-analyzer |
|
``` |
|
|
|
## SYNOPSIS |
|
|
|
{program}`llvm-debuginfo-analyzer` \[*options*\] \[*filename ...*\] |
|
|
|
## DESCRIPTION |
|
|
|
{program}`llvm-debuginfo-analyzer` parses debug and text sections in |
|
binary object files or LLVM IR textual / bitcode representation 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, |
|
COFF and IR (textual representation and bitcode). |
|
|
|
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}`llvm-debuginfo-analyzer-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. |
|
|
|
(llvm-debuginfo-analyzer-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. |
|
|
|
```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 |
|
and source language that produced the binary file. |
|
|
|
```text |
|
=global: Element referenced across Compile Units. |
|
=format: Object file format name. |
|
=language: Source language 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. |
|
|
|
```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; type sizes and the underlying types associated with the types |
|
aliases. |
|
|
|
```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. |
|
=size: Sizes for compound and base types. |
|
=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. |
|
|
|
```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. |
|
|
|
```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. |
|
|
|
```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. |
|
|
|
```text |
|
=base |
|
=coverage |
|
=directories |
|
=discriminator |
|
=filename |
|
=files |
|
=format |
|
=language |
|
=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. |
|
|
|
```text |
|
=argument |
|
=discarded |
|
=encoded |
|
=gaps |
|
=generated |
|
=global |
|
=inserted |
|
=linkage |
|
=local |
|
=location |
|
=offset |
|
=operation |
|
=pathname |
|
=qualified |
|
=qualifier |
|
=register |
|
=size |
|
=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. |
|
|
|
```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. |
|
|
|
```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. |
|
|
|
```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. |
|
|
|
```text |
|
=all: Include all the below outputs. |
|
``` |
|
|
|
```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. |
|
|
|
```text |
|
=none: Unsorted output (i.e. as read from input). |
|
=id: Sort by unique element ID. |
|
=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. |
|
|
|
```text |
|
=all: Include all the below reports. |
|
``` |
|
|
|
```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. |
|
|
|
```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. |
|
|
|
```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. |
|
=LineAssembler: Lines that correspond to disassembly text. |
|
=LineDebug: Lines that correspond to debug lines. |
|
=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. |
|
|
|
```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. |
|
=Module: A module. |
|
=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. |
|
|
|
```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. |
|
|
|
```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. |
|
|
|
```text |
|
=all: Include all the below elements. |
|
``` |
|
|
|
```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. |
|
|
|
```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. |
|
|
|
```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. |
|
|
|
:::{option} --internal=<value[,value,...]> |
|
With **value** being one of the options in the following list. |
|
|
|
```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`. |
|
|
|
```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): |
|
|
|
```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. |
|
|
|
```none |
|
llvm-debuginfo-analyzer --attribute=level,format |
|
--output-sort=offset |
|
--print=scopes,symbols,types,lines,instructions |
|
test-dwarf-clang.o |
|
``` |
|
|
|
or |
|
|
|
```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. |
|
|
|
```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: |
|
|
|
```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. |
|
|
|
```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. |
|
|
|
```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. |
|
|
|
```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. |
|
|
|
```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: |
|
|
|
```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. |
|
|
|
```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. |
|
|
|
```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) |
|
|
|
```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) |
|
|
|
```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) |
|
|
|
```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) |
|
|
|
```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). |
|
|
|
```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. |
|
|
|
```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. |
|
|
|
```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) |
|
|
|
```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) |
|
|
|
```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) |
|
|
|
```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) |
|
|
|
```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**. |
|
|
|
```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). |
|
|
|
```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. |
|
|
|
```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) |
|
|
|
```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) |
|
|
|
```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) |
|
|
|
```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) |
|
|
|
```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. |
|
|
|
```none |
|
llvm-debuginfo-analyzer --attribute=format,level |
|
--output-sort=name |
|
--select-types=Enumerator |
|
--report=parents |
|
--print=types |
|
pr-46466-*.o |
|
``` |
|
|
|
```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. |
|
|
|
```none |
|
llvm-debuginfo-analyzer --attribute=format,level |
|
--output-sort=name |
|
--select-types=Enumerator |
|
--print=types,summary |
|
pr-46466-*.o |
|
``` |
|
|
|
```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). |
|
|
|
```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*. |
|
|
|
```c++ |
|
#include "definitions.h" |
|
``` |
|
|
|
```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. |
|
|
|
```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) |
|
|
|
```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) |
|
|
|
```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) |
|
|
|
```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] 13 {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) |
|
|
|
```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. |
|
|
|
```none |
|
llvm-debuginfo-analyzer --attribute=level,format |
|
--output-sort=name |
|
--select-regex --select-nocase --select=Var |
|
--report=list |
|
--print=symbols |
|
pr-43860-*.o |
|
``` |
|
|
|
```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. |
|
|
|
```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. |
|
|
|
```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): |
|
|
|
```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. |
|
|
|
```none |
|
llvm-debuginfo-analyzer --attribute=level,format |
|
--output-sort=offset |
|
--print=scopes,symbols,types,lines,instructions |
|
test-clang.o |
|
``` |
|
|
|
or |
|
|
|
```none |
|
llvm-debuginfo-analyzer --attribute=level,format |
|
--output-sort=offset |
|
--print=elements |
|
test-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. |
|
|
|
```none |
|
Logical View: |
|
[000] {File} 'test-clang.o' -> 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. |
|
|
|
```none |
|
llvm-debuginfo-analyzer --attribute=level |
|
--select-nocase --select-regex |
|
--select=BLOCK --select=.store |
|
--report=list |
|
--print=symbols,types,instructions,summary |
|
test-clang.o |
|
|
|
Logical View: |
|
[000] {File} 'test-clang.o' |
|
|
|
[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 |
|
``` |
|
|
|
### LLVM IR (textual / bitcode representation) SUPPORT |
|
|
|
The below example is used to show the IR output generated by |
|
{program}`llvm-debuginfo-analyzer`. We compiled the example for a |
|
IR 64-bit target with Clang (-O0 -g --target=x86_64-linux): |
|
|
|
```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. |
|
|
|
```none |
|
llvm-debuginfo-analyzer --attribute=level,format |
|
--output-sort=offset |
|
--print=scopes,symbols,types,lines,instructions |
|
test-clang.ll |
|
``` |
|
|
|
or |
|
|
|
```none |
|
llvm-debuginfo-analyzer --attribute=level,format |
|
--output-sort=offset |
|
--print=elements |
|
test-clang.ll |
|
``` |
|
|
|
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. |
|
|
|
```none |
|
Logical View: |
|
[000] {File} 'test-clang.ll' -> Textual IR |
|
|
|
[001] {CompileUnit} 'test.cpp' |
|
[002] 2 {Function} extern not_inlined 'foo' -> 'int' |
|
[003] {Block} |
|
[004] 5 {Variable} 'CONSTANT' -> 'const INTEGER' |
|
[004] 5 {Line} |
|
[004] {Code} 'store i32 7, ptr %CONSTANT, align 4, !dbg !32' |
|
[004] 6 {Line} |
|
[004] {Code} 'store i32 7, ptr %retval, align 4, !dbg !33' |
|
[004] 6 {Line} |
|
[004] {Code} 'br label %return, !dbg !33' |
|
[003] 2 {Parameter} 'ParamPtr' -> 'INTPTR' |
|
[003] 2 {Parameter} 'ParamUnsigned' -> 'unsigned int' |
|
[003] 2 {Parameter} 'ParamBool' -> 'bool' |
|
[003] 4 {TypeAlias} 'INTEGER' -> 'int' |
|
[003] 2 {Line} |
|
[003] {Code} '%retval = alloca i32, align 4' |
|
[003] {Code} '%ParamPtr.addr = alloca ptr, align 8' |
|
[003] {Code} '%ParamUnsigned.addr = alloca i32, align 4' |
|
[003] {Code} '%ParamBool.addr = alloca i8, align 1' |
|
[003] {Code} '%CONSTANT = alloca i32, align 4' |
|
[003] {Code} 'store ptr %ParamPtr, ptr %ParamPtr.addr, align 8' |
|
[003] {Code} 'store i32 %ParamUnsigned, ptr %ParamUnsigned.addr, align 4' |
|
[003] {Code} '%storedv = zext i1 %ParamBool to i8' |
|
[003] {Code} 'store i8 %storedv, ptr %ParamBool.addr, align 1' |
|
[003] 8 {Line} |
|
[003] {Code} '%1 = load i32, ptr %ParamUnsigned.addr, align 4, !dbg !34' |
|
[003] 8 {Line} |
|
[003] {Code} 'store i32 %1, ptr %retval, align 4, !dbg !35' |
|
[003] 8 {Line} |
|
[003] {Code} 'br label %return, !dbg !35' |
|
[003] 9 {Line} |
|
[003] {Code} '%2 = load i32, ptr %retval, align 4, !dbg !36' |
|
[003] 9 {Line} |
|
[003] {Code} 'ret i32 %2, !dbg !36' |
|
[003] 3 {Line} |
|
[003] 3 {Line} |
|
[003] 3 {Line} |
|
[003] {Code} 'br i1 %loadedv, label %if.then, label %if.end, !dbg !26' |
|
[002] 1 {TypeAlias} 'INTPTR' -> '* const int' |
|
``` |
|
|
|
## EXIT STATUS |
|
|
|
{program}`llvm-debuginfo-analyzer` returns 0 if the input files were |
|
parsed and printed successfully. Otherwise, it returns 1. |
|
|
|
## LIMITATIONS AND KNOWN ISSUES |
|
|
|
See {download}`Limitations <../../tools/llvm-debuginfo-analyzer/README.md>`. |
|
|
|
## SEE ALSO |
|
|
|
{manpage}`llvm-dwarfdump` |