[llvm] [llvm-debuginfo-analyzer] Add support for WebAssembly binary format. (PR #82588)

Carlos Alberto Enciso via llvm-commits llvm-commits at lists.llvm.org
Wed Feb 21 22:17:31 PST 2024


https://github.com/CarlosAlbertoEnciso created https://github.com/llvm/llvm-project/pull/82588

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 and conversion between .wasm and .wat.

>From 9c9ce3cb5347c31fba5e8ac1480a7525e6d0964f Mon Sep 17 00:00:00 2001
From: Carlos Alberto Enciso <carlos.alberto.enciso at gmail.com>
Date: Thu, 22 Feb 2024 06:00:45 +0000
Subject: [PATCH] [llvm-debuginfo-analyzer] Add support for WebAssembly binary
 format.

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 and conversion between .wasm and .wat.
---
 .../CommandGuide/llvm-debuginfo-analyzer.rst  | 317 +++++++++++++++++-
 .../LogicalView/Readers/LVBinaryReader.h      |  42 +++
 .../DebugInfo/LogicalView/LVReaderHandler.cpp |   2 +-
 .../LogicalView/Readers/LVBinaryReader.cpp    |  30 ++
 .../LogicalView/Readers/LVELFReader.cpp       |  14 +-
 .../01-wasm-compare-logical-elements.test     | 103 ++++++
 .../01-wasm-print-basic-details.test          | 117 +++++++
 .../01-wasm-select-logical-elements.test      |  74 ++++
 .../WebAssembly/02-wasm-logical-lines.test    |  77 +++++
 ...-wasm-incorrect-lexical-scope-typedef.test | 132 ++++++++
 .../04-wasm-missing-nested-enumerators.test   | 127 +++++++
 ...wasm-incorrect-lexical-scope-variable.test | 111 ++++++
 .../06-wasm-full-logical-view.test            | 155 +++++++++
 .../WebAssembly/Inputs/definitions.h          |  30 ++
 .../WebAssembly/Inputs/hello-world-clang.wasm | Bin 0 -> 1414 bytes
 .../WebAssembly/Inputs/hello-world-clang.wat  |  52 +++
 .../WebAssembly/Inputs/hello-world.cpp        |   7 +
 .../WebAssembly/Inputs/pr-43860-clang.wasm    | Bin 0 -> 1613 bytes
 .../WebAssembly/Inputs/pr-43860-clang.wat     |  75 +++++
 .../WebAssembly/Inputs/pr-43860.cpp           |  15 +
 .../WebAssembly/Inputs/pr-44884-clang.wasm    | Bin 0 -> 1882 bytes
 .../WebAssembly/Inputs/pr-44884-clang.wat     | 149 ++++++++
 .../WebAssembly/Inputs/pr-44884.cpp           |  14 +
 .../WebAssembly/Inputs/pr-46466-clang.wasm    | Bin 0 -> 1180 bytes
 .../WebAssembly/Inputs/pr-46466-clang.wat     |  11 +
 .../WebAssembly/Inputs/pr-46466.cpp           |  11 +
 .../WebAssembly/Inputs/test-clang.wasm        | Bin 0 -> 1459 bytes
 .../WebAssembly/Inputs/test-clang.wat         |  63 ++++
 .../WebAssembly/Inputs/test.cpp               |   9 +
 .../WebAssembly/README.txt                    |  54 +++
 30 files changed, 1785 insertions(+), 6 deletions(-)
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/01-wasm-compare-logical-elements.test
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/01-wasm-print-basic-details.test
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/01-wasm-select-logical-elements.test
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/02-wasm-logical-lines.test
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/03-wasm-incorrect-lexical-scope-typedef.test
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/04-wasm-missing-nested-enumerators.test
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/05-wasm-incorrect-lexical-scope-variable.test
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/06-wasm-full-logical-view.test
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/definitions.h
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/hello-world-clang.wasm
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/hello-world-clang.wat
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/hello-world.cpp
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/pr-43860-clang.wasm
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/pr-43860-clang.wat
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/pr-43860.cpp
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/pr-44884-clang.wasm
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/pr-44884-clang.wat
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/pr-44884.cpp
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/pr-46466-clang.wasm
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/pr-46466-clang.wat
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/pr-46466.cpp
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/test-clang.wasm
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/test-clang.wat
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/test.cpp
 create mode 100644 llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/README.txt

diff --git a/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst b/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst
index a78066a5eea37e..82fad8ce4d5192 100644
--- a/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst
+++ b/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst
@@ -16,7 +16,7 @@ DESCRIPTION
 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, PDB and COFF.
+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
@@ -468,8 +468,9 @@ 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, COFF), as the given **kind** describes a very specific type
+CodeView), as the given **kind** describes a very specific type
 of element.
 
 LINES
@@ -598,7 +599,7 @@ When comparing logical views created from different debug formats, its
 accuracy depends on how close the debug information represents the
 user code. For instance, a logical view created from a binary file with
 DWARF debug information may include more detailed data than a logical
-view created from a binary file with CodeView/COFF debug information.
+view created from a binary file with CodeView debug information.
 
 The following options describe the elements to compare.
 
