For programs which use dwarf_srclang it might be useful to translate a
DW_LNAME (plus version) into a DW_LANG constant if there is no
DW_AT_language constant, but there is a DW_AT_language_name (and
DW_AT_language_version).

        * libdw/dwarf_srclang.c (language_to_srclang): New function.
        (dwarf_srclang): If there is no DW_AT_language, try
        DW_AT_language_name and DW_AT_language_version, use
        language_to_srclang.

Signed-off-by: Mark Wielaard <m...@klomp.org>
---
 libdw/dwarf_srclang.c | 221 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 218 insertions(+), 3 deletions(-)

diff --git a/libdw/dwarf_srclang.c b/libdw/dwarf_srclang.c
index aede449c69b6..948f44cb455e 100644
--- a/libdw/dwarf_srclang.c
+++ b/libdw/dwarf_srclang.c
@@ -305,6 +305,201 @@ static int srclang_to_language (Dwarf_Word srclang,
     }
 }
 
+static int
+language_to_srclang (Dwarf_Word lname, Dwarf_Word lversion, Dwarf_Word *value)
+{
+  switch (lname)
+    {
+    case DW_LNAME_Ada:
+      if (lversion <= 1983)
+       *value = DW_LANG_Ada83;
+      else if (lversion <= 1995)
+       *value = DW_LANG_Ada95;
+      else if (lversion <= 2005)
+       *value = DW_LANG_Ada2005;
+      else
+       *value = DW_LANG_Ada2012;
+      return 0;
+    case DW_LNAME_BLISS:
+      *value = DW_LANG_BLISS;
+      return 0;
+    case DW_LNAME_C:
+      if (lversion == 0)
+       *value = DW_LANG_C;
+      else if (lversion <= 198912)
+       *value = DW_LANG_C89;
+      else if (lversion <= 199901)
+       *value = DW_LANG_C99;
+      else if (lversion <= 201112)
+       *value = DW_LANG_C11;
+      else if (lversion <= 201710)
+       *value = DW_LANG_C17;
+      else
+       *value = DW_LANG_C23;
+      return 0;
+    case DW_LNAME_C_plus_plus:
+      if (lversion <= 199711)
+       *value = DW_LANG_C_plus_plus;
+      else if (lversion <= 201103)
+       *value = DW_LANG_C_plus_plus_11;
+      else if (lversion <= 201402)
+       *value = DW_LANG_C_plus_plus_14;
+      else if (lversion <= 201703)
+       *value = DW_LANG_C_plus_plus_17;
+      else if (lversion <= 202002)
+       *value = DW_LANG_C_plus_plus_20;
+      else
+       *value = DW_LANG_C_plus_plus_23;
+      return 0;
+    case DW_LNAME_Cobol:
+      if (lversion <= 1974)
+       *value = DW_LANG_Cobol74;
+      else
+       *value = DW_LANG_Cobol85;
+      return 0;
+    case DW_LNAME_Crystal:
+      *value = DW_LANG_Crystal;
+      return 0;
+    case DW_LNAME_D:
+      *value = DW_LANG_D;
+      return 0;
+    case DW_LNAME_Dylan:
+      *value = DW_LANG_Dylan;
+      return 0;
+    case DW_LNAME_Fortran:
+      if (lversion <= 1977)
+       *value = DW_LANG_Fortran77;
+      else if (lversion <= 1990)
+       *value = DW_LANG_Fortran90;
+      else if (lversion <= 1995)
+       *value = DW_LANG_Fortran95;
+      else if (lversion <= 2003)
+       *value = DW_LANG_Fortran03;
+      else if (lversion <= 2008)
+       *value = DW_LANG_Fortran08;
+      else if (lversion <= 2018)
+       *value = DW_LANG_Fortran18;
+      else
+       *value = DW_LANG_Fortran23;
+      return 0;
+    case DW_LNAME_Go:
+      *value = DW_LANG_Go;
+      return 0;
+    case DW_LNAME_Haskell:
+      *value = DW_LANG_Haskell;
+      return 0;
+    case DW_LNAME_Java:
+      *value = DW_LANG_Java;
+      return 0;
+    case DW_LNAME_Julia:
+      *value = DW_LANG_Julia;
+      return 0;
+    case DW_LNAME_Kotlin:
+      *value = DW_LANG_Kotlin;
+      return 0;
+    case DW_LNAME_Modula2:
+      *value = DW_LANG_Modula2;
+      return 0;
+    case DW_LNAME_Modula3:
+      *value = DW_LANG_Modula3;
+      return 0;
+    case DW_LNAME_ObjC:
+      *value = DW_LANG_ObjC;
+      return 0;
+    case DW_LNAME_ObjC_plus_plus:
+      *value = DW_LANG_ObjC_plus_plus;
+      return 0;
+    case DW_LNAME_OCaml:
+      *value = DW_LANG_OCaml;
+      return 0;
+    case DW_LNAME_OpenCL_C:
+      *value = DW_LANG_OpenCL;
+      return 0;
+    case DW_LNAME_Pascal:
+      *value = DW_LANG_Pascal83;
+      return 0;
+    case DW_LNAME_PLI:
+      *value = DW_LANG_PLI;
+      return 0;
+    case DW_LNAME_Python:
+      *value = DW_LANG_Python;
+      return 0;
+    case DW_LNAME_RenderScript:
+      *value = DW_LANG_RenderScript;
+      return 0;
+    case DW_LNAME_Rust:
+      *value = DW_LANG_Rust;
+      return 0;
+    case DW_LNAME_Swift:
+      *value = DW_LANG_Swift;
+      return 0;
+    case DW_LNAME_UPC:
+      *value = DW_LANG_UPC;
+      return 0;
+    case DW_LNAME_Zig:
+      *value = DW_LANG_Zig;
+      return 0;
+    case DW_LNAME_Assembly:
+      /* DW_LANG_Assembler is not as good for compatibility.  */
+      *value = DW_LANG_Mips_Assembler;
+      return 0;
+    case DW_LNAME_C_sharp:
+      *value = DW_LANG_C_sharp;
+      return 0;
+    case DW_LNAME_Mojo:
+      *value = DW_LANG_Move;
+      return 0;
+    case DW_LNAME_GLSL:
+      *value = DW_LANG_GLSL;
+      return 0;
+    case DW_LNAME_GLSL_ES:
+      *value = DW_LANG_GLSL_ES;
+      return 0;
+    case DW_LNAME_HLSL:
+      *value = DW_LANG_HLSL;
+      return 0;
+    case DW_LNAME_OpenCL_CPP:
+      *value = DW_LANG_OpenCL_CPP;
+      return 0;
+    case DW_LNAME_CPP_for_OpenCL:
+      *value = DW_LANG_CPP_for_OpenCL;
+      return 0;
+    case DW_LNAME_SYCL:
+      *value = DW_LANG_SYCL;
+      return 0;
+    case DW_LNAME_Ruby:
+      *value = DW_LANG_Ruby;
+      return 0;
+    case DW_LNAME_Move:
+      *value = DW_LANG_Move;
+      return 0;
+    case DW_LNAME_Hylo:
+      *value = DW_LANG_Hylo;
+      return 0;
+    case DW_LNAME_HIP:
+      *value = DW_LANG_HIP;
+      return 0;
+    case DW_LNAME_Odin:
+      *value = DW_LANG_Odin;
+      return 0;
+    case DW_LNAME_P4:
+      *value = DW_LANG_P4;
+      return 0;
+    case DW_LNAME_Metal:
+      *value = DW_LANG_Metal;
+      return 0;
+    case DW_LNAME_V:
+      *value = DW_LANG_V;
+      return 0;
+    case DW_LNAME_Algol68:
+      *value = DW_LANG_Algol68;
+      return 0;
+    default:
+      __libdw_seterrno (DWARF_E_UNKNOWN_LANGUAGE);
+      return -1;
+    }
+}
+
 NEW_VERSION (dwarf_srclang, ELFUTILS_0.143)
 int
 dwarf_srclang (Dwarf_Die *die)
