[llvm] [llvm-debuginfo-analyzer] Add support for parsing DWARF / CodeView SourceLanguage (PR #137223)

Javier Lopez-Gomez via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 4 09:17:19 PDT 2025


https://github.com/jalopezg-git updated https://github.com/llvm/llvm-project/pull/137223

>From 65b951308c39dc19f9674a9f1e46310f09859b59 Mon Sep 17 00:00:00 2001
From: Javier Lopez-Gomez <javier.lopez.gomez at proton.me>
Date: Wed, 4 Jun 2025 18:17:03 +0200
Subject: [PATCH] [llvm-debuginfo-analyzer] Add support for parsing DWARF /
 CodeView source language

---
 .../CommandGuide/llvm-debuginfo-analyzer.rst  |  4 +-
 .../DebugInfo/LogicalView/Core/LVElement.h    |  4 ++
 .../DebugInfo/LogicalView/Core/LVOptions.h    |  2 +
 .../llvm/DebugInfo/LogicalView/Core/LVScope.h |  6 ++
 .../LogicalView/Core/LVSourceLanguage.h       | 69 +++++++++++++++++++
 llvm/lib/DebugInfo/LogicalView/CMakeLists.txt |  1 +
 .../DebugInfo/LogicalView/Core/LVOptions.cpp  |  1 +
 .../DebugInfo/LogicalView/Core/LVScope.cpp    | 18 +++--
 .../LogicalView/Core/LVSourceLanguage.cpp     | 33 +++++++++
 .../LogicalView/Readers/LVCodeViewVisitor.cpp |  6 ++
 .../LogicalView/Readers/LVDWARFReader.cpp     |  5 ++
 .../COFF/02-coff-logical-lines.test           |  4 +-
 ...-coff-incorrect-lexical-scope-typedef.test |  4 +-
 .../04-coff-missing-nested-enumerators.test   |  4 +-
 ...coff-incorrect-lexical-scope-variable.test |  4 +-
 .../COFF/06-coff-full-logical-view.test       |  1 +
 .../DWARF/02-dwarf-logical-lines.test         |  4 +-
 ...dwarf-incorrect-lexical-scope-typedef.test |  4 +-
 .../04-dwarf-missing-nested-enumerators.test  |  4 +-
 ...warf-incorrect-lexical-scope-variable.test |  4 +-
 .../DWARF/06-dwarf-full-logical-view.test     |  1 +
 ...-57040-ignored-DW_FORM_implicit_const.test |  6 +-
 .../pr-57040-incorrect-function-compare.test  |  6 +-
 .../WebAssembly/02-wasm-logical-lines.test    |  3 +-
 ...-wasm-incorrect-lexical-scope-typedef.test |  4 +-
 .../04-wasm-missing-nested-enumerators.test   |  4 +-
 ...wasm-incorrect-lexical-scope-variable.test |  4 +-
 .../06-wasm-full-logical-view.test            |  1 +
 .../llvm-debuginfo-analyzer/cmdline.test      |  1 +
 .../tools/llvm-debuginfo-analyzer/Options.cpp |  2 +
 .../LogicalView/CodeViewReaderTest.cpp        |  5 ++
 .../DebugInfo/LogicalView/DWARFReaderTest.cpp |  5 ++
 32 files changed, 202 insertions(+), 22 deletions(-)
 create mode 100644 llvm/include/llvm/DebugInfo/LogicalView/Core/LVSourceLanguage.h
 create mode 100644 llvm/lib/DebugInfo/LogicalView/Core/LVSourceLanguage.cpp

diff --git a/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst b/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst
index 7c15e65c1adf7..453af0751e2a1 100644
--- a/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst
+++ b/llvm/docs/CommandGuide/llvm-debuginfo-analyzer.rst
@@ -134,12 +134,13 @@ toolchain name, binary file format, etc.
  The following attributes describe the most common information for a
  logical element. They help to identify the lexical scope level; the
  element visibility across modules (global, local); the toolchain name
- that produced the binary file.
+ and source language that produced the binary file.
 
  .. code-block:: text
 
    =global: Element referenced across Compile Units.
    =format: Object file format name.
+   =language: Source language name.
    =level: Lexical scope level (File=0, Compile Unit=1).
    =local: Element referenced only in the Compile Unit.
    =producer: Toolchain identification name.
@@ -231,6 +232,7 @@ toolchain name, binary file format, etc.
    =filename
    =files
    =format
+   =language
    =level
    =producer
    =publics
diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h
index d3a6973bb7f04..0fb78cfaefbfa 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h
@@ -15,6 +15,7 @@
 #define LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVELEMENT_H
 
 #include "llvm/DebugInfo/LogicalView/Core/LVObject.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVSourceLanguage.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/MathExtras.h"
 #include <map>
@@ -220,6 +221,9 @@ class LVElement : public LVObject {
   virtual StringRef getProducer() const { return StringRef(); }
   virtual void setProducer(StringRef ProducerName) {}
 
+  virtual LVSourceLanguage getSourceLanguage() const { return {}; }
+  virtual void setSourceLanguage(LVSourceLanguage SL) {}
+
   virtual bool isCompileUnit() const { return false; }
   virtual bool isRoot() const { return false; }
 
diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVOptions.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVOptions.h
index 409e4652b2401..118ec9322b7bf 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVOptions.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVOptions.h
@@ -106,6 +106,7 @@ enum class LVAttributeKind {
   Generated,     // --attribute=generated
   Global,        // --attribute=global
   Inserted,      // --attribute=inserted
+  Language,      // --attribute=language
   Level,         // --attribute=level
   Linkage,       // --attribute=linkage
   Local,         // --attribute=local
@@ -337,6 +338,7 @@ class LVOptions {
   ATTRIBUTE_OPTION(Generated);
   ATTRIBUTE_OPTION(Global);
   ATTRIBUTE_OPTION(Inserted);
+  ATTRIBUTE_OPTION(Language);
   ATTRIBUTE_OPTION(Level);
   ATTRIBUTE_OPTION(Linkage);
   ATTRIBUTE_OPTION(Location);
diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h
index a9bd7eef7b66b..a5726582707bc 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h
@@ -418,6 +418,9 @@ class LVScopeCompileUnit final : public LVScope {
   // Compilation directory name.
   size_t CompilationDirectoryIndex = 0;
 
+  // Source language.
+  LVSourceLanguage SourceLanguage{};
+
   // Used by the CodeView Reader.
   codeview::CPUType CompilationCPUType = codeview::CPUType::X64;
 
@@ -548,6 +551,9 @@ class LVScopeCompileUnit final : public LVScope {
     ProducerIndex = getStringPool().getIndex(ProducerName);
   }
 
+  LVSourceLanguage getSourceLanguage() const override { return SourceLanguage; }
+  void setSourceLanguage(LVSourceLanguage SL) override { SourceLanguage = SL; }
+
   void setCPUType(codeview::CPUType Type) { CompilationCPUType = Type; }
   codeview::CPUType getCPUType() { return CompilationCPUType; }
 
diff --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSourceLanguage.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSourceLanguage.h
new file mode 100644
index 0000000000000..52e4aa9701e44
--- /dev/null
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSourceLanguage.h
@@ -0,0 +1,69 @@
+//===-- LVSourceLanguage.h --------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the LVSourceLanguage struct, a unified representation of
+// the source language used in a compile unit.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVSOURCELANGUAGE_H
+#define LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVSOURCELANGUAGE_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+
+namespace llvm {
+namespace logicalview {
+
+/// A source language supported by any of the debug info representations.
+struct LVSourceLanguage {
+  static constexpr unsigned TagDwarf = 0x00;
+  static constexpr unsigned TagCodeView = 0x01;
+
+  enum TaggedLanguage : uint32_t {
+    Invalid = -1U,
+
+  // DWARF
+#define HANDLE_DW_LANG(ID, NAME, LOWER_BOUND, VERSION, VENDOR)                 \
+  DW_LANG_##NAME = (TagDwarf << 16) | ID,
+#include "llvm/BinaryFormat/Dwarf.def"
+  // CodeView
+#define CV_LANGUAGE(NAME, ID) CV_LANG_##NAME = (TagCodeView << 16) | ID,
+#include "llvm/DebugInfo/CodeView/CodeViewLanguages.def"
+  };
+
+  LVSourceLanguage() = default;
+  LVSourceLanguage(llvm::dwarf::SourceLanguage SL)
+      : LVSourceLanguage(TagDwarf, SL) {}
+  LVSourceLanguage(llvm::codeview::SourceLanguage SL)
+      : LVSourceLanguage(TagCodeView, SL) {}
+  bool operator==(const LVSourceLanguage &SL) const {
+    return get() == SL.get();
+  }
+  bool operator==(const LVSourceLanguage::TaggedLanguage &TL) const {
+    return get() == TL;
+  }
+
+  bool isValid() const { return Language != Invalid; }
+  TaggedLanguage get() const { return Language; }
+  StringRef getName() const;
+
+private:
+  TaggedLanguage Language = Invalid;
+
+  LVSourceLanguage(unsigned Tag, unsigned Lang)
+      : Language(static_cast<TaggedLanguage>((Tag << 16) | Lang)) {}
+  unsigned getTag() const { return Language >> 16; }
+  unsigned getLang() const { return Language & 0xffff; }
+};
+
+} // end namespace logicalview
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVSOURCELANGUAGE_H
diff --git a/llvm/lib/DebugInfo/LogicalView/CMakeLists.txt b/llvm/lib/DebugInfo/LogicalView/CMakeLists.txt
index f5adab723927a..67ee7698a3825 100644
--- a/llvm/lib/DebugInfo/LogicalView/CMakeLists.txt
+++ b/llvm/lib/DebugInfo/LogicalView/CMakeLists.txt
@@ -14,6 +14,7 @@ add_lv_impl_folder(Core
   Core/LVReader.cpp
   Core/LVScope.cpp
   Core/LVSort.cpp
+  Core/LVSourceLanguage.cpp
   Core/LVSupport.cpp
   Core/LVSymbol.cpp
   Core/LVType.cpp
diff --git a/llvm/lib/DebugInfo/LogicalView/Core/LVOptions.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVOptions.cpp
index c08e887fde3e5..467bb98670b40 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVOptions.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVOptions.cpp
@@ -39,6 +39,7 @@ void LVOptions::resolveDependencies() {
     setAttributeFilename();
     setAttributeFiles();
     setAttributeFormat();
+    setAttributeLanguage();
     setAttributeLevel();
     setAttributeProducer();
     setAttributePublics();
diff --git a/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
index 06a11635a629d..317686f6628ef 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
@@ -1717,11 +1717,19 @@ void LVScopeCompileUnit::print(raw_ostream &OS, bool Full) const {
 
 void LVScopeCompileUnit::printExtra(raw_ostream &OS, bool Full) const {
   OS << formattedKind(kind()) << " '" << getName() << "'\n";
-  if (options().getPrintFormatting() && options().getAttributeProducer())
-    printAttributes(OS, Full, "{Producer} ",
-                    const_cast<LVScopeCompileUnit *>(this), getProducer(),
-                    /*UseQuotes=*/true,
-                    /*PrintRef=*/false);
+  if (options().getPrintFormatting()) {
+    if (options().getAttributeProducer())
+      printAttributes(OS, Full, "{Producer} ",
+                      const_cast<LVScopeCompileUnit *>(this), getProducer(),
+                      /*UseQuotes=*/true,
+                      /*PrintRef=*/false);
+    if (auto SL = getSourceLanguage();
+        options().getAttributeLanguage() && SL.isValid())
+      printAttributes(OS, Full, "{Language} ",
+                      const_cast<LVScopeCompileUnit *>(this), SL.getName(),
+                      /*UseQuotes=*/true,
+                      /*PrintRef=*/false);
+  }
 
   // Reset file index, to allow its children to print the correct filename.
   options().resetFilenameIndex();
diff --git a/llvm/lib/DebugInfo/LogicalView/Core/LVSourceLanguage.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVSourceLanguage.cpp
new file mode 100644
index 0000000000000..e7b122de1bba5
--- /dev/null
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVSourceLanguage.cpp
@@ -0,0 +1,33 @@
+//===-- LVSourceLanguage.cpp ----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements LVSourceLanguage.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/LogicalView/Core/LVSourceLanguage.h"
+#include "llvm/DebugInfo/CodeView/EnumTables.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+using namespace llvm;
+using namespace llvm::logicalview;
+
+StringRef LVSourceLanguage::getName() const {
+  if (!isValid())
+    return {};
+  switch (getTag()) {
+  case LVSourceLanguage::TagDwarf:
+    return llvm::dwarf::LanguageString(getLang());
+  case LVSourceLanguage::TagCodeView: {
+    static auto LangNames = llvm::codeview::getSourceLanguageNames();
+    return LangNames[getLang()].Name;
+  }
+  default:
+    llvm_unreachable("Unsupported language");
+  }
+}
diff --git a/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.cpp
index 4a1eb888095e2..24eaa1234727d 100644
--- a/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.cpp
@@ -949,6 +949,9 @@ Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record,
     Scope->setName(CurrentObjectName);
     if (options().getAttributeProducer())
       Scope->setProducer(Compile2.Version);
+    if (options().getAttributeLanguage())
+      Scope->setSourceLanguage(LVSourceLanguage{
+          static_cast<llvm::codeview::SourceLanguage>(Compile2.getLanguage())});
     getReader().isSystemEntry(Scope, CurrentObjectName);
 
     // The line records in CodeView are recorded per Module ID. Update
@@ -994,6 +997,9 @@ Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record,
     Scope->setName(CurrentObjectName);
     if (options().getAttributeProducer())
       Scope->setProducer(Compile3.Version);
+    if (options().getAttributeLanguage())
+      Scope->setSourceLanguage(LVSourceLanguage{
+          static_cast<llvm::codeview::SourceLanguage>(Compile3.getLanguage())});
     getReader().isSystemEntry(Scope, CurrentObjectName);
 
     // The line records in CodeView are recorded per Module ID. Update
diff --git a/llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp
index 3dbe11accd2d4..d5e65138c5304 100644
--- a/llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp
@@ -172,6 +172,11 @@ void LVDWARFReader::processOneAttribute(const DWARFDie &Die,
     if (options().getAttributeProducer())
       CurrentElement->setProducer(dwarf::toStringRef(FormValue));
     break;
+  case dwarf::DW_AT_language:
+    if (options().getAttributeLanguage())
+      CurrentElement->setSourceLanguage(LVSourceLanguage{
+          static_cast<llvm::dwarf::SourceLanguage>(GetAsUnsignedConstant())});
+    break;
   case dwarf::DW_AT_upper_bound:
     CurrentElement->setUpperBound(GetBoundValue(FormValue));
     break;
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/COFF/02-coff-logical-lines.test b/llvm/test/tools/llvm-debuginfo-analyzer/COFF/02-coff-logical-lines.test
index d2058c6b6be32..7bd816abe905f 100644
--- a/llvm/test/tools/llvm-debuginfo-analyzer/COFF/02-coff-logical-lines.test
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/COFF/02-coff-logical-lines.test
@@ -15,7 +15,7 @@
 ; 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: llvm-debuginfo-analyzer --attribute=language,level,format,producer \
 ; RUN:                         --print=lines,instructions \
 ; RUN:                         %p/Inputs/hello-world-codeview-clang.o \
 ; RUN:                         %p/Inputs/hello-world-codeview-msvc.o 2>&1 | \
@@ -26,6 +26,7 @@
 ; ONE-EMPTY:
 ; ONE-NEXT: [001]             {CompileUnit} 'hello-world.cpp'
 ; ONE-NEXT: [002]               {Producer} 'clang version 15.0.0 {{.*}}'
+; ONE-NEXT: [002]               {Language} 'Cpp'
 ; ONE-NEXT: [002]               {Function} extern not_inlined 'main' -> 'int'
 ; ONE-NEXT: [003]     4           {Line}
 ; ONE-NEXT: [003]                 {Code} 'subq	$0x28, %rsp'
@@ -43,6 +44,7 @@
 ; ONE-EMPTY:
 ; ONE-NEXT: [001]             {CompileUnit} 'hello-world.cpp'
 ; ONE-NEXT: [002]               {Producer} 'Microsoft (R) Optimizing Compiler'
+; ONE-NEXT: [002]               {Language} 'Cpp'
 ; ONE-NEXT: [002]               {Function} extern not_inlined 'main' -> 'int'
 ; ONE-NEXT: [003]     4           {Line}
 ; ONE-NEXT: [003]                 {Code} 'subq	$0x28, %rsp'
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/COFF/03-coff-incorrect-lexical-scope-typedef.test b/llvm/test/tools/llvm-debuginfo-analyzer/COFF/03-coff-incorrect-lexical-scope-typedef.test
index b7c646a103019..25f765b48f7de 100644
--- a/llvm/test/tools/llvm-debuginfo-analyzer/COFF/03-coff-incorrect-lexical-scope-typedef.test
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/COFF/03-coff-incorrect-lexical-scope-typedef.test
@@ -30,7 +30,7 @@
 ; emits both typedefs at the same lexical scope (3), which is wrong.
 ; GCC and MSVC emit correct lexical scope for both typedefs.
 
-; RUN: llvm-debuginfo-analyzer --attribute=level,format,producer \
+; RUN: llvm-debuginfo-analyzer --attribute=language,level,format,producer \
 ; RUN:                         --output-sort=kind \
 ; RUN:                         --print=symbols,types,lines \
 ; RUN:                         %p/Inputs/pr-44884-codeview-clang.o \
@@ -42,6 +42,7 @@
 ; ONE-EMPTY:
 ; ONE-NEXT: [001]             {CompileUnit} 'pr-44884.cpp'
 ; ONE-NEXT: [002]               {Producer} 'clang version 15.0.0 {{.*}}'
+; ONE-NEXT: [002]               {Language} 'Cpp'
 ; ONE-NEXT: [002]               {Function} extern not_inlined 'bar' -> 'int'
 ; ONE-NEXT: [003]                 {Parameter} 'Input' -> 'float'
 ; ONE-NEXT: [003]     1           {Line}
@@ -63,6 +64,7 @@
 ; ONE-EMPTY:
 ; ONE-NEXT: [001]             {CompileUnit} 'pr-44884.cpp'
 ; ONE-NEXT: [002]               {Producer} 'Microsoft (R) Optimizing Compiler'
+; ONE-NEXT: [002]               {Language} 'Cpp'
 ; ONE-NEXT: [002]               {Function} extern not_inlined 'bar' -> 'int'
 ; ONE-NEXT: [003]                 {Variable} 'Input' -> 'float'
 ; ONE-NEXT: [003]     1           {Line}
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/COFF/04-coff-missing-nested-enumerators.test b/llvm/test/tools/llvm-debuginfo-analyzer/COFF/04-coff-missing-nested-enumerators.test
index a6862e31ad5d3..aecc0914b33ad 100644
--- a/llvm/test/tools/llvm-debuginfo-analyzer/COFF/04-coff-missing-nested-enumerators.test
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/COFF/04-coff-missing-nested-enumerators.test
@@ -25,7 +25,7 @@
 ; references to the enumerators 'RED' and 'BLUE'. The CodeView generated
 ; by GCC and MSVC, does include such references.
 
-; RUN: llvm-debuginfo-analyzer --attribute=level,format,producer,size \
+; RUN: llvm-debuginfo-analyzer --attribute=language,level,format,producer,size \
 ; RUN:                         --output-sort=name \
 ; RUN:                         --print=symbols,types \
 ; RUN:                         %p/Inputs/pr-46466-codeview-clang.o \
@@ -37,6 +37,7 @@
 ; ONE-EMPTY:
 ; ONE-NEXT: [001]             {CompileUnit} 'pr-46466.cpp'
 ; ONE-NEXT: [002]               {Producer} 'clang version 15.0.0 {{.*}}'
+; ONE-NEXT: [002]               {Language} 'Cpp'
 ; ONE-NEXT: [002]               {Variable} extern 'S' -> 'Struct'
 ; ONE-NEXT: [002]     1         {Struct} 'Struct' [Size = 1]
 ; ONE-NEXT: [003]                 {Member} public 'U' -> 'Union'
@@ -50,6 +51,7 @@
 ; ONE-EMPTY:
 ; ONE-NEXT: [001]             {CompileUnit} 'pr-46466.cpp'
 ; ONE-NEXT: [002]               {Producer} 'Microsoft (R) Optimizing Compiler'
+; ONE-NEXT: [002]               {Language} 'Cpp'
 ; ONE-NEXT: [002]               {Variable} extern 'S' -> 'Struct'
 ; ONE-NEXT: [002]     1         {Struct} 'Struct' [Size = 1]
 ; ONE-NEXT: [003]                 {Member} public 'U' -> 'Union'
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/COFF/05-coff-incorrect-lexical-scope-variable.test b/llvm/test/tools/llvm-debuginfo-analyzer/COFF/05-coff-incorrect-lexical-scope-variable.test
index dea30c9f2b37d..aa628f70bc503 100644
--- a/llvm/test/tools/llvm-debuginfo-analyzer/COFF/05-coff-incorrect-lexical-scope-variable.test
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/COFF/05-coff-incorrect-lexical-scope-variable.test
@@ -31,7 +31,7 @@
 ; The CodeView generated by MSVC, show those variables at the correct
 ; lexical scope: '3' and '4' respectively.
 
-; RUN: llvm-debuginfo-analyzer --attribute=level,format,producer \
+; RUN: llvm-debuginfo-analyzer --attribute=language,level,format,producer \
 ; RUN:                         --output-sort=name \
 ; RUN:                         --print=symbols \
 ; RUN:                         %p/Inputs/pr-43860-codeview-clang.o \
@@ -43,6 +43,7 @@
 ; ONE-EMPTY:
 ; ONE-NEXT: [001]             {CompileUnit} 'pr-43860.cpp'
 ; ONE-NEXT: [002]               {Producer} 'clang version 15.0.0 {{.*}}'
+; ONE-NEXT: [002]               {Language} 'Cpp'
 ; ONE-NEXT: [002]     2         {Function} inlined 'InlineFunction' -> 'int'
 ; ONE-NEXT: [003]                 {Parameter} '' -> 'int'
 ; ONE-NEXT: [002]               {Function} extern not_inlined 'test' -> 'int'
@@ -59,6 +60,7 @@
 ; ONE-EMPTY:
 ; ONE-NEXT: [001]             {CompileUnit} 'pr-43860.cpp'
 ; ONE-NEXT: [002]               {Producer} 'Microsoft (R) Optimizing Compiler'
+; ONE-NEXT: [002]               {Language} 'Cpp'
 ; ONE-NEXT: [002]               {Function} extern declared_inlined 'InlineFunction' -> 'int'
 ; ONE-NEXT: [003]                 {Block}
 ; ONE-NEXT: [004]                   {Variable} 'Var_2' -> 'int'
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/COFF/06-coff-full-logical-view.test b/llvm/test/tools/llvm-debuginfo-analyzer/COFF/06-coff-full-logical-view.test
index 42c6f124ce70a..34b9de71084de 100644
--- a/llvm/test/tools/llvm-debuginfo-analyzer/COFF/06-coff-full-logical-view.test
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/COFF/06-coff-full-logical-view.test
@@ -28,6 +28,7 @@
 ; ONE-EMPTY:
 ; ONE-NEXT: [0x0000000000][001]              {CompileUnit} 'test.cpp'
 ; ONE-NEXT: [0x0000000000][002]                {Producer} 'clang version 15.0.0 {{.*}}'
+; ONE-NEXT: [0x0000000000][002]                {Language} 'Cpp'
 ; ONE-NEXT:                                    {Directory} 'test.cpp'
 ; ONE-NEXT:                                    {Directory} 'x:/tests/input'
 ; ONE-NEXT:                                    {File} 'general'
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/02-dwarf-logical-lines.test b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/02-dwarf-logical-lines.test
index 62eaf593a16c2..533914f002827 100644
--- a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/02-dwarf-logical-lines.test
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/02-dwarf-logical-lines.test
@@ -15,7 +15,7 @@
 ; 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: llvm-debuginfo-analyzer --attribute=language,level,format,producer \
 ; RUN:                         --print=lines,instructions \
 ; RUN:                         %p/Inputs/hello-world-dwarf-clang.o \
 ; RUN:                         %p/Inputs/hello-world-dwarf-gcc.o 2>&1 | \
@@ -26,6 +26,7 @@
 ; ONE-EMPTY:
 ; ONE-NEXT: [001]             {CompileUnit} 'hello-world.cpp'
 ; ONE-NEXT: [002]               {Producer} 'clang version 15.0.0 {{.*}}'
+; ONE-NEXT: [002]               {Language} 'DW_LANG_C_plus_plus_14'
 ; ONE-NEXT: [002]     3         {Function} extern not_inlined 'main' -> 'int'
 ; ONE-NEXT: [003]     4           {Line}
 ; ONE-NEXT: [003]                 {Code} 'pushq	%rbp'
@@ -48,6 +49,7 @@
 ; ONE-EMPTY:
 ; ONE-NEXT: [001]             {CompileUnit} 'hello-world.cpp'
 ; ONE-NEXT: [002]               {Producer} 'GNU C++14 10.3.0 {{.*}}'
+; ONE-NEXT: [002]               {Language} 'DW_LANG_C_plus_plus'
 ; ONE-NEXT: [002]     3         {Function} extern not_inlined 'main' -> 'int'
 ; ONE-NEXT: [003]     4           {Line}
 ; ONE-NEXT: [003]                 {Code} 'endbr64'
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/03-dwarf-incorrect-lexical-scope-typedef.test b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/03-dwarf-incorrect-lexical-scope-typedef.test
index f252a9a046f03..dc57d01f3b8bb 100644
--- a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/03-dwarf-incorrect-lexical-scope-typedef.test
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/03-dwarf-incorrect-lexical-scope-typedef.test
@@ -30,7 +30,7 @@
 ; 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: llvm-debuginfo-analyzer --attribute=language,level,format,producer \
 ; RUN:                         --output-sort=kind \
 ; RUN:                         --print=symbols,types,lines \
 ; RUN:                         %p/Inputs/pr-44884-dwarf-clang.o \
@@ -42,6 +42,7 @@
 ; ONE-EMPTY:
 ; ONE-NEXT: [001]             {CompileUnit} 'pr-44884.cpp'
 ; ONE-NEXT: [002]               {Producer} 'clang version 15.0.0 {{.*}}'
+; ONE-NEXT: [002]               {Language} 'DW_LANG_C_plus_plus_14'
 ; ONE-NEXT: [002]     1         {Function} extern not_inlined 'bar' -> 'int'
 ; ONE-NEXT: [003]     1           {Parameter} 'Input' -> 'float'
 ; ONE-NEXT: [003]     1           {Line}
@@ -76,6 +77,7 @@
 ; ONE-EMPTY:
 ; ONE-NEXT: [001]             {CompileUnit} 'pr-44884.cpp'
 ; ONE-NEXT: [002]               {Producer} 'GNU C++14 10.3.0 {{.*}}'
+; ONE-NEXT: [002]               {Language} 'DW_LANG_C_plus_plus'
 ; ONE-NEXT: [002]     1         {Function} extern not_inlined 'bar' -> 'int'
 ; ONE-NEXT: [003]     1           {Parameter} 'Input' -> 'float'
 ; ONE-NEXT: [003]     1           {Line}
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/04-dwarf-missing-nested-enumerators.test b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/04-dwarf-missing-nested-enumerators.test
index 15d426f88a372..cd1ee436557ff 100644
--- a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/04-dwarf-missing-nested-enumerators.test
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/04-dwarf-missing-nested-enumerators.test
@@ -25,7 +25,7 @@
 ; references to the enumerators 'RED' and 'BLUE'. The DWARF generated
 ; by GCC, does include such references.
 
-; RUN: llvm-debuginfo-analyzer --attribute=level,format,producer,size \
+; RUN: llvm-debuginfo-analyzer --attribute=language,level,format,producer,size \
 ; RUN:                         --output-sort=name \
 ; RUN:                         --print=symbols,types \
 ; RUN:                         %p/Inputs/pr-46466-dwarf-clang.o \
@@ -37,6 +37,7 @@
 ; ONE-EMPTY:
 ; ONE-NEXT: [001]             {CompileUnit} 'pr-46466.cpp'
 ; ONE-NEXT: [002]               {Producer} 'clang version 15.0.0 {{.*}}'
+; ONE-NEXT: [002]               {Language} 'DW_LANG_C_plus_plus_14'
 ; ONE-NEXT: [002]     8         {Variable} extern 'S' -> 'Struct'
 ; ONE-NEXT: [002]     1         {Struct} 'Struct' [Size = 1]
 ; ONE-NEXT: [003]     5           {Member} public 'U' -> 'Union'
@@ -46,6 +47,7 @@
 ; ONE-EMPTY:
 ; ONE-NEXT: [001]             {CompileUnit} 'pr-46466.cpp'
 ; ONE-NEXT: [002]               {Producer} 'GNU C++14 10.3.0 {{.*}}'
+; ONE-NEXT: [002]               {Language} 'DW_LANG_C_plus_plus'
 ; ONE-NEXT: [002]     8         {Variable} extern 'S' -> 'Struct'
 ; ONE-NEXT: [002]     1         {Struct} 'Struct' [Size = 1]
 ; ONE-NEXT: [003]     5           {Member} public 'U' -> 'Union'
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/05-dwarf-incorrect-lexical-scope-variable.test b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/05-dwarf-incorrect-lexical-scope-variable.test
index 3c3c5dcbda520..97f1d212bac4c 100644
--- a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/05-dwarf-incorrect-lexical-scope-variable.test
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/05-dwarf-incorrect-lexical-scope-variable.test
@@ -31,7 +31,7 @@
 ; 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: llvm-debuginfo-analyzer --attribute=language,level,format,producer \
 ; RUN:                         --output-sort=name \
 ; RUN:                         --print=symbols \
 ; RUN:                         %p/Inputs/pr-43860-dwarf-clang.o \
@@ -43,6 +43,7 @@
 ; ONE-EMPTY:
 ; ONE-NEXT: [001]             {CompileUnit} 'pr-43860.cpp'
 ; ONE-NEXT: [002]               {Producer} 'clang version 15.0.0 {{.*}}'
+; ONE-NEXT: [002]               {Language} 'DW_LANG_C_plus_plus_14'
 ; ONE-NEXT: [002]     2         {Function} extern inlined 'InlineFunction' -> 'int'
 ; ONE-NEXT: [003]                 {Block}
 ; ONE-NEXT: [004]     5             {Variable} 'Var_2' -> 'int'
@@ -63,6 +64,7 @@
 ; ONE-EMPTY:
 ; ONE-NEXT: [001]             {CompileUnit} 'pr-43860.cpp'
 ; ONE-NEXT: [002]               {Producer} 'GNU C++14 10.3.0 {{.*}}'
+; ONE-NEXT: [002]               {Language} 'DW_LANG_C_plus_plus'
 ; ONE-NEXT: [002]     2         {Function} extern declared_inlined 'InlineFunction' -> 'int'
 ; ONE-NEXT: [003]                 {Block}
 ; ONE-NEXT: [004]     5             {Variable} 'Var_2' -> 'int'
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/06-dwarf-full-logical-view.test b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/06-dwarf-full-logical-view.test
index 1d0843df52504..6616710a10045 100644
--- a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/06-dwarf-full-logical-view.test
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/06-dwarf-full-logical-view.test
@@ -28,6 +28,7 @@
 ; ONE-EMPTY:
 ; ONE-NEXT: [0x000000000b][001]              {CompileUnit} 'test.cpp'
 ; ONE-NEXT: [0x000000000b][002]                {Producer} 'clang version 15.0.0 {{.*}}'
+; ONE-NEXT: [0x000000000b][002]                {Language} 'DW_LANG_C_plus_plus_14'
 ; ONE-NEXT:                                    {Directory} '/data/projects/tests/input/general'
 ; ONE-NEXT:                                    {File} 'test.cpp'
 ; ONE-NEXT:                                    {Public} 'foo' [0x0000000000:0x000000003a]
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/pr-57040-ignored-DW_FORM_implicit_const.test b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/pr-57040-ignored-DW_FORM_implicit_const.test
index 9df058c559805..6e8e720722f04 100644
--- a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/pr-57040-ignored-DW_FORM_implicit_const.test
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/pr-57040-ignored-DW_FORM_implicit_const.test
@@ -28,7 +28,7 @@
 ;  8    return ParamUnsigned;
 ;  9  }
 
-; RUN: llvm-debuginfo-analyzer --attribute=level,format,producer \
+; RUN: llvm-debuginfo-analyzer --attribute=language,level,format,producer \
 ; RUN:                         --print=scopes,symbols,types \
 ; RUN:                         %p/Inputs/pr-57040-test-dwarf-clang.o 2>&1 | \
 ; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
@@ -38,6 +38,7 @@
 ; ONE-EMPTY:
 ; ONE-NEXT: [001]             {CompileUnit} 'test.cpp'
 ; ONE-NEXT: [002]               {Producer} 'clang version 14.0.6'
+; ONE-NEXT: [002]               {Language} 'DW_LANG_C_plus_plus_14'
 ; ONE-NEXT: [002]     1         {TypeAlias} 'INTPTR' -> '* const int'
 ; ONE-NEXT: [002]     2         {Function} extern not_inlined 'foo' -> 'int'
 ; ONE-NEXT: [003]                 {Block}
@@ -47,7 +48,7 @@
 ; ONE-NEXT: [003]     2           {Parameter} 'ParamUnsigned' -> 'unsigned int'
 ; ONE-NEXT: [003]     4           {TypeAlias} 'INTEGER' -> 'int'
 
-; RUN: llvm-debuginfo-analyzer --attribute=level,format,producer \
+; RUN: llvm-debuginfo-analyzer --attribute=language,level,format,producer \
 ; RUN:                         --print=scopes,symbols,types \
 ; RUN:                         %p/Inputs/pr-57040-test-dwarf-gcc.o 2>&1 | \
 ; RUN: FileCheck --strict-whitespace -check-prefix=TWO %s
@@ -57,6 +58,7 @@
 ; TWO-EMPTY:
 ; TWO-NEXT: [001]             {CompileUnit} 'test.cpp'
 ; TWO-NEXT: [002]               {Producer} 'GNU C++17 11.3.0 {{.*}}'
+; TWO-NEXT: [002]               {Language} 'DW_LANG_C_plus_plus_14'
 ; TWO-NEXT: [002]     1         {TypeAlias} 'INTPTR' -> '* const int'
 ; TWO-NEXT: [002]     2         {Function} extern not_inlined 'foo' -> 'int'
 ; TWO-NEXT: [003]                 {Block}
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/pr-57040-incorrect-function-compare.test b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/pr-57040-incorrect-function-compare.test
index 46fbc703f7dee..278d4f4850f5f 100644
--- a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/pr-57040-incorrect-function-compare.test
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/pr-57040-incorrect-function-compare.test
@@ -35,7 +35,7 @@
 ;  8    return ParamUnsigned;
 ;  9  }
 
-; RUN: llvm-debuginfo-analyzer --attribute=level,producer \
+; RUN: llvm-debuginfo-analyzer --attribute=language,level,producer \
 ; RUN:                         --compare=types \
 ; RUN:                         --report=view \
 ; RUN:                         --print=symbols,types \
@@ -51,6 +51,7 @@
 ; ONE-EMPTY:
 ; ONE-NEXT:  [001]             {CompileUnit} 'test.cpp'
 ; ONE-NEXT:  [002]               {Producer} 'clang version 14.0.6'
+; ONE-NEXT:  [002]               {Language} 'DW_LANG_C_plus_plus_14'
 ; ONE-NEXT:  [002]     1         {TypeAlias} 'INTPTR' -> '* const int'
 ; ONE-NEXT:  [002]     2         {Function} extern not_inlined 'foo' -> 'int'
 ; ONE-NEXT:  [003]                 {Block}
@@ -90,7 +91,7 @@
 
 ; Changing the 'Reference' and 'Target' order:
 
-; RUN: llvm-debuginfo-analyzer --attribute=level,producer \
+; RUN: llvm-debuginfo-analyzer --attribute=language,level,producer \
 ; RUN:                         --compare=types \
 ; RUN:                         --report=view \
 ; RUN:                         --print=symbols,types \
@@ -106,6 +107,7 @@
 ; THR-EMPTY:
 ; THR-NEXT:  [001]             {CompileUnit} 'test.cpp'
 ; THR-NEXT:  [002]               {Producer} 'GNU C++17 11.3.0 {{.*}}'
+; THR-NEXT:  [002]               {Language} 'DW_LANG_C_plus_plus_14'
 ; THR-NEXT:  [002]     1         {TypeAlias} 'INTPTR' -> '* const int'
 ; THR-NEXT:  [002]     2         {Function} extern not_inlined 'foo' -> 'int'
 ; THR-NEXT:  [003]                 {Block}
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
index 101f6abdc96b6..50a531ad7d823 100644
--- 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
@@ -18,7 +18,7 @@
 ; RUN: llvm-mc -arch=wasm32 -filetype=obj \
 ; RUN:         %p/Inputs/hello-world-clang.s -o %t.hello-world-clang.o
 
-; RUN: llvm-debuginfo-analyzer --attribute=level,format,producer \
+; RUN: llvm-debuginfo-analyzer --attribute=language,level,format,producer \
 ; RUN:                         --print=lines,instructions \
 ; RUN:                         %t.hello-world-clang.o 2>&1 | \
 ; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
@@ -28,6 +28,7 @@
 ; ONE-EMPTY:
 ; ONE-NEXT: [001]             {CompileUnit} 'hello-world.cpp'
 ; ONE-NEXT: [002]               {Producer} 'clang version 19{{.*}}'
+; ONE-NEXT: [002]               {Language} 'DW_LANG_C_plus_plus_14'
 ; ONE-NEXT: [002]     3         {Function} extern not_inlined 'main' -> 'int'
 ; ONE-NEXT: [003]     4           {Line}
 ; ONE-NEXT: [003]                 {Code} 'nop'
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
index eb05ecae8ccf6..1192a0cb7ca5a 100644
--- 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
@@ -33,7 +33,7 @@
 ; RUN: llvm-mc -arch=wasm32 -filetype=obj \
 ; RUN:         %p/Inputs/pr-44884-clang.s -o %t.pr-44884-clang.o
 
-; RUN: llvm-debuginfo-analyzer --attribute=level,format,producer \
+; RUN: llvm-debuginfo-analyzer --attribute=language,level,format,producer \
 ; RUN:                         --output-sort=kind \
 ; RUN:                         --print=symbols,types,lines \
 ; RUN:                         %t.pr-44884-clang.o \
@@ -45,6 +45,7 @@
 ; ONE-EMPTY:
 ; ONE-NEXT: [001]             {CompileUnit} 'pr-44884.cpp'
 ; ONE-NEXT: [002]               {Producer} 'clang version 19{{.*}}'
+; ONE-NEXT: [002]               {Language} 'DW_LANG_C_plus_plus_14'
 ; ONE-NEXT: [002]     1         {Function} extern not_inlined 'bar' -> 'int'
 ; ONE-NEXT: [003]     1           {Parameter} 'Input' -> 'float'
 ; ONE-NEXT: [003]     1           {Line}
@@ -84,6 +85,7 @@
 ; ONE-EMPTY:
 ; ONE-NEXT: [001]             {CompileUnit} 'pr-44884.cpp'
 ; ONE-NEXT: [002]               {Producer} 'GNU C++14 10.3.0 {{.*}}'
+; ONE-NEXT: [002]               {Language} 'DW_LANG_C_plus_plus'
 ; ONE-NEXT: [002]     1         {Function} extern not_inlined 'bar' -> 'int'
 ; ONE-NEXT: [003]     1           {Parameter} 'Input' -> 'float'
 ; ONE-NEXT: [003]     1           {Line}
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
index cafa51c41966c..58f80e06bd279 100644
--- 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
@@ -28,7 +28,7 @@
 ; RUN: llvm-mc -arch=wasm32 -filetype=obj \
 ; RUN:         %p/Inputs/pr-46466-clang.s -o %t.pr-46466-clang.o
 
-; RUN: llvm-debuginfo-analyzer --attribute=level,format,producer \
+; RUN: llvm-debuginfo-analyzer --attribute=language,level,format,producer \
 ; RUN:                         --output-sort=name \
 ; RUN:                         --print=symbols,types \
 ; RUN:                         %t.pr-46466-clang.o \
@@ -40,6 +40,7 @@
 ; ONE-EMPTY:
 ; ONE-NEXT: [001]             {CompileUnit} 'pr-46466.cpp'
 ; ONE-NEXT: [002]               {Producer} 'clang version 19{{.*}}'
+; ONE-NEXT: [002]               {Language} 'DW_LANG_C_plus_plus_14'
 ; ONE-NEXT: [002]     8         {Variable} extern 'S' -> 'Struct'
 ; ONE-NEXT: [002]     1         {Struct} 'Struct'
 ; ONE-NEXT: [003]     5           {Member} public 'U' -> 'Union'
@@ -49,6 +50,7 @@
 ; ONE-EMPTY:
 ; ONE-NEXT: [001]             {CompileUnit} 'pr-46466.cpp'
 ; ONE-NEXT: [002]               {Producer} 'GNU C++14 10.3.0 {{.*}}'
+; ONE-NEXT: [002]               {Language} 'DW_LANG_C_plus_plus'
 ; ONE-NEXT: [002]     8         {Variable} extern 'S' -> 'Struct'
 ; ONE-NEXT: [002]     1         {Struct} 'Struct'
 ; ONE-NEXT: [003]     5           {Member} public 'U' -> 'Union'
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
index 4348161f8c5ba..32a186004a362 100644
--- 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
@@ -34,7 +34,7 @@
 ; RUN: llvm-mc -arch=wasm32 -filetype=obj \
 ; RUN:         %p/Inputs/pr-43860-clang.s -o %t.pr-43860-clang.o
 
-; RUN: llvm-debuginfo-analyzer --attribute=level,format,producer \
+; RUN: llvm-debuginfo-analyzer --attribute=language,level,format,producer \
 ; RUN:                         --output-sort=name \
 ; RUN:                         --print=symbols \
 ; RUN:                         %t.pr-43860-clang.o \
@@ -46,6 +46,7 @@
 ; ONE-EMPTY:
 ; ONE-NEXT: [001]             {CompileUnit} 'pr-43860.cpp'
 ; ONE-NEXT: [002]               {Producer} 'clang version 19{{.*}}'
+; ONE-NEXT: [002]               {Language} 'DW_LANG_C_plus_plus_14'
 ; ONE-NEXT: [002]     2         {Function} extern inlined 'InlineFunction' -> 'int'
 ; ONE-NEXT: [003]                 {Block}
 ; ONE-NEXT: [004]     5             {Variable} 'Var_2' -> 'int'
@@ -66,6 +67,7 @@
 ; ONE-EMPTY:
 ; ONE-NEXT: [001]             {CompileUnit} 'pr-43860.cpp'
 ; ONE-NEXT: [002]               {Producer} 'GNU C++14 10.3.0 {{.*}}'
+; ONE-NEXT: [002]               {Language} 'DW_LANG_C_plus_plus'
 ; ONE-NEXT: [002]     2         {Function} extern declared_inlined 'InlineFunction' -> 'int'
 ; ONE-NEXT: [003]                 {Block}
 ; ONE-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
index 81b78bac03215..ac4873f0a4d34 100644
--- 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
@@ -31,6 +31,7 @@
 ; ONE-EMPTY:
 ; ONE-NEXT: [0x000000000b][001]              {CompileUnit} 'test.cpp'
 ; ONE-NEXT: [0x000000000b][002]                {Producer} 'clang version 19{{.*}}'
+; ONE-NEXT: [0x000000000b][002]                {Language} 'DW_LANG_C_plus_plus_14'
 ; ONE-NEXT:                                    {Directory} '{{.*}}/general'
 ; ONE-NEXT:                                    {File} 'test.cpp'
 ; ONE-NEXT:                                    {Public} 'foo' [0x0000000002:0x000000007f]
diff --git a/llvm/test/tools/llvm-debuginfo-analyzer/cmdline.test b/llvm/test/tools/llvm-debuginfo-analyzer/cmdline.test
index 000c6e6b5ae3c..7763426142476 100644
--- a/llvm/test/tools/llvm-debuginfo-analyzer/cmdline.test
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/cmdline.test
@@ -51,6 +51,7 @@ HELP-ALL:     =gaps                    -   Missing debug location (gaps).
 HELP-ALL:     =generated               -   Compiler generated elements.
 HELP-ALL:     =global                  -   Element referenced across Compile Units.
 HELP-ALL:     =inserted                -   Generated inlined abstract references.
+HELP-ALL:     =language                -   Source language name.
 HELP-ALL:     =level                   -   Lexical scope level (File=0, Compile Unit=1).
 HELP-ALL:     =linkage                 -   Linkage name.
 HELP-ALL:     =local                   -   Element referenced only in the Compile Unit.
diff --git a/llvm/tools/llvm-debuginfo-analyzer/Options.cpp b/llvm/tools/llvm-debuginfo-analyzer/Options.cpp
index 86ca87376348d..79e2edccc50b8 100644
--- a/llvm/tools/llvm-debuginfo-analyzer/Options.cpp
+++ b/llvm/tools/llvm-debuginfo-analyzer/Options.cpp
@@ -89,6 +89,8 @@ cl::list<LVAttributeKind> cmdline::AttributeOptions(
                       "Element referenced across Compile Units."),
            clEnumValN(LVAttributeKind::Inserted, "inserted",
                       "Generated inlined abstract references."),
+           clEnumValN(LVAttributeKind::Language, "language",
+                      "Source language name."),
            clEnumValN(LVAttributeKind::Level, "level",
                       "Lexical scope level (File=0, Compile Unit=1)."),
            clEnumValN(LVAttributeKind::Linkage, "linkage", "Linkage name."),
diff --git a/llvm/unittests/DebugInfo/LogicalView/CodeViewReaderTest.cpp b/llvm/unittests/DebugInfo/LogicalView/CodeViewReaderTest.cpp
index 613a417db0f95..f9aa050832c09 100644
--- a/llvm/unittests/DebugInfo/LogicalView/CodeViewReaderTest.cpp
+++ b/llvm/unittests/DebugInfo/LogicalView/CodeViewReaderTest.cpp
@@ -79,6 +79,10 @@ void checkElementPropertiesClangCodeview(LVReader *Reader) {
   EXPECT_EQ(CompileUnit->getBaseAddress(), 0u);
   EXPECT_TRUE(CompileUnit->getProducer().starts_with("clang"));
   EXPECT_EQ(CompileUnit->getName(), "test.cpp");
+  LVSourceLanguage Language = CompileUnit->getSourceLanguage();
+  EXPECT_TRUE(Language.isValid());
+  ASSERT_EQ(Language, LVSourceLanguage::CV_LANG_Cpp);
+  ASSERT_EQ(Language.getName(), "Cpp");
 
   EXPECT_EQ(Function->lineCount(), 16u);
   EXPECT_EQ(Function->scopeCount(), 1u);
@@ -453,6 +457,7 @@ void elementProperties(SmallString<128> &InputsDir) {
   ReaderOptions.setAttributeProducer();
   ReaderOptions.setAttributePublics();
   ReaderOptions.setAttributeRange();
+  ReaderOptions.setAttributeLanguage();
   ReaderOptions.setAttributeLocation();
   ReaderOptions.setAttributeSize();
   ReaderOptions.setPrintAll();
diff --git a/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp b/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp
index c409f24130d83..544c39a3c7b2e 100644
--- a/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp
+++ b/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp
@@ -76,6 +76,10 @@ void checkElementProperties(LVReader *Reader) {
   EXPECT_EQ(CompileUnit->getBaseAddress(), 0u);
   EXPECT_TRUE(CompileUnit->getProducer().starts_with("clang"));
   EXPECT_EQ(CompileUnit->getName(), "test.cpp");
+  LVSourceLanguage Language = CompileUnit->getSourceLanguage();
+  EXPECT_TRUE(Language.isValid());
+  EXPECT_EQ(Language, LVSourceLanguage::DW_LANG_C_plus_plus_14);
+  EXPECT_EQ(Language.getName(), "DW_LANG_C_plus_plus_14");
 
   EXPECT_EQ(CompileUnit->lineCount(), 0u);
   EXPECT_EQ(CompileUnit->scopeCount(), 1u);
@@ -315,6 +319,7 @@ void elementProperties(SmallString<128> &InputsDir) {
   ReaderOptions.setAttributeProducer();
   ReaderOptions.setAttributePublics();
   ReaderOptions.setAttributeRange();
+  ReaderOptions.setAttributeLanguage();
   ReaderOptions.setAttributeLocation();
   ReaderOptions.setAttributeInserted();
   ReaderOptions.setAttributeSize();



More information about the llvm-commits mailing list