@@ -1952,6 +1953,316 @@ 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 64-bit target with Clang (-O0 -g --target=wasm64):
+
+.. 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	4'
+  [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} 'block   	unknown_type'
+  [003]                 {Code} 'i64.mul'
+  [003]                 {Code} 'throw   	127'
+  [003]                 {Code} 'global.get	0'
+  [003]                 {Code} 'local.set	3'
+  [003]                 {Code} 'i64.const	32'
+  [003]                 {Code} 'local.set	4'
+  [003]                 {Code} 'local.get	3'
+  [003]                 {Code} 'local.get	4'
+  [003]                 {Code} 'i64.sub'
+  [003]                 {Code} 'local.set	5'
+  [003]                 {Code} 'local.get	5'
+  [003]                 {Code} 'local.get	0'
+  [003]                 {Code} 'i64.store	16'
+  [003]                 {Code} 'local.get	5'
+  [003]                 {Code} 'local.get	1'
+  [003]                 {Code} 'i32.store	12'
+  [003]                 {Code} 'local.get	2'
+  [003]                 {Code} 'local.set	6'
+  [003]                 {Code} 'local.get	5'
+  [003]                 {Code} 'local.get	6'
+  [003]                 {Code} 'i32.store8	11'
+  [003]     3           {Line}
+  [003]                 {Code} 'local.get	5'
+  [003]                 {Code} 'i32.load8_u	11'
+  [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	12'
+  [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'
+  [003]           {Code} 'block   	unknown_type'
+  [003]           {Code} 'i32.store	12'
+  [004]           {Code} 'i32.store	28'
+  [003]           {Code} 'i32.store	28'
+  [004]           {Code} 'i32.store	4'
+  [003]           {Code} 'i32.store8	11'
+  [003]           {Code} 'i64.store	16'
+
+  -----------------------------
+  Element      Total    Printed
+  -----------------------------
+  Scopes           3          0
+  Symbols          4          0
+  Types            2          0
+  Lines           62          9
+  -----------------------------
+  Total           71          9
+
+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
diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h
index a66cf4608823be..f62ae25c10f6db 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h
@@ -122,6 +122,48 @@ class LVBinaryReader : public LVReader {
   std::unique_ptr<MCContext> MC;
   std::unique_ptr<MCInstPrinter> MIP;
 
+  // https://yurydelendik.github.io/webassembly-dwarf/
+  // 2. Consuming and Generating DWARF for WebAssembly Code
+  // Note: Some DWARF constructs don't map one-to-one onto WebAssembly
+  // constructs. We strive to enumerate and resolve any ambiguities here.
+  //
+  // 2.1. Code Addresses
+  // Note: DWARF associates various bits of debug info
+  // with particular locations in the program via its code address (instruction
+  // pointer or PC). However, WebAssembly's linear memory address space does not
+  // contain WebAssembly instructions.
+  //
+  // Wherever a code address (see 2.17 of [DWARF]) is used in DWARF for
+  // WebAssembly, it must be the offset of an instruction relative within the
+  // Code section of the WebAssembly file. The DWARF is considered malformed if
+  // a PC offset is between instruction boundaries within the Code section.
+  //
+  // Note: It is expected that a DWARF consumer does not know how to decode
+  // WebAssembly instructions. The instruction pointer is selected as the offset
+  // in the binary file of the first byte of the instruction, and it is
+  // consistent with the WebAssembly Web API conventions definition of the code
+  // location.
+  //
+  // EXAMPLE: .DEBUG_LINE INSTRUCTION POINTERS
+  // The .debug_line DWARF section maps instruction pointers to source
+  // locations. With WebAssembly, the .debug_line section maps Code
+  // section-relative instruction offsets to source locations.
+  //
+  //  EXAMPLE: DW_AT_* ATTRIBUTES
+  // For entities with a single associated code address, DWARF uses
+  // the DW_AT_low_pc attribute to specify the associated code address value.
+  // For WebAssembly, the DW_AT_low_pc's value is a Code section-relative
+  // instruction offset.
+  //
+  // For entities with a single contiguous range of code, DWARF uses a
+  // pair of DW_AT_low_pc and DW_AT_high_pc attributes to specify the associated
+  // contiguous range of code address values. For WebAssembly, these attributes
+  // are Code section-relative instruction offsets.
+  //
+  // For entities with multiple ranges of code, DWARF uses the DW_AT_ranges
+  // attribute, which refers to the array located at the .debug_ranges section.
+  LVAddress WasmOffset = 0;
+
   // Loads all info for the architecture of the provided object file.
   Error loadGenericTargetInfo(StringRef TheTriple, StringRef TheFeatures);
 
diff --git a/llvm/lib/DebugInfo/LogicalView/LVReaderHandler.cpp b/llvm/lib/DebugInfo/LogicalView/LVReaderHandler.cpp
index 5f82f816dc19d5..16c4fbed1423fb 100644
--- a/llvm/lib/DebugInfo/LogicalView/LVReaderHandler.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/LVReaderHandler.cpp
@@ -48,7 +48,7 @@ Error LVReaderHandler::createReader(StringRef Filename, LVReaders &Readers,
         return std::make_unique<LVCodeViewReader>(Filename, FileFormatName,
                                                   *COFF, W, ExePath);
       }
-      if (Obj.isELF() || Obj.isMachO())
+      if (Obj.isELF() || Obj.isMachO() || Obj.isWasm())
         return std::make_unique<LVELFReader>(Filename, FileFormatName, Obj, W);
     }
     if (isa<PDBFile *>(Input)) {
diff --git a/llvm/lib/DebugInfo/LogicalView/Readers/LVBinaryReader.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVBinaryReader.cpp
index a0cd8b7839cf7a..d219b8abe1ae98 100644
--- a/llvm/lib/DebugInfo/LogicalView/Readers/LVBinaryReader.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVBinaryReader.cpp
@@ -146,6 +146,30 @@ bool LVBinaryReader::getSymbolTableIsComdat(StringRef Name) {
 
 void LVBinaryReader::mapVirtualAddress(const object::ObjectFile &Obj) {
   for (const object::SectionRef &Section : Obj.sections()) {
+    LLVM_DEBUG({
+      Expected<StringRef> SectionNameOrErr = Section.getName();
+      StringRef Name;
+      if (!SectionNameOrErr)
+        consumeError(SectionNameOrErr.takeError());
+      else
+        Name = *SectionNameOrErr;
+      dbgs() << "Index: " << format_decimal(Section.getIndex(), 3) << ", "
+             << "Address: " << hexValue(Section.getAddress()) << ", "
+             << "Size: " << hexValue(Section.getSize()) << ", "
+             << "Name: " << Name << "\n";
+      dbgs() << "isCompressed:   " << Section.isCompressed() << ", "
+             << "isText:         " << Section.isText() << ", "
+             << "isData:         " << Section.isData() << ", "
+             << "isBSS:          " << Section.isBSS() << ", "
+             << "isVirtual:      " << Section.isVirtual() << "\n";
+      dbgs() << "isBitcode:      " << Section.isBitcode() << ", "
+             << "isStripped:     " << Section.isStripped() << ", "
+             << "isBerkeleyText: " << Section.isBerkeleyText() << ", "
+             << "isBerkeleyData: " << Section.isBerkeleyData() << ", "
+             << "isDebugSection: " << Section.isDebugSection() << "\n";
+      dbgs() << "\n";
+    });
+
     if (!Section.isText() || Section.isVirtual() || !Section.getSize())
       continue;
 
@@ -161,8 +185,14 @@ void LVBinaryReader::mapVirtualAddress(const object::ObjectFile &Obj) {
       continue;
     }
     if ((*SectionNameOrErr).equals(".text") ||
+        (*SectionNameOrErr).equals("CODE") ||
         (*SectionNameOrErr).equals(".code"))
       DotTextSectionIndex = Section.getIndex();
+      // If the object is WebAssembly, update the address offset that
+      // will be added to DWARF DW_AT_* attributes.
+      if (Obj.isWasm()) {
+        WasmOffset = Section.getAddress();
+      }
   }
 
   // Process the symbol table.
diff --git a/llvm/lib/DebugInfo/LogicalView/Readers/LVELFReader.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVELFReader.cpp
index 4469092099daca..79428357fa26c1 100644
--- a/llvm/lib/DebugInfo/LogicalView/Readers/LVELFReader.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVELFReader.cpp
@@ -415,6 +415,8 @@ void LVELFReader::processOneAttribute(const DWARFDie &Die, LVOffset *OffsetPtr,
       if (FoundLowPC) {
         if (CurrentLowPC == MaxAddress)
           CurrentElement->setIsDiscarded();
+        // Consider the case of WebAssembly.
+        CurrentLowPC += WasmOffset;
         if (CurrentElement->isCompileUnit())
           setCUBaseAddress(CurrentLowPC);
       }
@@ -429,10 +431,14 @@ void LVELFReader::processOneAttribute(const DWARFDie &Die, LVOffset *OffsetPtr,
         CurrentHighPC = *Address;
       if (std::optional<uint64_t> Offset = FormValue.getAsUnsignedConstant())
         // High PC is an offset from LowPC.
-        CurrentHighPC = CurrentLowPC + *Offset;
+        // Don't add the WebAssembly offset if we have seen a DW_AT_low_pc.
+        CurrentHighPC =
+            (FoundLowPC ? CurrentLowPC - WasmOffset : CurrentLowPC) + *Offset;
       // Store the real upper limit for the address range.
       if (UpdateHighAddress && CurrentHighPC > 0)
         --CurrentHighPC;
+      // Consider the case of WebAssembly.
+      CurrentHighPC += WasmOffset;
       if (CurrentElement->isCompileUnit())
         setCUHighAddress(CurrentHighPC);
     }
@@ -466,6 +472,9 @@ void LVELFReader::processOneAttribute(const DWARFDie &Die, LVOffset *OffsetPtr,
         // Store the real upper limit for the address range.
         if (UpdateHighAddress && Range.HighPC > 0)
           --Range.HighPC;
+        // Consider the case of WebAssembly.
+        Range.LowPC += WasmOffset;
+        Range.HighPC += WasmOffset;
         // Add the pair of addresses.
         CurrentScope->addObject(Range.LowPC, Range.HighPC);
         // If the scope is the CU, do not update the ranges set.
@@ -735,7 +744,8 @@ void LVELFReader::createLineAndFileRecords(
       // and they will be released when its scope parent is deleted.
       LVLineDebug *Line = createLineDebug();
       CULines.push_back(Line);
-      Line->setAddress(Row.Address.Address);
+      // Consider the case of WebAssembly.
+      Line->setAddress(Row.Address.Address + WasmOffset);
       Line->setFilename(
           CompileUnit->getFilename(IncrementIndex ? Row.File + 1 : Row.File));
       Line->setLineNumber(Row.Line);
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/01-wasm-compare-logical-elements.test b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/01-wasm-compare-logical-elements.test
new file mode 100644
index 00000000000000..4194fd89dd5dfe
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/01-wasm-compare-logical-elements.test
@@ -0,0 +1,103 @@
+; REQUIRES: webassembly-registered-target
+
+; Test case 1 - General options
+
+; test.cpp
+;  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  }
+
+; Compare mode - Logical view.
+; The output shows in view form the 'missing (-), added (+)' elements,
+; giving more context by swapping the reference and target object files.
+
+; RUN: llvm-debuginfo-analyzer --attribute=level \
+; RUN:                         --compare=types \
+; RUN:                         --report=view \
+; RUN:                         --print=symbols,types \
+; RUN:                         %p/Inputs/test-clang.wasm \
+; RUN:                         %p/../DWARF/Inputs/test-dwarf-gcc.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
+
+; ONE:      Reference: 'test-clang.wasm'
+; ONE-NEXT: Target:    'test-dwarf-gcc.o'
+; ONE-EMPTY:
+; ONE-NEXT: Logical View:
+; ONE-NEXT:  [000]           {File} 'test-clang.wasm'
+; ONE-EMPTY:
+; ONE-NEXT:  [001]             {CompileUnit} 'test.cpp'
+; ONE-NEXT:  [002]     1         {TypeAlias} 'INTPTR' -> '* const int'
+; ONE-NEXT:  [002]     2         {Function} extern not_inlined 'foo' -> 'int'
+; ONE-NEXT:  [003]                 {Block}
+; ONE-NEXT:  [004]     5             {Variable} 'CONSTANT' -> 'const INTEGER'
+; ONE-NEXT: +[004]     4             {TypeAlias} 'INTEGER' -> 'int'
+; ONE-NEXT:  [003]     2           {Parameter} 'ParamBool' -> 'bool'
+; ONE-NEXT:  [003]     2           {Parameter} 'ParamPtr' -> 'INTPTR'
+; ONE-NEXT:  [003]     2           {Parameter} 'ParamUnsigned' -> 'unsigned int'
+; ONE-NEXT: -[003]     4           {TypeAlias} 'INTEGER' -> 'int'
+
+; Compare mode - Logical elements.
+; The output shows in tabular form the 'missing (-), added (+)' elements,
+; giving more context by swapping the reference and target object files.
+
+; RUN: llvm-debuginfo-analyzer --attribute=level \
+; RUN:                         --compare=types \
+; RUN:                         --report=list \
+; RUN:                         --print=symbols,types,summary \
+; RUN:                         %p/Inputs/test-clang.wasm \
+; RUN:                         %p/../DWARF/Inputs/test-dwarf-gcc.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=TWO %s
+
+; TWO:      Reference: 'test-clang.wasm'
+; TWO-NEXT: Target:    'test-dwarf-gcc.o'
+; TWO-EMPTY:
+; TWO-NEXT: (1) Missing Types:
+; TWO-NEXT: -[003]     4     {TypeAlias} 'INTEGER' -> 'int'
+; TWO-EMPTY:
+; TWO-NEXT: (1) Added Types:
+; TWO-NEXT: +[004]     4     {TypeAlias} 'INTEGER' -> 'int'
+; TWO-EMPTY:
+; TWO-NEXT: ----------------------------------------
+; TWO-NEXT: Element   Expected    Missing      Added
+; TWO-NEXT: ----------------------------------------
+; TWO-NEXT: Scopes           4          0          0
+; TWO-NEXT: Symbols          0          0          0
+; TWO-NEXT: Types            2          1          1
+; TWO-NEXT: Lines            0          0          0
+; TWO-NEXT: ----------------------------------------
+; TWO-NEXT: Total            6          1          1
+
+; Changing the 'Reference' and 'Target' order:
+
+; RUN: llvm-debuginfo-analyzer --attribute=level \
+; RUN:                         --compare=types \
+; RUN:                         --report=list \
+; RUN:                         --print=symbols,types,summary \
+; RUN:                         %p/../DWARF/Inputs/test-dwarf-gcc.o \
+; RUN:                         %p/Inputs/test-clang.wasm 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=THR %s
+
+; THR:      Reference: 'test-dwarf-gcc.o'
+; THR-NEXT: Target:    'test-clang.wasm'
+; THR-EMPTY:
+; THR-NEXT: (1) Missing Types:
+; THR-NEXT: -[004]     4     {TypeAlias} 'INTEGER' -> 'int'
+; THR-EMPTY:
+; THR-NEXT: (1) Added Types:
+; THR-NEXT: +[003]     4     {TypeAlias} 'INTEGER' -> 'int'
+; THR-EMPTY:
+; THR-NEXT: ----------------------------------------
+; THR-NEXT: Element   Expected    Missing      Added
+; THR-NEXT: ----------------------------------------
+; THR-NEXT: Scopes           4          0          0
+; THR-NEXT: Symbols          0          0          0
+; THR-NEXT: Types            2          1          1
+; THR-NEXT: Lines            0          0          0
+; THR-NEXT: ----------------------------------------
+; THR-NEXT: Total            6          1          1
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/01-wasm-print-basic-details.test b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/01-wasm-print-basic-details.test
new file mode 100644
index 00000000000000..10b44028bfbfb9
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/01-wasm-print-basic-details.test
@@ -0,0 +1,117 @@
+; REQUIRES: webassembly-registered-target
+
+; Test case 1 - General options.
+
+; test.cpp
+;  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.
+
+; RUN: llvm-debuginfo-analyzer --attribute=level,format \
+; RUN:                         --output-sort=offset \
+; RUN:                         --print=scopes,symbols,types,lines,instructions \
+; RUN:                         %p/Inputs/test-clang.wasm 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
+
+; RUN: llvm-debuginfo-analyzer --attribute=level,format \
+; RUN:                         --output-sort=offset \
+; RUN:                         --print=elements \
+; RUN:                         %p/Inputs/test-clang.wasm 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
+
+; ONE:      Logical View:
+; ONE-NEXT: [000]           {File} 'test-clang.wasm' -> WASM
+; ONE-EMPTY:
+; ONE-NEXT: [001]             {CompileUnit} 'test.cpp'
+; ONE-NEXT: [002]     2         {Function} extern not_inlined 'foo' -> 'int'
+; ONE-NEXT: [003]     2           {Parameter} 'ParamPtr' -> 'INTPTR'
+; ONE-NEXT: [003]     2           {Parameter} 'ParamUnsigned' -> 'unsigned int'
+; ONE-NEXT: [003]     2           {Parameter} 'ParamBool' -> 'bool'
+; ONE-NEXT: [003]                 {Block}
+; ONE-NEXT: [004]     5             {Variable} 'CONSTANT' -> 'const INTEGER'
+; ONE-NEXT: [004]     5             {Line}
+; ONE-NEXT: [004]                   {Code} 'i32.const	7'
+; ONE-NEXT: [004]                   {Code} 'local.set	10'
+; ONE-NEXT: [004]                   {Code} 'local.get	5'
+; ONE-NEXT: [004]                   {Code} 'local.get	10'
+; ONE-NEXT: [004]                   {Code} 'i32.store	4'
+; ONE-NEXT: [004]     6             {Line}
+; ONE-NEXT: [004]                   {Code} 'i32.const	7'
+; ONE-NEXT: [004]                   {Code} 'local.set	11'
+; ONE-NEXT: [004]                   {Code} 'local.get	5'
+; ONE-NEXT: [004]                   {Code} 'local.get	11'
+; ONE-NEXT: [004]                   {Code} 'i32.store	28'
+; ONE-NEXT: [004]                   {Code} 'br      	1'
+; ONE-NEXT: [004]     -             {Line}
+; ONE-NEXT: [004]                   {Code} 'end'
+; ONE-NEXT: [003]     4           {TypeAlias} 'INTEGER' -> 'int'
+; ONE-NEXT: [003]     2           {Line}
+; ONE-NEXT: [003]                 {Code} 'block   	unknown_type'
+; ONE-NEXT: [003]                 {Code} 'i64.mul'
+; ONE-NEXT: [003]                 {Code} 'throw   	127'
+; ONE-NEXT: [003]                 {Code} 'global.get	0'
+; ONE-NEXT: [003]                 {Code} 'local.set	3'
+; ONE-NEXT: [003]                 {Code} 'i64.const	32'
+; ONE-NEXT: [003]                 {Code} 'local.set	4'
+; ONE-NEXT: [003]                 {Code} 'local.get	3'
+; ONE-NEXT: [003]                 {Code} 'local.get	4'
+; ONE-NEXT: [003]                 {Code} 'i64.sub'
+; ONE-NEXT: [003]                 {Code} 'local.set	5'
+; ONE-NEXT: [003]                 {Code} 'local.get	5'
+; ONE-NEXT: [003]                 {Code} 'local.get	0'
+; ONE-NEXT: [003]                 {Code} 'i64.store	16'
+; ONE-NEXT: [003]                 {Code} 'local.get	5'
+; ONE-NEXT: [003]                 {Code} 'local.get	1'
+; ONE-NEXT: [003]                 {Code} 'i32.store	12'
+; ONE-NEXT: [003]                 {Code} 'local.get	2'
+; ONE-NEXT: [003]                 {Code} 'local.set	6'
+; ONE-NEXT: [003]                 {Code} 'local.get	5'
+; ONE-NEXT: [003]                 {Code} 'local.get	6'
+; ONE-NEXT: [003]                 {Code} 'i32.store8	11'
+; ONE-NEXT: [003]     3           {Line}
+; ONE-NEXT: [003]                 {Code} 'local.get	5'
+; ONE-NEXT: [003]                 {Code} 'i32.load8_u	11'
+; ONE-NEXT: [003]                 {Code} 'local.set	7'
+; ONE-NEXT: [003]     3           {Line}
+; ONE-NEXT: [003]                 {Code} 'i32.const	1'
+; ONE-NEXT: [003]                 {Code} 'local.set	8'
+; ONE-NEXT: [003]                 {Code} 'local.get	7'
+; ONE-NEXT: [003]                 {Code} 'local.get	8'
+; ONE-NEXT: [003]                 {Code} 'i32.and'
+; ONE-NEXT: [003]                 {Code} 'local.set	9'
+; ONE-NEXT: [003]                 {Code} 'block'
+; ONE-NEXT: [003]                 {Code} 'block'
+; ONE-NEXT: [003]                 {Code} 'local.get	9'
+; ONE-NEXT: [003]                 {Code} 'i32.eqz'
+; ONE-NEXT: [003]                 {Code} 'br_if   	0'
+; ONE-NEXT: [003]     8           {Line}
+; ONE-NEXT: [003]                 {Code} 'local.get	5'
+; ONE-NEXT: [003]                 {Code} 'i32.load	12'
+; ONE-NEXT: [003]                 {Code} 'local.set	12'
+; ONE-NEXT: [003]     8           {Line}
+; ONE-NEXT: [003]                 {Code} 'local.get	5'
+; ONE-NEXT: [003]                 {Code} 'local.get	12'
+; ONE-NEXT: [003]                 {Code} 'i32.store	28'
+; ONE-NEXT: [003]     -           {Line}
+; ONE-NEXT: [003]                 {Code} 'end'
+; ONE-NEXT: [003]     9           {Line}
+; ONE-NEXT: [003]                 {Code} 'local.get	5'
+; ONE-NEXT: [003]                 {Code} 'i32.load	28'
+; ONE-NEXT: [003]                 {Code} 'local.set	13'
+; ONE-NEXT: [003]                 {Code} 'local.get	13'
+; ONE-NEXT: [003]                 {Code} 'return'
+; ONE-NEXT: [003]                 {Code} 'end'
+; ONE-NEXT: [003]     9           {Line}
+; ONE-NEXT: [003]                 {Code} 'unreachable'
+; ONE-NEXT: [002]     1         {TypeAlias} 'INTPTR' -> '* const int'
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/01-wasm-select-logical-elements.test b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/01-wasm-select-logical-elements.test
new file mode 100644
index 00000000000000..44602dc7ac2cec
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/01-wasm-select-logical-elements.test
@@ -0,0 +1,74 @@
+; REQUIRES: webassembly-registered-target
+
+; Test case 1 - General options
+
+; test.cpp
+;  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  }
+
+; 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.
+
+; RUN: llvm-debuginfo-analyzer --attribute=level \
+; RUN:                         --select-nocase --select-regex \
+; RUN:                         --select=BLOCK --select=.store \
+; RUN:                         --report=list \
+; RUN:                         --print=symbols,types,instructions,summary \
+; RUN:                         %p/Inputs/test-clang.wasm 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
+
+; ONE:      Logical View:
+; ONE-NEXT: [000]           {File} 'test-clang.wasm'
+; ONE-EMPTY:
+; ONE-NEXT: [001]           {CompileUnit} 'test.cpp'
+; ONE-NEXT: [003]           {Code} 'block'
+; ONE-NEXT: [003]           {Code} 'block'
+; ONE-NEXT: [003]           {Code} 'block   	unknown_type'
+; ONE-NEXT: [003]           {Code} 'i32.store	12'
+; ONE-NEXT: [004]           {Code} 'i32.store	28'
+; ONE-NEXT: [003]           {Code} 'i32.store	28'
+; ONE-NEXT: [004]           {Code} 'i32.store	4'
+; ONE-NEXT: [003]           {Code} 'i32.store8	11'
+; ONE-NEXT: [003]           {Code} 'i64.store	16'
+; ONE-EMPTY:
+; ONE-NEXT: -----------------------------
+; ONE-NEXT: Element      Total    Printed
+; ONE-NEXT: -----------------------------
+; ONE-NEXT: Scopes           3          0
+; ONE-NEXT: Symbols          4          0
+; ONE-NEXT: Types            2          0
+; ONE-NEXT: Lines           62          9
+; ONE-NEXT: -----------------------------
+; ONE-NEXT: Total           71          9
+
+; RUN: llvm-debuginfo-analyzer --attribute=level \
+; RUN:                         --select-regex --select-nocase \
+; RUN:                         --select=INTe \
+; RUN:                         --report=list \
+; RUN:                         --print=symbols,types \
+; RUN:                         %p/Inputs/test-clang.wasm \
+; RUN:                         %p/../DWARF/Inputs/test-dwarf-gcc.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=TWO %s
+
+; TWO:      Logical View:
+; TWO-NEXT: [000]           {File} 'test-clang.wasm'
+; TWO-EMPTY:
+; TWO-NEXT: [001]           {CompileUnit} 'test.cpp'
+; TWO-NEXT: [003]     4     {TypeAlias} 'INTEGER' -> 'int'
+; TWO-NEXT: [004]     5     {Variable} 'CONSTANT' -> 'const INTEGER'
+; TWO-EMPTY:
+; TWO-NEXT: Logical View:
+; TWO-NEXT: [000]           {File} 'test-dwarf-gcc.o'
+; TWO-EMPTY:
+; TWO-NEXT: [001]           {CompileUnit} 'test.cpp'
+; TWO-NEXT: [004]     4     {TypeAlias} 'INTEGER' -> 'int'
+; TWO-NEXT: [004]     5     {Variable} 'CONSTANT' -> 'const INTEGER'
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/02-wasm-logical-lines.test b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/02-wasm-logical-lines.test
new file mode 100644
index 00000000000000..af55d7812115a6
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/02-wasm-logical-lines.test
@@ -0,0 +1,77 @@
+; REQUIRES: webassembly-registered-target
+
+; Test case 2 - Assembler instructions.
+
+; hello-world.cpp
+;  1  extern int printf(const char * format, ... );
+;  2
+;  3  int main()
+;  4  {
+;  5    printf("Hello, World\n");
+;  6    return 0;
+;  7  }
+
+; Logical lines.
+; The logical views shows the intermixed lines and assembler instructions,
+; allowing to compare the code generated by the different toolchains.
+
+; RUN: llvm-debuginfo-analyzer --attribute=level,format,producer \
+; RUN:                         --print=lines,instructions \
+; RUN:                         %p/Inputs/hello-world-clang.wasm 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
+
+; ONE:      Logical View:
+; ONE-NEXT: [000]           {File} 'hello-world-clang.wasm' -> WASM
+; ONE-EMPTY:
+; ONE-NEXT: [001]             {CompileUnit} 'hello-world.cpp'
+; ONE-NEXT: [002]               {Producer} 'clang version 19{{.*}}'
+; ONE-NEXT: [002]     3         {Function} extern not_inlined 'main' -> 'int'
+; ONE-NEXT: [003]     4           {Line}
+; ONE-NEXT: [003]                 {Code} 'else'
+; ONE-NEXT: [003]                 {Code} 'loop    	i64'
+; ONE-NEXT: [003]                 {Code} 'nop'
+; ONE-NEXT: [003]                 {Code} 'i64.div_s'
+; ONE-NEXT: [003]                 {Code} 'block   	i64'
+; ONE-NEXT: [003]                 {Code} 'nop'
+; ONE-NEXT: [003]                 {Code} 'i64.div_s'
+; ONE-NEXT: [003]                 {Code} 'block   	i64'
+; ONE-NEXT: [003]                 {Code} 'global.get	0'
+; ONE-NEXT: [003]                 {Code} 'local.set	0'
+; ONE-NEXT: [003]                 {Code} 'i64.const	16'
+; ONE-NEXT: [003]                 {Code} 'local.set	1'
+; ONE-NEXT: [003]                 {Code} 'local.get	0'
+; ONE-NEXT: [003]                 {Code} 'local.get	1'
+; ONE-NEXT: [003]                 {Code} 'i64.sub'
+; ONE-NEXT: [003]                 {Code} 'local.set	2'
+; ONE-NEXT: [003]                 {Code} 'local.get	2'
+; ONE-NEXT: [003]                 {Code} 'global.set	0'
+; ONE-NEXT: [003]                 {Code} 'i32.const	0'
+; ONE-NEXT: [003]                 {Code} 'local.set	3'
+; ONE-NEXT: [003]                 {Code} 'local.get	2'
+; ONE-NEXT: [003]                 {Code} 'local.get	3'
+; ONE-NEXT: [003]                 {Code} 'i32.store	12'
+; ONE-NEXT: [003]     5           {Line}
+; ONE-NEXT: [003]                 {Code} 'i64.const	0'
+; ONE-NEXT: [003]                 {Code} 'local.set	4'
+; ONE-NEXT: [003]                 {Code} 'i64.const	0'
+; ONE-NEXT: [003]                 {Code} 'local.set	5'
+; ONE-NEXT: [003]                 {Code} 'local.get	4'
+; ONE-NEXT: [003]                 {Code} 'local.get	5'
+; ONE-NEXT: [003]                 {Code} 'call	0'
+; ONE-NEXT: [003]                 {Code} 'drop'
+; ONE-NEXT: [003]     6           {Line}
+; ONE-NEXT: [003]                 {Code} 'i32.const	0'
+; ONE-NEXT: [003]                 {Code} 'local.set	6'
+; ONE-NEXT: [003]                 {Code} 'i64.const	16'
+; ONE-NEXT: [003]                 {Code} 'local.set	7'
+; ONE-NEXT: [003]                 {Code} 'local.get	2'
+; ONE-NEXT: [003]                 {Code} 'local.get	7'
+; ONE-NEXT: [003]                 {Code} 'i64.add'
+; ONE-NEXT: [003]                 {Code} 'local.set	8'
+; ONE-NEXT: [003]                 {Code} 'local.get	8'
+; ONE-NEXT: [003]                 {Code} 'global.set	0'
+; ONE-NEXT: [003]                 {Code} 'local.get	6'
+; ONE-NEXT: [003]                 {Code} 'return'
+; ONE-NEXT: [003]                 {Code} 'end'
+; ONE-NEXT: [003]     6           {Line}
+; ONE-NEXT: [003]                 {Code} 'return'
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/03-wasm-incorrect-lexical-scope-typedef.test b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/03-wasm-incorrect-lexical-scope-typedef.test
new file mode 100644
index 00000000000000..8902a5168834ab
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/03-wasm-incorrect-lexical-scope-typedef.test
@@ -0,0 +1,132 @@
+; REQUIRES: webassembly-registered-target
+
+; Test case 3 - Incorrect lexical scope for typedef.
+
+; pr-44884.cpp
+;  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 lines 4 and 7 contains 2 typedefs, defined at different lexical
+; scopes.
+
+; The above test is used to illustrates a scope issue found in the
+; Clang compiler.
+; PR44884: https://bugs.llvm.org/show_bug.cgi?id=44884
+; PR44229: https://github.com/llvm/llvm-project/issues/44229
+
+; In the following logical views, we can see that the Clang compiler
+; emits both typedefs at the same lexical scope (3), which is wrong.
+; GCC emit correct lexical scope for both typedefs.
+
+; RUN: llvm-debuginfo-analyzer --attribute=level,format,producer \
+; RUN:                         --output-sort=kind \
+; RUN:                         --print=symbols,types,lines \
+; RUN:                         %p/Inputs/pr-44884-clang.wasm \
+; RUN:                         %p/../DWARF/Inputs/pr-44884-dwarf-gcc.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
+
+; ONE:      Logical View:
+; ONE-NEXT: [000]           {File} 'pr-44884-clang.wasm' -> WASM
+; ONE-EMPTY:
+; ONE-NEXT: [001]             {CompileUnit} 'pr-44884.cpp'
+; ONE-NEXT: [002]               {Producer} 'clang version 19{{.*}}'
+; ONE-NEXT: [002]     1         {Function} extern not_inlined 'bar' -> 'int'
+; ONE-NEXT: [003]     1           {Parameter} 'Input' -> 'float'
+; ONE-NEXT: [003]     1           {Line}
+; ONE-NEXT: [003]     1           {Line}
+; ONE-NEXT: [003]     -           {Line}
+; ONE-NEXT: [003]     1           {Line}
+; ONE-NEXT: [003]     -           {Line}
+; ONE-NEXT: [003]     1           {Line}
+; ONE-NEXT: [003]     1           {Line}
+; ONE-NEXT: [003]     1           {Line}
+; ONE-NEXT: [002]     3         {Function} extern not_inlined 'foo' -> 'unsigned int'
+; ONE-NEXT: [003]                 {Block}
+; ONE-NEXT: [004]     9             {Variable} 'Added' -> 'FLOAT'
+; ONE-NEXT: [004]     9             {Line}
+; ONE-NEXT: [004]     9             {Line}
+; ONE-NEXT: [004]     9             {Line}
+; ONE-NEXT: [004]     9             {Line}
+; ONE-NEXT: [004]     9             {Line}
+; ONE-NEXT: [004]    10             {Line}
+; ONE-NEXT: [004]    10             {Line}
+; ONE-NEXT: [004]    10             {Line}
+; ONE-NEXT: [004]    13             {Line}
+; ONE-NEXT: [003]     3           {Parameter} 'Param' -> 'char'
+; ONE-NEXT: [003]     7           {TypeAlias} 'FLOAT' -> 'float'
+; ONE-NEXT: [003]     4           {TypeAlias} 'INT' -> 'int'
+; ONE-NEXT: [003]     5           {Variable} 'Value' -> 'INT'
+; ONE-NEXT: [003]     3           {Line}
+; ONE-NEXT: [003]     5           {Line}
+; ONE-NEXT: [003]     5           {Line}
+; ONE-NEXT: [003]    13           {Line}
+; ONE-NEXT: [003]    13           {Line}
+; ONE-NEXT: [003]    13           {Line}
+; ONE-NEXT: [003]    13           {Line}
+; ONE-EMPTY:
+; ONE-NEXT: Logical View:
+; ONE-NEXT: [000]           {File} 'pr-44884-dwarf-gcc.o' -> elf64-x86-64
+; ONE-EMPTY:
+; ONE-NEXT: [001]             {CompileUnit} 'pr-44884.cpp'
+; ONE-NEXT: [002]               {Producer} 'GNU C++14 10.3.0 {{.*}}'
+; ONE-NEXT: [002]     1         {Function} extern not_inlined 'bar' -> 'int'
+; ONE-NEXT: [003]     1           {Parameter} 'Input' -> 'float'
+; ONE-NEXT: [003]     1           {Line}
+; ONE-NEXT: [003]     1           {Line}
+; ONE-NEXT: [003]     1           {Line}
+; ONE-NEXT: [002]     3         {Function} extern not_inlined 'foo' -> 'unsigned int'
+; ONE-NEXT: [003]                 {Block}
+; ONE-NEXT: [004]                   {Block}
+; ONE-NEXT: [005]     9               {Variable} 'Added' -> 'FLOAT'
+; ONE-NEXT: [005]     9               {Line}
+; ONE-NEXT: [005]     9               {Line}
+; ONE-NEXT: [005]     9               {Line}
+; ONE-NEXT: [005]    10               {Line}
+; ONE-NEXT: [005]    13               {Line}
+; ONE-NEXT: [004]     7             {TypeAlias} 'FLOAT' -> 'float'
+; ONE-NEXT: [003]     3           {Parameter} 'Param' -> 'char'
+; ONE-NEXT: [003]     4           {TypeAlias} 'INT' -> 'int'
+; ONE-NEXT: [003]     5           {Variable} 'Value' -> 'INT'
+; ONE-NEXT: [003]     3           {Line}
+; ONE-NEXT: [003]     5           {Line}
+; ONE-NEXT: [003]    13           {Line}
+; ONE-NEXT: [003]    14           {Line}
+; ONE-NEXT: [003]    14           {Line}
+
+; Using the selection facilities, we can produce a simple tabular
+; output showing just the logical types that are 'Typedef'.
+
+; RUN: llvm-debuginfo-analyzer --attribute=level,format \
+; RUN:                         --output-sort=name \
+; RUN:                         --select-types=Typedef \
+; RUN:                         --report=list \
+; RUN:                         --print=types \
+; RUN:                         %p/Inputs/pr-44884-clang.wasm \
+; RUN:                         %p/../DWARF/Inputs/pr-44884-dwarf-gcc.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=TWO %s
+
+; TWO:      Logical View:
+; TWO-NEXT: [000]           {File} 'pr-44884-clang.wasm' -> WASM
+; TWO-EMPTY:
+; TWO-NEXT: [001]           {CompileUnit} 'pr-44884.cpp'
+; TWO-NEXT: [003]     7     {TypeAlias} 'FLOAT' -> 'float'
+; TWO-NEXT: [003]     4     {TypeAlias} 'INT' -> 'int'
+; TWO-EMPTY:
+; TWO-NEXT: Logical View:
+; TWO-NEXT: [000]           {File} 'pr-44884-dwarf-gcc.o' -> elf64-x86-64
+; TWO-EMPTY:
+; TWO-NEXT: [001]           {CompileUnit} 'pr-44884.cpp'
+; TWO-NEXT: [004]     7     {TypeAlias} 'FLOAT' -> 'float'
+; TWO-NEXT: [003]     4     {TypeAlias} 'INT' -> 'int'
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/04-wasm-missing-nested-enumerators.test b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/04-wasm-missing-nested-enumerators.test
new file mode 100644
index 00000000000000..cdcb7d45460331
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/04-wasm-missing-nested-enumerators.test
@@ -0,0 +1,127 @@
+; REQUIRES: webassembly-registered-target
+
+; Test case 4 - Missing nested enumerations.
+
+; pr-46466.cpp
+;   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: https://bugs.llvm.org/show_bug.cgi?id=46466
+; PR45811: https://github.com/llvm/llvm-project/issues/45811
+
+; In the following 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, does include such references.
+
+; RUN: llvm-debuginfo-analyzer --attribute=level,format,producer \
+; RUN:                         --output-sort=name \
+; RUN:                         --print=symbols,types \
+; RUN:                         %p/Inputs/pr-46466-clang.wasm \
+; RUN:                         %p/../DWARF/Inputs/pr-46466-dwarf-gcc.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
+
+; ONE:      Logical View:
+; ONE-NEXT: [000]           {File} 'pr-46466-clang.wasm' -> WASM
+; ONE-EMPTY:
+; ONE-NEXT: [001]             {CompileUnit} 'pr-46466.cpp'
+; ONE-NEXT: [002]               {Producer} 'clang version 19{{.*}}'
+; ONE-NEXT: [002]     8         {Variable} extern 'S' -> 'Struct'
+; ONE-NEXT: [002]     1         {Struct} 'Struct'
+; ONE-NEXT: [003]     5           {Member} public 'U' -> 'Union'
+; ONE-EMPTY:
+; ONE-NEXT: Logical View:
+; ONE-NEXT: [000]           {File} 'pr-46466-dwarf-gcc.o' -> elf64-x86-64
+; ONE-EMPTY:
+; ONE-NEXT: [001]             {CompileUnit} 'pr-46466.cpp'
+; ONE-NEXT: [002]               {Producer} 'GNU C++14 10.3.0 {{.*}}'
+; ONE-NEXT: [002]     8         {Variable} extern 'S' -> 'Struct'
+; ONE-NEXT: [002]     1         {Struct} 'Struct'
+; ONE-NEXT: [003]     5           {Member} public 'U' -> 'Union'
+; ONE-NEXT: [003]     2           {Union} 'Union'
+; ONE-NEXT: [004]     3             {Enumeration} 'NestedEnum' -> 'unsigned int'
+; ONE-NEXT: [005]                     {Enumerator} 'BLUE' = '0x1'
+; ONE-NEXT: [005]                     {Enumerator} 'RED' = '0x0'
+
+; Using the 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.
+
+; RUN: llvm-debuginfo-analyzer --attribute=level,format \
+; RUN:                         --output-sort=name \
+; RUN:                         --select-types=Enumerator \
+; RUN:                         --report=parents \
+; RUN:                         --print=types \
+; RUN:                         %p/Inputs/pr-46466-clang.wasm \
+; RUN:                         %p/../DWARF/Inputs/pr-46466-dwarf-gcc.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=TWO %s
+
+; TWO:      Logical View:
+; TWO-NEXT: [000]           {File} 'pr-46466-clang.wasm' -> WASM
+; TWO-EMPTY:
+; TWO-NEXT: [001]             {CompileUnit} 'pr-46466.cpp'
+; TWO-EMPTY:
+; TWO-NEXT: Logical View:
+; TWO-NEXT: [000]           {File} 'pr-46466-dwarf-gcc.o' -> elf64-x86-64
+; TWO-EMPTY:
+; TWO-NEXT: [001]             {CompileUnit} 'pr-46466.cpp'
+; TWO-NEXT: [002]     1         {Struct} 'Struct'
+; TWO-NEXT: [003]     2           {Union} 'Union'
+; TWO-NEXT: [004]     3             {Enumeration} 'NestedEnum' -> 'unsigned int'
+; TWO-NEXT: [005]                     {Enumerator} 'BLUE' = '0x1'
+; TWO-NEXT: [005]                     {Enumerator} 'RED' = '0x0'
+
+; Using the 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.
+
+; RUN: llvm-debuginfo-analyzer --attribute=level,format \
+; RUN:                         --output-sort=name \
+; RUN:                         --select-types=Enumerator \
+; RUN:                         --print=types,summary \
+; RUN:                         %p/Inputs/pr-46466-clang.wasm \
+; RUN:                         %p/../DWARF/Inputs/pr-46466-dwarf-gcc.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=THR %s
+
+; THR:      Logical View:
+; THR-NEXT: [000]           {File} 'pr-46466-clang.wasm' -> WASM
+; THR-EMPTY:
+; THR-NEXT: [001]           {CompileUnit} 'pr-46466.cpp'
+; THR-EMPTY:
+; THR-NEXT: -----------------------------
+; THR-NEXT: Element      Total    Printed
+; THR-NEXT: -----------------------------
+; THR-NEXT: Scopes           4          0
+; THR-NEXT: Symbols          0          0
+; THR-NEXT: Types            0          0
+; THR-NEXT: Lines            0          0
+; THR-NEXT: -----------------------------
+; THR-NEXT: Total            4          0
+; THR-EMPTY:
+; THR-NEXT: Logical View:
+; THR-NEXT: [000]           {File} 'pr-46466-dwarf-gcc.o' -> elf64-x86-64
+; THR-EMPTY:
+; THR-NEXT: [001]           {CompileUnit} 'pr-46466.cpp'
+; THR-NEXT: [005]           {Enumerator} 'BLUE' = '0x1'
+; THR-NEXT: [005]           {Enumerator} 'RED' = '0x0'
+; THR-EMPTY:
+; THR-NEXT: -----------------------------
+; THR-NEXT: Element      Total    Printed
+; THR-NEXT: -----------------------------
+; THR-NEXT: Scopes           5          0
+; THR-NEXT: Symbols          0          0
+; THR-NEXT: Types            2          2
+; THR-NEXT: Lines            0          0
+; THR-NEXT: -----------------------------
+; THR-NEXT: Total            7          2
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/05-wasm-incorrect-lexical-scope-variable.test b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/05-wasm-incorrect-lexical-scope-variable.test
new file mode 100644
index 00000000000000..fac3bacffcc405
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/05-wasm-incorrect-lexical-scope-variable.test
@@ -0,0 +1,111 @@
+; REQUIRES: webassembly-registered-target
+
+; Test case 5 - Incorrect lexical scope variable.
+
+; pr-43860.cpp
+;  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: https://bugs.llvm.org/show_bug.cgi?id=43860
+; PR43205: https://github.com/llvm/llvm-project/issues/43205
+
+; In the following logical views, we can see that the DWARF 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 show those variables at the correct
+; lexical scope: '3' and '4' respectively.
+
+; RUN: llvm-debuginfo-analyzer --attribute=level,format,producer \
+; RUN:                         --output-sort=name \
+; RUN:                         --print=symbols \
+; RUN:                         %p/Inputs/pr-43860-clang.wasm \
+; RUN:                         %p/../DWARF/Inputs/pr-43860-dwarf-gcc.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
+
+; ONE:      Logical View:
+; ONE-NEXT: [000]           {File} 'pr-43860-clang.wasm' -> WASM
+; ONE-EMPTY:
+; ONE-NEXT: [001]             {CompileUnit} 'pr-43860.cpp'
+; ONE-NEXT: [002]               {Producer} 'clang version 19{{.*}}'
+; ONE-NEXT: [002]     2         {Function} extern inlined 'InlineFunction' -> 'int'
+; ONE-NEXT: [003]                 {Block}
+; ONE-NEXT: [004]     5             {Variable} 'Var_2' -> 'int'
+; ONE-NEXT: [003]     2           {Parameter} 'Param' -> 'int'
+; ONE-NEXT: [003]     3           {Variable} 'Var_1' -> 'int'
+; ONE-NEXT: [002]    11         {Function} extern not_inlined 'test' -> 'int'
+; ONE-NEXT: [003]    12           {Variable} 'A' -> 'int'
+; ONE-NEXT: [003]    13           {InlinedFunction} inlined 'InlineFunction' -> 'int'
+; ONE-NEXT: [004]                   {Block}
+; ONE-NEXT: [005]                     {Variable} 'Var_2' -> 'int'
+; ONE-NEXT: [004]                   {Parameter} 'Param' -> 'int'
+; ONE-NEXT: [004]                   {Variable} 'Var_1' -> 'int'
+; ONE-NEXT: [003]    11           {Parameter} 'Param_1' -> 'int'
+; ONE-NEXT: [003]    11           {Parameter} 'Param_2' -> 'int'
+; ONE-EMPTY:
+; ONE-NEXT: Logical View:
+; ONE-NEXT: [000]           {File} 'pr-43860-dwarf-gcc.o' -> elf64-x86-64
+; ONE-EMPTY:
+; ONE-NEXT: [001]             {CompileUnit} 'pr-43860.cpp'
+; ONE-NEXT: [002]               {Producer} 'GNU C++14 10.3.0 {{.*}}'
+; ONE-NEXT: [002]     2         {Function} extern declared_inlined 'InlineFunction' -> 'int'
+; ONE-NEXT: [003]                 {Block}
+; ONE-NEXT: [004]     5             {Variable} 'Var_2' -> 'int'
+; ONE-NEXT: [003]     2           {Parameter} 'Param' -> 'int'
+; ONE-NEXT: [003]     3           {Variable} 'Var_1' -> 'int'
+; ONE-NEXT: [002]    11         {Function} extern not_inlined 'test' -> 'int'
+; ONE-NEXT: [003]    12           {Variable} 'A' -> 'int'
+; ONE-NEXT: [003]    13           {InlinedFunction} declared_inlined 'InlineFunction' -> 'int'
+; ONE-NEXT: [004]                   {Block}
+; ONE-NEXT: [005]                     {Variable} 'Var_2' -> 'int'
+; ONE-NEXT: [004]                   {Parameter} 'Param' -> 'int'
+; ONE-NEXT: [004]                   {Variable} 'Var_1' -> 'int'
+; ONE-NEXT: [003]    11           {Parameter} 'Param_1' -> 'int'
+; ONE-NEXT: [003]    11           {Parameter} 'Param_2' -> 'int'
+
+; Using the 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.
+
+; RUN: llvm-debuginfo-analyzer --attribute=level,format \
+; RUN:                         --output-sort=name \
+; RUN:                         --select-regex --select-nocase \
+; RUN:                         --select=Var \
+; RUN:                         --report=list \
+; RUN:                         --print=symbols \
+; RUN:                         %p/Inputs/pr-43860-clang.wasm \
+; RUN:                         %p/../DWARF/Inputs/pr-43860-dwarf-gcc.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=TWO %s
+
+; TWO:      Logical View:
+; TWO-NEXT: [000]           {File} 'pr-43860-clang.wasm' -> WASM
+; TWO-EMPTY:
+; TWO-NEXT: [001]           {CompileUnit} 'pr-43860.cpp'
+; TWO-NEXT: [004]           {Variable} 'Var_1' -> 'int'
+; TWO-NEXT: [003]     3     {Variable} 'Var_1' -> 'int'
+; TWO-NEXT: [005]           {Variable} 'Var_2' -> 'int'
+; TWO-NEXT: [004]     5     {Variable} 'Var_2' -> 'int'
+; TWO-EMPTY:
+; TWO-NEXT: Logical View:
+; TWO-NEXT: [000]           {File} 'pr-43860-dwarf-gcc.o' -> elf64-x86-64
+; TWO-EMPTY:
+; TWO-NEXT: [001]           {CompileUnit} 'pr-43860.cpp'
+; TWO-NEXT: [004]           {Variable} 'Var_1' -> 'int'
+; TWO-NEXT: [003]     3     {Variable} 'Var_1' -> 'int'
+; TWO-NEXT: [005]           {Variable} 'Var_2' -> 'int'
+; TWO-NEXT: [004]     5     {Variable} 'Var_2' -> 'int'
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/06-wasm-full-logical-view.test b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/06-wasm-full-logical-view.test
new file mode 100644
index 00000000000000..9f4c95eea093f6
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/06-wasm-full-logical-view.test
@@ -0,0 +1,155 @@
+; REQUIRES: webassembly-registered-target
+
+; Test case 6 - Full logical view
+
+; test.cpp
+;  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 low level details.
+; The following command prints low level information that includes
+; offsets within the debug information section, debug location
+; operands, linkage names, etc.
+
+; RUN: llvm-debuginfo-analyzer --attribute=all \
+; RUN:                         --print=all \
+; RUN:                         %p/Inputs/test-clang.wasm 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
+
+; ONE:      Logical View:
+; ONE-NEXT: [0x0000000000][000]            {File} '{{.*}}test-clang.wasm' -> WASM
+; ONE-EMPTY:
+; ONE-NEXT: [0x000000000b][001]              {CompileUnit} 'test.cpp'
+; ONE-NEXT: [0x000000000b][002]                {Producer} 'clang version 19{{.*}}'
+; ONE-NEXT:                                    {Directory} '{{.*}}/general'
+; ONE-NEXT:                                    {File} 'test.cpp'
+; ONE-NEXT:                                    {Public} 'foo' [0x0000000002:0x0000000081]
+; ONE-NEXT: [0x000000000b][002]                {Range} Lines 2:9 [0x0000000002:0x0000000081]
+; ONE-NEXT: [0x00000000bf][002]                {BaseType} 'bool'
+; ONE-NEXT: [0x000000009c][002]                {BaseType} 'int'
+; ONE-NEXT: [0x00000000b8][002]                {BaseType} 'unsigned int'
+; ONE-EMPTY:
+; ONE-NEXT: [0x00000000a3][002]   {Source} '{{.*}}/general/test.cpp'
+; ONE-NEXT: [0x00000000a3][002]      1         {TypeAlias} 'INTPTR' -> [0x00000000ae]'* const int'
+; ONE-NEXT: [0x000000002a][002]      2         {Function} extern not_inlined 'foo' -> [0x000000009c]'int'
+; ONE-NEXT: [0x000000002a][003]                  {Range} Lines 2:9 [0x0000000002:0x0000000081]
+; ONE-NEXT: [0x000000002a][003]                  {Linkage}  0x3 '_Z3fooPKijb'
+; ONE-NEXT: [0x0000000074][003]                  {Block}
+; ONE-NEXT: [0x0000000074][004]                    {Range} Lines 5:0 [0x000000004e:0x0000000066]
+; ONE-NEXT: [0x0000000081][004]      5             {Variable} 'CONSTANT' -> [0x00000000c6]'const INTEGER'
+; ONE-NEXT: [0x0000000081][005]                      {Coverage} 100.00%
+; ONE-NEXT: [0x0000000082][005]                      {Location}
+; ONE-NEXT: [0x0000000082][006]                        {Entry} fbreg 4
+; ONE-NEXT: [0x000000004e][004]      5             {Line} {NewStatement} '{{.*}}/general/test.cpp'
+; ONE-NEXT: [0x000000004e][004]                    {Code} 'i32.const	7'
+; ONE-NEXT: [0x0000000050][004]                    {Code} 'local.set	10'
+; ONE-NEXT: [0x0000000052][004]                    {Code} 'local.get	5'
+; ONE-NEXT: [0x0000000054][004]                    {Code} 'local.get	10'
+; ONE-NEXT: [0x0000000056][004]                    {Code} 'i32.store	4'
+; ONE-NEXT: [0x0000000059][004]      6             {Line} {NewStatement} '{{.*}}/general/test.cpp'
+; ONE-NEXT: [0x0000000059][004]                    {Code} 'i32.const	7'
+; ONE-NEXT: [0x000000005b][004]                    {Code} 'local.set	11'
+; ONE-NEXT: [0x000000005d][004]                    {Code} 'local.get	5'
+; ONE-NEXT: [0x000000005f][004]                    {Code} 'local.get	11'
+; ONE-NEXT: [0x0000000061][004]                    {Code} 'i32.store	28'
+; ONE-NEXT: [0x0000000064][004]                    {Code} 'br      	1'
+; ONE-NEXT: [0x0000000066][004]      0             {Line} '{{.*}}/general/test.cpp'
+; ONE-NEXT: [0x0000000066][004]                    {Code} 'end'
+; ONE-NEXT: [0x0000000066][003]      2           {Parameter} 'ParamBool' -> [0x00000000bf]'bool'
+; ONE-NEXT: [0x0000000066][004]                    {Coverage} 100.00%
+; ONE-NEXT: [0x0000000067][004]                    {Location}
+; ONE-NEXT: [0x0000000067][005]                      {Entry} fbreg 11
+; ONE-NEXT: [0x000000004a][003]      2           {Parameter} 'ParamPtr' -> [0x00000000a3]'INTPTR'
+; ONE-NEXT: [0x000000004a][004]                    {Coverage} 100.00%
+; ONE-NEXT: [0x000000004b][004]                    {Location}
+; ONE-NEXT: [0x000000004b][005]                      {Entry} fbreg 16
+; ONE-NEXT: [0x0000000058][003]      2           {Parameter} 'ParamUnsigned' -> [0x00000000b8]'unsigned int'
+; ONE-NEXT: [0x0000000058][004]                    {Coverage} 100.00%
+; ONE-NEXT: [0x0000000059][004]                    {Location}
+; ONE-NEXT: [0x0000000059][005]                      {Entry} fbreg 12
+; ONE-NEXT: [0x0000000090][003]      4           {TypeAlias} 'INTEGER' -> [0x000000009c]'int'
+; ONE-NEXT: [0x0000000002][003]      2           {Line} {NewStatement} '{{.*}}/general/test.cpp'
+; ONE-NEXT: [0x0000000002][003]                  {Code} 'block   	unknown_type'
+; ONE-NEXT: [0x0000000004][003]                  {Code} 'i64.mul'
+; ONE-NEXT: [0x0000000005][003]                  {Code} 'throw   	127'
+; ONE-NEXT: [0x0000000007][003]                  {Code} 'global.get	0'
+; ONE-NEXT: [0x000000000d][003]                  {Code} 'local.set	3'
+; ONE-NEXT: [0x000000000f][003]                  {Code} 'i64.const	32'
+; ONE-NEXT: [0x0000000011][003]                  {Code} 'local.set	4'
+; ONE-NEXT: [0x0000000013][003]                  {Code} 'local.get	3'
+; ONE-NEXT: [0x0000000015][003]                  {Code} 'local.get	4'
+; ONE-NEXT: [0x0000000017][003]                  {Code} 'i64.sub'
+; ONE-NEXT: [0x0000000018][003]                  {Code} 'local.set	5'
+; ONE-NEXT: [0x000000001a][003]                  {Code} 'local.get	5'
+; ONE-NEXT: [0x000000001c][003]                  {Code} 'local.get	0'
+; ONE-NEXT: [0x000000001e][003]                  {Code} 'i64.store	16'
+; ONE-NEXT: [0x0000000021][003]                  {Code} 'local.get	5'
+; ONE-NEXT: [0x0000000023][003]                  {Code} 'local.get	1'
+; ONE-NEXT: [0x0000000025][003]                  {Code} 'i32.store	12'
+; ONE-NEXT: [0x0000000028][003]                  {Code} 'local.get	2'
+; ONE-NEXT: [0x000000002a][003]                  {Code} 'local.set	6'
+; ONE-NEXT: [0x000000002c][003]                  {Code} 'local.get	5'
+; ONE-NEXT: [0x000000002e][003]                  {Code} 'local.get	6'
+; ONE-NEXT: [0x0000000030][003]                  {Code} 'i32.store8	11'
+; ONE-NEXT: [0x0000000033][003]      3           {Line} {NewStatement} {PrologueEnd} '{{.*}}/general/test.cpp'
+; ONE-NEXT: [0x0000000033][003]                  {Code} 'local.get	5'
+; ONE-NEXT: [0x0000000035][003]                  {Code} 'i32.load8_u	11'
+; ONE-NEXT: [0x0000000038][003]                  {Code} 'local.set	7'
+; ONE-NEXT: [0x000000003a][003]      3           {Line} '{{.*}}/general/test.cpp'
+; ONE-NEXT: [0x000000003a][003]                  {Code} 'i32.const	1'
+; ONE-NEXT: [0x000000003c][003]                  {Code} 'local.set	8'
+; ONE-NEXT: [0x000000003e][003]                  {Code} 'local.get	7'
+; ONE-NEXT: [0x0000000040][003]                  {Code} 'local.get	8'
+; ONE-NEXT: [0x0000000042][003]                  {Code} 'i32.and'
+; ONE-NEXT: [0x0000000043][003]                  {Code} 'local.set	9'
+; ONE-NEXT: [0x0000000045][003]                  {Code} 'block'
+; ONE-NEXT: [0x0000000047][003]                  {Code} 'block'
+; ONE-NEXT: [0x0000000049][003]                  {Code} 'local.get	9'
+; ONE-NEXT: [0x000000004b][003]                  {Code} 'i32.eqz'
+; ONE-NEXT: [0x000000004c][003]                  {Code} 'br_if   	0'
+; ONE-NEXT: [0x0000000067][003]      8           {Line} {NewStatement} '{{.*}}/general/test.cpp'
+; ONE-NEXT: [0x0000000067][003]                  {Code} 'local.get	5'
+; ONE-NEXT: [0x0000000069][003]                  {Code} 'i32.load	12'
+; ONE-NEXT: [0x000000006c][003]                  {Code} 'local.set	12'
+; ONE-NEXT: [0x000000006e][003]      8           {Line} '{{.*}}/general/test.cpp'
+; ONE-NEXT: [0x000000006e][003]                  {Code} 'local.get	5'
+; ONE-NEXT: [0x0000000070][003]                  {Code} 'local.get	12'
+; ONE-NEXT: [0x0000000072][003]                  {Code} 'i32.store	28'
+; ONE-NEXT: [0x0000000075][003]      0           {Line} '{{.*}}/general/test.cpp'
+; ONE-NEXT: [0x0000000075][003]                  {Code} 'end'
+; ONE-NEXT: [0x0000000076][003]      9           {Line} {NewStatement} '{{.*}}/general/test.cpp'
+; ONE-NEXT: [0x0000000076][003]                  {Code} 'local.get	5'
+; ONE-NEXT: [0x0000000078][003]                  {Code} 'i32.load	28'
+; ONE-NEXT: [0x000000007b][003]                  {Code} 'local.set	13'
+; ONE-NEXT: [0x000000007d][003]                  {Code} 'local.get	13'
+; ONE-NEXT: [0x000000007f][003]                  {Code} 'return'
+; ONE-NEXT: [0x0000000080][003]                  {Code} 'end'
+; ONE-NEXT: [0x0000000081][003]      9           {Line} {NewStatement} {EndSequence} '{{.*}}/general/test.cpp'
+; ONE-NEXT: [0x0000000081][003]                  {Code} 'unreachable'
+; ONE-EMPTY:
+; ONE-NEXT: -----------------------------
+; ONE-NEXT: Element      Total    Printed
+; ONE-NEXT: -----------------------------
+; ONE-NEXT: Scopes           3          3
+; ONE-NEXT: Symbols          4          4
+; ONE-NEXT: Types            5          5
+; ONE-NEXT: Lines           73         73
+; ONE-NEXT: -----------------------------
+; ONE-NEXT: Total           85         85
+; ONE-EMPTY:
+; ONE-NEXT: Scope Sizes:
+; ONE-NEXT:        192 (100.00%) : [0x000000000b][001]              {CompileUnit} 'test.cpp'
+; ONE-NEXT:        113 ( 58.85%) : [0x000000002a][002]      2         {Function} extern not_inlined 'foo' -> [0x000000009c]'int'
+; ONE-NEXT:         27 ( 14.06%) : [0x0000000074][003]                  {Block}
+; ONE-EMPTY:
+; ONE-NEXT: Totals by lexical level:
+; ONE-NEXT: [001]:        192 (100.00%)
+; ONE-NEXT: [002]:        113 ( 58.85%)
+; ONE-NEXT: [003]:         27 ( 14.06%)
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/definitions.h b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/definitions.h
new file mode 100644
index 00000000000000..dfbd3db044dd80
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/definitions.h
@@ -0,0 +1,30 @@
+//-----------------------------------------------------------------------------
+// Definitions.
+//-----------------------------------------------------------------------------
+#ifndef SUITE_DEFINITIONS_H
+#define SUITE_DEFINITIONS_H
+
+#ifdef _MSC_VER
+#define forceinline __forceinline
+#define OPTIMIZE_OFF __pragma(optimize("", off))
+#define OPTIMIZE_ON  __pragma(optimize("", on))
+#elif defined(__clang__)
+#if __has_attribute(__always_inline__)
+#define forceinline inline __attribute__((__always_inline__))
+#else
+#define forceinline inline
+#endif
+#define OPTIMIZE_OFF _Pragma("clang optimize off")
+#define OPTIMIZE_ON  _Pragma("clang optimize on")
+#elif defined(__GNUC__)
+#define forceinline inline __attribute__((__always_inline__))
+#define OPTIMIZE_OFF _Pragma("GCC optimize off")
+#define OPTIMIZE_ON  _Pragma("GCC optimize on")
+#else
+#define forceinline inline
+#define OPTIMIZE_OFF
+#define OPTIMIZE_ON
+#error
+#endif
+
+#endif // SUITE_DEFINITIONS_H
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/hello-world-clang.wasm b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/hello-world-clang.wasm
new file mode 100644
index 0000000000000000000000000000000000000000..a4f21dd31de18f5c4236dedfe31961fda23d773a
GIT binary patch
literal 1414
zcmc&!&5zqe6n`_eV>`||*+wk=kdULcd}xWYyJVByRx0e41tMCp>Q+K62Y2F398<@(
z#&*h9upi>aZ4n1<@CU$^KY>c9XU at Isu?HkhaN&(Nl`8cQz>?p4^PBfI at 4Xpd*^~eP
zIXOBy0_6da!w2->K+;2`^i;yC!sA)p^P({3On6g1O~gJ`$sEpd=0Eh(B#d(|l!Fpp
z at b33gfyj9GQ~xoP*agoE<54KMpL^pX_VX}_y_^jrPEr8nTN#Q1tsP5&RR1a06Ae8c
z((=EI$Pu()yU`*JIOLlab?B86+=7<kP)F&}+O`DB4_fLrv@}O`w1x!WBC1u;T1Qp=
z>z3gdXVy-oZq*4nY?Ps;*Scl>AT0=NgJplhqbPaT`8*NPs0#3x+*xo(d{_h?8x94Z
zkwtRVZfc6%c>R*SNX}INXcq>}Yu0s(p2yP>GH3#*EyVg3fc7Q|0F^7C*f%T-5nYOw
zbpu7i1?l30^NKC)2hH~{V2j{8%nq!1*f1U^j}cVm4j8hBSeawV at H@eumJ+~3%GZ$)
z%~a+XC?BJw?jf;3yM?UsL=vJuMP}&6%f{++pg%oBoG3G?bc#g7xPQxhs`GrZT=)@-
z182rXhK+SrH{BI?B?xop?Ma at e*|kmw7n5S>W+8X8B;I%ZWZKyq?6h}9IAb~Q_-WD3
zlO*ydER5S}DqLy4xxrS}x?R>?ANTm?#;7;)*VcU2 at At=D)*r63^$os($U88RZE8P~
zU2^?2h0ciOtdol5OB}hZlldY{kqaIOp2;NJSrKB~FiwlS6Y!V|76C>V;CWkj?rh!j
z_6GNNyu0^ycRUZKm=)ki1N<om;6*3ot at sE_qQYCUMuhxpFGyBiD+FFi3$*}D`l7_I
zX-bu at HjQ8DB{YNQ(zlLIABJ&2jo;<c1eM_ZOGFriF^fEz32gwO75A2lm6u&?U<Onz
zb5x1tl{(%m2}cU8DAZ7>seLbf5!)4sEQ~w1CGfMvtAa;~@810E!yUDv+eE)i>Rrrn
zpy-T10`P~_T0GNwX$bY2S*d_o)4 at Ea9}{!Q0P~`LLYCeDXuL<kysbYW=3V_MS^5Hx
z9qG at A`A9z{@Z+ogWGPLu)W!PzB8SVw-i-<$CyE+!xC$0<V&C-AsL0O9Y8Ps#<YPbi
zs6E^#S~-Q{f0(}C<az2j69LEfjkCPKDN~l~)1rLi+Ch{IS(GgsSs27^{#CwgoV}#I
F?tgDnWN`oh

literal 0
HcmV?d00001

diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/hello-world-clang.wat b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/hello-world-clang.wat
new file mode 100644
index 00000000000000..a79cd8749a5fb6
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/hello-world-clang.wat
@@ -0,0 +1,52 @@
+(module
+  (type (;0;) (func (result i32)))
+  (type (;1;) (func (param i64 i64) (result i32)))
+  (type (;2;) (func (param i32 i64) (result i32)))
+  (import "env" "__linear_memory" (memory (;0;) i64 1))
+  (import "env" "__stack_pointer" (global (;0;) (mut i64)))
+  (import "env" "_Z6printfPKcz" (func (;0;) (type 1)))
+  (import "env" "__indirect_function_table" (table (;0;) 0 funcref))
+  (func $__original_main (type 0) (result i32)
+    (local i64 i64 i64 i32 i64 i64 i32 i64 i64)
+    global.get 0
+    local.set 0
+    i64.const 16
+    local.set 1
+    local.get 0
+    local.get 1
+    i64.sub
+    local.set 2
+    local.get 2
+    global.set 0
+    i32.const 0
+    local.set 3
+    local.get 2
+    local.get 3
+    i32.store offset=12
+    i64.const 0
+    local.set 4
+    i64.const 0
+    local.set 5
+    local.get 4
+    local.get 5
+    call 0
+    drop
+    i32.const 0
+    local.set 6
+    i64.const 16
+    local.set 7
+    local.get 2
+    local.get 7
+    i64.add
+    local.set 8
+    local.get 8
+    global.set 0
+    local.get 6
+    return)
+  (func $main (type 2) (param i32 i64) (result i32)
+    (local i32)
+    call $__original_main
+    local.set 2
+    local.get 2
+    return)
+  (data $.L.str (i64.const 0) "Hello, World\0a\00"))
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/hello-world.cpp b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/hello-world.cpp
new file mode 100644
index 00000000000000..73a8e247e26ec3
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/hello-world.cpp
@@ -0,0 +1,7 @@
+extern int printf(const char * format, ... );
+
+int main()
+{
+  printf("Hello, World\n");
+  return 0;
+}
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/pr-43860-clang.wasm b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/pr-43860-clang.wasm
new file mode 100644
index 0000000000000000000000000000000000000000..da9355b3ad7dc71ce16f601bcc29b4f4ee7cba5b
GIT binary patch
literal 1613
zcmc&#TZ<e;6h2keJ=2%D?2XApSLwzm(Pese*527mz^HKpOCF2{ygfMf^wiGwW~RI8
zt{z>)?5-~%Ai)Je5kUg_5D at YrK8xfB<Uu6=AVTmVPYFoCQ at xvY7Jq;Zb*jGae0{1;
z)v0dq(jfr=a&>oi7sy9+XNT<2TM|&l!%?-<83ZBslFpD1qhy;Za7d at Z^DlSeC<p~l
z*cHM)&m(~G!=8+EgHU$G+<6YkU9jovmdz|`vCnM9QY>iG3G7IlmMrBoov>9zYMW{j
zmFxndLYvM?G;0?T72C9afO1LQ)-BD_w`>D_Mw`w^-;8Y{G7pt?I}fedWvgtJw(JV}
zDu**@cGap at P54!=wCwbFH|ux2Za3j0GD)7VOslLiapLL9B$+AzP=|ySR#`RAnCsJL
zPg*7bQ{f2#ptxf|HE}l!r;vHYG*MY}Fyd6<)%th{08Is2|2Ks09)rd+q%|#Hd(V8|
zd>5mbQr?;dC`q9ll+8RYo*X=qS(t}e1mQ;XCz6WvfF_R?Y}k_>KG(6ad<1X<dwLtq
zU2KGYC at s5xG*%wugrrsFp&YAnjLF?YqbkMmILcq3eE%5vB2Gw5Db(oxL}?tAW{!|f
z_qADxN>XXOgk}w!e9mGcWzD4fv#U5P(fzt~l`o- at kJKVL^Hz?~+{Cg2<1qVFB>un)
z`__mjX%K~0YsHy&=KF!LPHzekr>o5-g3YY!qycx*DBO1ZXxO~8zSg*y1S3!IrXObw
z5k&)k(+k2z94C%^eP!93UvOQ|UEFB%mE~T$=PxYy-qO<2hU+bL7rn)0zKqO^5GM`y
z<>mIg<Hs>Hd!F!`aT0BDU!={{Pl6cxg!dDk$`v-!EWk;FFwR7?&qJPg1L%Cva at Rw7
z at 6KnTFHjc1aSV9t;G&m!LwE=8W-GS~_ at XO#DuMuHcOXD#F6=D8YXH~Ai$%_`jeDrT
zDYS%;zbj?g;n9FRp5wV7382#_=gthGng)GgS}hiYdZLi2RW|w~2a|=7dQy@?)rDF{
zmx;(gR^3(&?Sje*0zV`;&rSJtDB?OU2VtLT-%6<Bdi0}A=mapTFj`==2wzISk?=v}
zJLlefV~vrbPT-MbClA=MYoN~P1qynJfj-6dh+f06PqFKy_AI6`$8Hn7$?g*U47*SC
z^Xvi9-)0Yq-eLDhZ37h_v&TgLlwGCzHNw82`qzYgMfD#E`;OLrCh!~7ekX7T;G6%>
zF88%aYAxKapX7e)SOC4u$C{*?EYHmAb5c3ii3eGFU|KGeP~>A#@Lr?4P1L-OlmDT9
xf06lAg_rcX=xlILWLT<ft~$(w*B$Uie-L%OK{}_UK|gHpPsE&d at M~zh{{VKhUE2Tv

literal 0
HcmV?d00001

diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/pr-43860-clang.wat b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/pr-43860-clang.wat
new file mode 100644
index 00000000000000..4461a5844667c9
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/pr-43860-clang.wat
@@ -0,0 +1,75 @@
+(module
+  (type (;0;) (func (param i32 i32) (result i32)))
+  (import "env" "__linear_memory" (memory (;0;) i64 0))
+  (import "env" "__stack_pointer" (global (;0;) (mut i64)))
+  (func $_Z4testii (type 0) (param i32 i32) (result i32)
+    (local i64 i64 i64 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32)
+    global.get 0
+    local.set 2
+    i64.const 32
+    local.set 3
+    local.get 2
+    local.get 3
+    i64.sub
+    local.set 4
+    local.get 4
+    local.get 0
+    i32.store offset=16
+    local.get 4
+    local.get 1
+    i32.store offset=12
+    local.get 4
+    i32.load offset=16
+    local.set 5
+    local.get 4
+    local.get 5
+    i32.store offset=8
+    local.get 4
+    i32.load offset=12
+    local.set 6
+    local.get 4
+    local.get 6
+    i32.store offset=28
+    local.get 4
+    i32.load offset=28
+    local.set 7
+    local.get 4
+    local.get 7
+    i32.store offset=24
+    local.get 4
+    i32.load offset=28
+    local.set 8
+    local.get 4
+    i32.load offset=24
+    local.set 9
+    local.get 8
+    local.get 9
+    i32.add
+    local.set 10
+    local.get 4
+    local.get 10
+    i32.store offset=20
+    local.get 4
+    i32.load offset=20
+    local.set 11
+    local.get 4
+    local.get 11
+    i32.store offset=24
+    local.get 4
+    i32.load offset=24
+    local.set 12
+    local.get 4
+    i32.load offset=8
+    local.set 13
+    local.get 13
+    local.get 12
+    i32.add
+    local.set 14
+    local.get 4
+    local.get 14
+    i32.store offset=8
+    local.get 4
+    i32.load offset=8
+    local.set 15
+    local.get 15
+    return))
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/pr-43860.cpp b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/pr-43860.cpp
new file mode 100644
index 00000000000000..a3d3b76c59e586
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/pr-43860.cpp
@@ -0,0 +1,15 @@
+#include "definitions.h"
+forceinline int InlineFunction(int Param) {
+  int Var_1 = Param;
+  {
+    int Var_2 = Param + Var_1;
+    Var_1 = Var_2;
+  }
+  return Var_1;
+}
+
+int test(int Param_1, int Param_2) {
+  int A = Param_1;
+  A += InlineFunction(Param_2);
+  return A;
+}
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/pr-44884-clang.wasm b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/pr-44884-clang.wasm
new file mode 100644
index 0000000000000000000000000000000000000000..ef8d5f69ee9980623dbb98192c58f5fd9676da44
GIT binary patch
literal 1882
zcmc%~ONbmr^i@??cURAMcQ&)5L8!)6VwRan*2(T9f at WQ#tcr=4hzK(2>FJ$xGSf5k
zXU&59Nz5sMg#?d&Ku~f}1VPb&UXnvDVh$l*qQs+z95e?F9^$K+-H?UcE$H|E)vNbr
zz=^s90LZzuwKbqe$ue0zN><4#{c0d!Ua**JG&+9ZIboygb$j6w)nG#$#g2QT(eL>|
z?1gNFu=fW}K&;EBRXCrq6}GIeK91rwu*vgzn at S?-vdtuuP^W3hcG9%1N$s4?=dg~0
zwl2BU-?0s89I#EgpYE4t2Bdb;7E;(&nxtk`u#<L5rfe%EEjumKxzr89*^0GFmyK1r
z^3Ze>gBn!YeUOu^3^`kyE!kXZlE;`8^Cp;;Nn at ItlI@_TjYydZG_$0TR;-drE5Vee
zOdq#1GV`^aMVD-yYU(DMos+rzAd#I%dH#N=kzuG&3{{Y$vJl&2a!eKydz&1Q+m72s
zY|S`&jK61>WND+;VlD;$U^K{7T3$10H=JfO^cKkoc_LfjESn$So*f}a#sTOAu<Wy`
zR0 at DqP(P~gF9lha-IsbMHD7q{5de(?Eo}+_cx?--rv^>{MiJ%<Lo<90`12HIPi<uP
zgN5GjDAbe&Of@!O!zqREtPjzBNUtEtHAXiiK4R at QuurZcaScC0b}A7)pT0fdZXg8K
zRS=Kj2Ikk1xQQQOKPwSEpSwHYenrUXc~iqW2>%W_{SpFoUcnDlT2`sVWhF9HE=%#6
zp+b)-(g1o(=`?x=k*3jmh;-Ea_+ZmRCun=o<~2^Bi8`Bg&Y}53&u3}_tc})1ap-n1
zj$HJ@$nOPm_uk5`%C5E_%N at t!xF7ASR*^ZDG%JzsRia+7RB?OV>KpS1%7;RK(TTmP
z+fT}Iuh(&pIet*?_rr>E-&=QfP1R~nZO_8Ax3}J!Zn;xat}`<;vruzpntPl*b+3++
zr=TB}Yqfg4R&o1%sJ5KgsrJL(anFsTYUGA~A93ilLoZSlmZQYSq<+v(;%eIqywK?Y
z?m0Bxe!A&|3xGh;3%#BT2p|a}za4ljsf^~88!U8sP7H^f(CGqJ9m1PVC-GqZwZkym
zYI!Yq at zsN~hXFo)aLUwA%?0eJ1``MgA^&DG3aLJ;N85UjLF)zGd>z6kEb}j&PL0^#
z+r0EL{#2o(pqsBX#&Z at ek8wjcPxEd1N&c7~^X-a`dFCx%&=a0RN#<j2>F at GUB=e|b
zF&$TNzENXgV1Xz6piRxs2P_t9Z1jZYv23C^)fGl at _;p4NMosuc*;=93>A97;gD)Il
z+^~qTM2vNe`!@mO5+!g}^<iXa^uW&XaiKF1X%1qPpCY2DgLss$6Y-=5Vv=7W#VG(W
z$FCCc62C^o5q_H#9SS1k*NIr<H;Fhy_+26{5PpUhKO*!e5ML6$PQ?#|pQYj|;U7?O
zjqqDU{6hF0B7P(M9)XLh=)#tIhRdL9MQnW0gg>B|r%)`>8w5U7)?2GrZ)wuvZnS+J
zpXdv9KY>HnN?hCnYO0k;oVG`@bB%r{iH2Zz4bo`j;vjmha&w9B!S00r!_IuG?v#t2
ru<gZ-1<#2STn{#x>n5?&?0DsNr`L2k(WI$nzwDiiC(Yr1<aF&nJ2{z%