@@ -312,9 +507,29 @@ dwarf_srclang (Dwarf_Die *die)
   Dwarf_Attribute attr_mem;
   Dwarf_Word value;
 
-  return INTUSE(dwarf_formudata) (INTUSE(dwarf_attr_integrate)
-                                 (die, DW_AT_language, &attr_mem),
-                                 &value) == 0 ? (int) value : -1;
+  int res = INTUSE(dwarf_formudata) (INTUSE(dwarf_attr_integrate)
+                                    (die, DW_AT_language, &attr_mem),
+                                    &value) == 0 ? (int) value : -1;
+  if (res == -1)
+    {
+      res = INTUSE(dwarf_formudata) (INTUSE(dwarf_attr_integrate)
+                                    (die, DW_AT_language_name, &attr_mem),
+                                    &value);
+      if (res == 0)
+       {
+         Dwarf_Word lname = value;
+         Dwarf_Word lversion;
+         res = INTUSE(dwarf_formudata) (INTUSE(dwarf_attr_integrate)
+                                        (die, DW_AT_language_version,
+                                         &attr_mem), &value);
+         lversion = (res == 0) ? value : 0;
+         res = language_to_srclang (lname, lversion, &value);
+         if (res == 0)
+           res = (int) value;
+       }
+    }
+
+  return res;
 }
 NEW_INTDEF (dwarf_srclang)
 OLD_VERSION (dwarf_srclang, ELFUTILS_0.122)
-- 
2.48.1

Reply via email to