literal 0
HcmV?d00001

diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/pr-44884-clang.wat b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/pr-44884-clang.wat
new file mode 100644
index 00000000000000..6b65ca23ab6d64
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/pr-44884-clang.wat
@@ -0,0 +1,149 @@
+(module
+  (type (;0;) (func (param f32) (result i32)))
+  (type (;1;) (func (param i32) (result i32)))
+  (import "env" "__linear_memory" (memory (;0;) i64 0))
+  (import "env" "__stack_pointer" (global (;0;) (mut i64)))
+  (func $_Z3barf (type 0) (param f32) (result i32)
+    (local i64 i64 i64 f32 f32 f32 i32 i32 i32 i32 i32 i32)
+    global.get 0
+    local.set 1
+    i64.const 16
+    local.set 2
+    local.get 1
+    local.get 2
+    i64.sub
+    local.set 3
+    local.get 3
+    local.get 0
+    f32.store offset=12
+    local.get 3
+    f32.load offset=12
+    local.set 4
+    local.get 4
+    f32.abs
+    local.set 5
+    f32.const 0x1p+31 (;=2.14748e+09;)
+    local.set 6
+    local.get 5
+    local.get 6
+    f32.lt
+    local.set 7
+    local.get 7
+    i32.eqz
+    local.set 8
+    block  ;; label = @1
+      block  ;; label = @2
+        local.get 8
+        br_if 0 (;@2;)
+        local.get 4
+        i32.trunc_f32_s
+        local.set 9
+        local.get 9
+        local.set 10
+        br 1 (;@1;)
+      end
+      i32.const -2147483648
+      local.set 11
+      local.get 11
+      local.set 10
+    end
+    local.get 10
+    local.set 12
+    local.get 12
+    return)
+  (func $_Z3fooc (type 1) (param i32) (result i32)
+    (local i64 i64 i64 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 f32 f32 i32 i32 i32 i32 i32 i32 i32 i64 i64)
+    global.get 0
+    local.set 1
+    i64.const 16
+    local.set 2
+    local.get 1
+    local.get 2
+    i64.sub
+    local.set 3
+    local.get 3
+    global.set 0
+    local.get 3
+    local.get 0
+    i32.store8 offset=15
+    local.get 3
+    i32.load8_u offset=15
+    local.set 4
+    i32.const 24
+    local.set 5
+    local.get 4
+    local.get 5
+    i32.shl
+    local.set 6
+    local.get 6
+    local.get 5
+    i32.shr_s
+    local.set 7
+    local.get 3
+    local.get 7
+    i32.store offset=8
+    local.get 3
+    i32.load offset=8
+    local.set 8
+    local.get 3
+    i32.load8_u offset=15
+    local.set 9
+    i32.const 24
+    local.set 10
+    local.get 9
+    local.get 10
+    i32.shl
+    local.set 11
+    local.get 11
+    local.get 10
+    i32.shr_s
+    local.set 12
+    local.get 8
+    local.get 12
+    i32.add
+    local.set 13
+    local.get 13
+    f32.convert_i32_s
+    local.set 14
+    local.get 3
+    local.get 14
+    f32.store offset=4
+    local.get 3
+    f32.load offset=4
+    local.set 15
+    local.get 15
+    call $_Z3barf
+    local.set 16
+    local.get 3
+    local.get 16
+    i32.store offset=8
+    local.get 3
+    i32.load offset=8
+    local.set 17
+    local.get 3
+    i32.load8_u offset=15
+    local.set 18
+    i32.const 24
+    local.set 19
+    local.get 18
+    local.get 19
+    i32.shl
+    local.set 20
+    local.get 20
+    local.get 19
+    i32.shr_s
+    local.set 21
+    local.get 17
+    local.get 21
+    i32.add
+    local.set 22
+    i64.const 16
+    local.set 23
+    local.get 3
+    local.get 23
+    i64.add
+    local.set 24
+    local.get 24
+    global.set 0
+    local.get 22
+    return))
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/pr-44884.cpp b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/pr-44884.cpp
new file mode 100644
index 00000000000000..4b47aae8e0b17b
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/pr-44884.cpp
@@ -0,0 +1,14 @@
+int bar(float Input) { return (int)Input; }
+
+unsigned foo(char Param) {
+  typedef int INT;
+  INT Value = Param;
+  {
+    typedef float FLOAT;
+    {
+      FLOAT Added = Value + Param;
+      Value = bar(Added);
+    }
+  }
+  return Value + Param;
+}
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/pr-46466-clang.wasm b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/pr-46466-clang.wasm
new file mode 100644
index 0000000000000000000000000000000000000000..f20d68bca653baa359bb0067c05d790a338961f7
GIT binary patch
literal 1180
zcmc&!Pix#p6n{@6?P at GrwqtP87J>sQq?pw at M&4bg&?F5x_*QV!LodomJC at aGB{4JF
z)|bRKgg_v<6>>{IK%uu at dkG<@kV}ruCFfpx?WJ$l4!HCKL@@9Fd-L?(PXeJQ2mtu-
z at bD1uF5m;_H!C_!R at 22KDT_)9l}zNMRtJuYr)F(Lb}wn_qB2sk`^b)G`7nPp<8x1D
zEI at p46EDFUEC#`&lZdY&pbL*F4i=)ZOxrvWX{zKDm+|v(#be>p`Om^-Jl6qmVqoFU
z%JomK1z!fv1pu~!gMfuWU=0B7!pv`#5vksJIP2|1V9VUNP=zeCF}4yw_cA4Y6$F$3
z at U!hBIPIgT_UeaZbgc(`I~TYFN0!m^l#Vl#0Bo-Fg2;6`=yP^z2j;!D7DV?Y at o%l{
zf#<!N86D`HEztdImiGKDIp5g;Zm;UTC*n~Hf7{mPPFvGPWu>U{wW(CPsH?TB+tEg}
zkr!s|%Dyp;zSi%PvfrkWE at Y(Z>LAMMNq=|ecJCWiOofsCtZ93uuFGs+6jiTjRAke)
zM`B|$jzzq+H;~(- at nD>7Zf0UQ9PY(pm~M%!ksOib3usg?9>jw|lr;_X$HItyqv{`I
zW^`X?s%VHSnJcMnhdtdEbZJpFt?B2ol1h}Y3wPj7MPAr7s?7`}-^WI3GX+b5&;;<t
z;^f0hEc|ZJKwP*?l;-+RxL}#x4ITV%Q)C2>%>j2jE7HR_IzA=9AGT_j%H1of-0^?0
zYKO}DA38u6cc~zAI?fU>$7c at r9@{AFM5)#hIpI&MFDqHrS#$<7-6c+o<?}A^bM6uH
zRS)>5?o(X72*B6f7q~P;;5XgZ$ambA$iH)6;c5b~P%*CEx5$5V-yuIn_dUY1|6gHe
zz;Ttn1^Crsg45K;ZAL(Fe2a-z<PyVMNmI7^gj|hbo`N#kgdF$M1N3I#Q6B*`zuWg&
rG(zRlBzsbrmhi#W7bmR|X(@YoS*N1Z>%K1XswaOk>;B2VW)S}iE1n&T

literal 0
HcmV?d00001

diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/pr-46466-clang.wat b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/pr-46466-clang.wat
new file mode 100644
index 00000000000000..4c1f2857c636e7
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/pr-46466-clang.wat
@@ -0,0 +1,11 @@
+(module
+  (type (;0;) (func (result i32)))
+  (import "env" "__linear_memory" (memory (;0;) i64 1))
+  (import "env" "__stack_pointer" (global (;0;) (mut i64)))
+  (func $_Z4testv (type 0) (result i32)
+    (local i32)
+    i32.const 1
+    local.set 0
+    local.get 0
+    return)
+  (data $S (i64.const 0) "\00"))
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/pr-46466.cpp b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/pr-46466.cpp
new file mode 100644
index 00000000000000..28be9a5d60ec3b
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/pr-46466.cpp
@@ -0,0 +1,11 @@
+struct Struct {
+  union Union {
+    enum NestedEnum { RED, BLUE };
+  };
+  Union U;
+};
+
+Struct S;
+int test() {
+  return S.U.BLUE;
+}
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/test-clang.wasm b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/test-clang.wasm
new file mode 100644
index 0000000000000000000000000000000000000000..2147ec7fa041097909833b74370f7db4581724e1
GIT binary patch
literal 1459
zcmc&!&2Jk;6n`_bA0Dscd{}Y=RA^Te6cpJ`g5!LEO41Oa2q}%)a6y&Kcs+48wRg?#
zY}6nTCrBXZ0ksDNhawJK5MMnYA$lSw)I$$F^uVRJ9^q1P<51q%X$j&FV5NEQ{eFHs
z at 6DUv8bs0|06;!EI5+_EHrwy at NRQssh%y=O4%h4LAe17mcVs7u_oxBKbfScRx!#R}
zP|29>6ZU?83&<WG>aBW|?Pq$=A$I^CJLh_a%Ut6<&vZ=}=GX{2QlmMSdKQM(A~>#D
z0>`tLiI;J0H}j6i=@MOX`RWiX+g=v4vNdX8h?%Zaqo;EOqY0Yxa!BNm=)=?AkUKQ&
zz=yhxp>k6;(pFtG8nN6ZqvZK~!DRW7Q_ti_$(RK|%Set{OXFdl<rkfoowdTNPXRC!
z==fs-z;OCm0A}@Hyj6s?!XOR6J_9U&)^Qww%rNo*{Dr;)_)YiX9QP80ThVQtxq%B)
z_4vVqL+$Xnii`FmfS!&|0^<)bzdS<r4lY7(pk?&>$h|)LYJhSN`sn8Yavt^3FKCT*
zH2N9GWzy?L9!nGRS4~-Zt5X^qVBgih8`cl#?&BgP^CLR0Q|yP at 7&gaLO87NI0N>!v
zL-zP|iHiNU2wU#1jFTV=-RXt$RC%fuD0gC8scy1ZsUX-+8|5UB<s=IC%6`<TTwGf%
zZN$N at P_p88(~^p!w!bZcu+;6wW&QfXyqKD)Rz-Dot0oubo3*AtGvkZ7xw);Xm}|_6
z*?BpS%!{C8qRM`^3zeo&qSB3{9qFs2lK64ZMIXynEEC;bDM<q?7=+zaRa!EXv1mj6
zt(Uf<Xyc7wrvVrMDjYUMEIJ!1hPCz0jm--K{AQR0txz^0Jr3L_spqhLXlS!?e*NO+
z^7^KJbM^Jr3jn|CZ{o2U^w)I>hiHI{mJsq+en>kUFzEaE=P*d%Ej-af!L+k<x?m}@
zU}esl=JytR_qLg}CQN22c14-QV%((;ZU*1#iZ+(I9E2^JxuKznC7lyTr6Z^%gHel7
z8?Nb$Y%JT6UtT%?+A1S93iVITjt<xpVm1rhqQG+u_!v7Ryl4P_nq4KuX90?n*z+sw
zi0~zLhwycFkMK+E0pUCB5h<o9Wc~qRpHTiOVV_a{1z~py|C+G-gx at 0UA>l`aeN5r=
z|5nz6vq`apL-|gBUL3Evnfj<Yn$ZGGMN5+WO1;}olYyD8LJpIByn5LzHTH<vS8Dt}
xDD)?No?#{8mQ?jEDO8GrWRt_4REb7gmRjwoA==4gMhmPYuc*n);QzN){Tr at fQzHNX

literal 0
HcmV?d00001

diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/test-clang.wat b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/test-clang.wat
new file mode 100644
index 00000000000000..ccacc0fab12918
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/test-clang.wat
@@ -0,0 +1,63 @@
+(module
+  (type (;0;) (func (param i64 i32 i32) (result i32)))
+  (import "env" "__linear_memory" (memory (;0;) i64 0))
+  (import "env" "__stack_pointer" (global (;0;) (mut i64)))
+  (func $_Z3fooPKijb (type 0) (param i64 i32 i32) (result i32)
+    (local i64 i64 i64 i32 i32 i32 i32 i32 i32 i32 i32)
+    global.get 0
+    local.set 3
+    i64.const 32
+    local.set 4
+    local.get 3
+    local.get 4
+    i64.sub
+    local.set 5
+    local.get 5
+    local.get 0
+    i64.store offset=16
+    local.get 5
+    local.get 1
+    i32.store offset=12
+    local.get 2
+    local.set 6
+    local.get 5
+    local.get 6
+    i32.store8 offset=11
+    local.get 5
+    i32.load8_u offset=11
+    local.set 7
+    i32.const 1
+    local.set 8
+    local.get 7
+    local.get 8
+    i32.and
+    local.set 9
+    block  ;; label = @1
+      block  ;; label = @2
+        local.get 9
+        i32.eqz
+        br_if 0 (;@2;)
+        i32.const 7
+        local.set 10
+        local.get 5
+        local.get 10
+        i32.store offset=4
+        i32.const 7
+        local.set 11
+        local.get 5
+        local.get 11
+        i32.store offset=28
+        br 1 (;@1;)
+      end
+      local.get 5
+      i32.load offset=12
+      local.set 12
+      local.get 5
+      local.get 12
+      i32.store offset=28
+    end
+    local.get 5
+    i32.load offset=28
+    local.set 13
+    local.get 13
+    return))
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/test.cpp b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/test.cpp
new file mode 100644
index 00000000000000..5cf39f47735844
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/Inputs/test.cpp
@@ -0,0 +1,9 @@
+using INTPTR = const int *;
+int foo(INTPTR ParamPtr, unsigned ParamUnsigned, bool ParamBool) {
+  if (ParamBool) {
+    typedef int INTEGER;
+    const INTEGER CONSTANT = 7;
+    return CONSTANT;
+  }
+  return ParamUnsigned;
+}
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/README.txt b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/README.txt
new file mode 100644
index 00000000000000..9e6c8dc6aa845d
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/WebAssembly/README.txt
@@ -0,0 +1,54 @@
+LLVM WebAssembly limitations
+----------------------------
+LLVM does not support any conversion between the binary format (.wasm)
+and the text format (.wat):
+
+  .wasm -> .wat
+  .wat  -> .wasm
+
+WebAssembly external tools
+--------------------------
+These tools are intended for use in (or for development of) toolchains
+or other systems that want to manipulate WebAssembly files.
+
+  Development of WebAssembly and associated infrastructure
+  https://github.com/WebAssembly
+
+  WABT: The WebAssembly Binary Toolkit
+  https://github.com/WebAssembly/wabt
+
+  wasm2wat — translate from the binary format to the text format
+  https://webassembly.github.io/wabt/doc/wasm2wat.1.html
+
+  wat2wasm — translate from WebAssembly text format to the WebAssembly binary format
+  https://webassembly.github.io/wabt/doc/wat2wasm.1.html
+
+How to generate .wasm from .cpp
+-------------------------------
+Each test includes its C++ source. To generate the .wasm for any of
+the tests (ie. hello-world.cpp):
+
+For target=wasm64
+  clang --target=wasm64 -c -w -g -O0 -o hello-world.wasm hello-world.cpp
+
+or
+
+For target=wasm32
+  clang --target=wasm32 -c -w -g -O0 -o hello-world.wasm hello-world.cpp
+
+How to generate .wasm from .wat
+-------------------------------
+Using the 'wasm2wat' and 'wat2wasm' (WABT: The WebAssembly Binary Toolkit),
+we can generate the WebAssembly text format file.
+
+For target=wasm64
+  wasm2wat hello-world.wasm --enable-memory64 -o hello-world.wat
+
+For target=wasm32
+  wat2wasm hello-world.wat -o hello-world.wasm
+
+Notes:
+------
+* The tests run the .wasm file (target=wasm64).
+* The .wat files were generated using WABT wasm2wat tool and are included
+  only for extra information.



More information about the llvm-commits mailing list