debuginfod: Add CORS (webapp access) support to webapi.
+libdw: Add dwarf_language and dwarf_language_lower_bound functions.
+
Version 0.192 "New rules, faster tools"
CONDUCT: A new code of conduct has been adopted. See the
/* Compute size of an aggregate type from DWARF.
Copyright (C) 2010, 2014, 2016 Red Hat, Inc.
+ Copyright (C) 2025, Mark J. Wielaard <mark@klomp.org>
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
}
else
{
+ Dwarf_Word lang;
Dwarf_Die cu = CUDIE (die->cu);
- int lang = INTUSE(dwarf_srclang) (&cu);
- if (lang == -1
- || INTUSE(dwarf_default_lower_bound) (lang, &lower) != 0)
+ int res = INTUSE(dwarf_language) (&cu, &lang, NULL);
+ if (res < 0
+ || INTUSE(dwarf_language_lower_bound) (lang, &lower) != 0)
return -1;
}
if (unlikely (lower > upper))
/* Get the default subrange lower bound for a given language.
Copyright (C) 2016 Red Hat, Inc.
- Copyright (C) 2024 Mark J. Wielaard <mark@klomp.org>
+ Copyright (C) 2024, 2025 Mark J. Wielaard <mark@klomp.org>
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
}
}
INTDEF (dwarf_default_lower_bound)
+
+/* Determine default lower bound from language, as per the DWARF6
+ https://dwarfstd.org/languages-v6.html table. */
+int
+dwarf_language_lower_bound (Dwarf_Word lang, Dwarf_Sword *result)
+{
+ switch (lang)
+ {
+ case DW_LNAME_BLISS:
+ case DW_LNAME_C:
+ case DW_LNAME_C_plus_plus:
+ case DW_LNAME_Crystal:
+ case DW_LNAME_D:
+ case DW_LNAME_Dylan:
+ case DW_LNAME_Go:
+ case DW_LNAME_Haskell:
+ case DW_LNAME_Java:
+ case DW_LNAME_Kotlin:
+ case DW_LNAME_ObjC:
+ case DW_LNAME_ObjC_plus_plus:
+ case DW_LNAME_OCaml:
+ case DW_LNAME_OpenCL_C:
+ case DW_LNAME_Python:
+ case DW_LNAME_RenderScript:
+ case DW_LNAME_Rust:
+ case DW_LNAME_Swift:
+ case DW_LNAME_UPC:
+ case DW_LNAME_Zig:
+ case DW_LNAME_Assembly:
+ case DW_LNAME_C_sharp:
+ case DW_LNAME_Mojo:
+ case DW_LNAME_GLSL:
+ case DW_LNAME_GLSL_ES:
+ case DW_LNAME_HLSL:
+ case DW_LNAME_OpenCL_CPP:
+ case DW_LNAME_CPP_for_OpenCL:
+ case DW_LNAME_SYCL:
+ case DW_LNAME_Ruby:
+ case DW_LNAME_Move:
+ case DW_LNAME_Hylo:
+ case DW_LNAME_HIP:
+ case DW_LNAME_Odin:
+ case DW_LNAME_P4:
+ case DW_LNAME_Metal:
+ case DW_LNAME_V:
+ *result = 0;
+ return 0;
+
+ case DW_LNAME_Ada:
+ case DW_LNAME_Cobol:
+ case DW_LNAME_Fortran:
+ case DW_LNAME_Julia:
+ case DW_LNAME_Modula2:
+ case DW_LNAME_Modula3:
+ case DW_LNAME_Pascal:
+ case DW_LNAME_PLI:
+ case DW_LNAME_Algol68:
+ *result = 1;
+ return 0;
+
+ default:
+ __libdw_seterrno (DWARF_E_UNKNOWN_LANGUAGE);
+ return -1;
+ }
+}
+INTDEF (dwarf_language_lower_bound)
/* Get function information.
Copyright (C) 2005, 2013, 2015 Red Hat, Inc.
- Copyright (C) 2024 Mark J. Wielaard <mark@klomp.org>
+ Copyright (C) 2024, 2025 Mark J. Wielaard <mark@klomp.org>
This file is part of elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 2005.
|| INTUSE(dwarf_tag) (cudie) != DW_TAG_compile_unit))
return -1;
- int lang = INTUSE(dwarf_srclang) (cudie);
- bool c_cu = (lang == DW_LANG_C89
- || lang == DW_LANG_C
- || lang == DW_LANG_C99
- || lang == DW_LANG_C11
- || lang == DW_LANG_C17
- || lang == DW_LANG_C23);
+ Dwarf_Word lang;
+ bool c_cu = (INTUSE(dwarf_language) (cudie, &lang, NULL) == 0
+ && lang == DW_LNAME_C);
struct visitor_info v = { callback, arg, (void *) offset, NULL, c_cu };
struct Dwarf_Die_Chain chain = { .die = CUDIE (cudie->cu),
/* Return source language attribute of DIE.
Copyright (C) 2003-2010 Red Hat, Inc.
+ Copyright (C) 2025 Mark J. Wielaard <mark@klomp.org>
This file is part of elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 2003.
#include "libdwP.h"
+static int srclang_to_language (Dwarf_Word srclang,
+ Dwarf_Word *lname,
+ Dwarf_Word *lversion)
+{
+ switch (srclang)
+ {
+ case DW_LANG_C89:
+ *lname = DW_LNAME_C;
+ *lversion = 198912;
+ return 0;
+ case DW_LANG_C:
+ *lname = DW_LNAME_C;
+ *lversion = 0;
+ return 0;
+ case DW_LANG_Ada83:
+ *lname = DW_LNAME_Ada;
+ *lversion = 1983;
+ return 0;
+ case DW_LANG_C_plus_plus:
+ *lname = DW_LNAME_C_plus_plus;
+ *lversion = 199711;
+ return 0;
+ case DW_LANG_Cobol74:
+ *lname = DW_LNAME_Cobol;
+ *lversion = 1974;
+ return 0;
+ case DW_LANG_Cobol85:
+ *lname = DW_LNAME_Cobol;
+ *lversion = 1985;
+ return 0;
+ case DW_LANG_Fortran77:
+ *lname = DW_LNAME_Fortran;
+ *lversion = 1977;
+ return 0;
+ case DW_LANG_Fortran90:
+ *lname = DW_LNAME_Fortran;
+ *lversion = 1990;
+ return 0;
+ case DW_LANG_Pascal83:
+ *lname = DW_LNAME_Pascal;
+ *lversion = 1983;
+ return 0;
+ case DW_LANG_Modula2:
+ *lname = DW_LNAME_Modula2;
+ *lversion = 0;
+ return 0;
+ case DW_LANG_Java:
+ *lname = DW_LNAME_Java;
+ *lversion = 0;
+ return 0;
+ case DW_LANG_C99:
+ *lname = DW_LNAME_C;
+ *lversion = 199901;
+ return 0;
+ case DW_LANG_Ada95:
+ *lname = DW_LNAME_Ada;
+ *lversion = 1995;
+ return 0;
+ case DW_LANG_Fortran95:
+ *lname = DW_LNAME_Fortran;
+ *lversion = 1995;
+ return 0;
+ case DW_LANG_PLI:
+ *lname = DW_LNAME_PLI;
+ *lversion = 0;
+ return 0;
+ case DW_LANG_ObjC:
+ *lname = DW_LNAME_ObjC;
+ *lversion = 0;
+ return 0;
+ case DW_LANG_ObjC_plus_plus:
+ *lname = DW_LNAME_ObjC_plus_plus;
+ *lversion = 0;
+ return 0;
+ case DW_LANG_UPC:
+ *lname = DW_LNAME_UPC;
+ *lversion = 0;
+ return 0;
+ case DW_LANG_D:
+ *lname = DW_LNAME_D;
+ *lversion = 0;
+ return 0;
+ case DW_LANG_Python:
+ *lname = DW_LNAME_Python;
+ *lversion = 0;
+ return 0;
+ case DW_LANG_OpenCL:
+ *lname = DW_LNAME_OpenCL_C;
+ *lversion = 0;
+ return 0;
+ case DW_LANG_Go:
+ *lname = DW_LNAME_Go;
+ *lversion = 0;
+ return 0;
+ case DW_LANG_Modula3:
+ *lname = DW_LNAME_Modula3;
+ *lversion = 0;
+ return 0;
+ case DW_LANG_Haskell:
+ *lname = DW_LNAME_Haskell;
+ *lversion = 0;
+ return 0;
+ case DW_LANG_C_plus_plus_03:
+ *lname = DW_LNAME_C_plus_plus;
+ *lversion = 199711; /* This is really just c++98. */
+ return 0;
+ case DW_LANG_C_plus_plus_11:
+ *lname = DW_LNAME_C_plus_plus;
+ *lversion = 201103;
+ return 0;
+ case DW_LANG_OCaml:
+ *lname = DW_LNAME_OCaml;
+ *lversion = 0;
+ return 0;
+ case DW_LANG_Rust:
+ *lname = DW_LNAME_Rust;
+ *lversion = 0;
+ return 0;
+ case DW_LANG_C11:
+ *lname = DW_LNAME_C;
+ *lversion = 201112;
+ return 0;
+ case DW_LANG_Swift:
+ *lname = DW_LNAME_Swift;
+ *lversion = 0;
+ return 0;
+ case DW_LANG_Julia:
+ *lname = DW_LNAME_Julia;
+ *lversion = 0;
+ return 0;
+ case DW_LANG_C_plus_plus_14:
+ *lname = DW_LNAME_C_plus_plus;
+ *lversion = 201402;
+ return 0;
+ case DW_LANG_Fortran03:
+ *lname = DW_LNAME_Fortran;
+ *lversion = 2003;
+ return 0;
+ case DW_LANG_Fortran08:
+ *lname = DW_LNAME_Fortran;
+ *lversion = 2008;
+ return 0;
+ case DW_LANG_RenderScript:
+ *lname = DW_LNAME_RenderScript;
+ *lversion = 0;
+ return 0;
+ case DW_LANG_BLISS:
+ *lname = DW_LNAME_BLISS;
+ *lversion = 0;
+ return 0;
+ case DW_LANG_Kotlin:
+ *lname = DW_LNAME_Kotlin;
+ *lversion = 0;
+ return 0;
+ case DW_LANG_Zig:
+ *lname = DW_LNAME_Zig;
+ *lversion = 0;
+ return 0;
+ case DW_LANG_Crystal:
+ *lname = DW_LNAME_Crystal;
+ *lversion = 0;
+ return 0;
+ case DW_LANG_C_plus_plus_17:
+ *lname = DW_LANG_C_plus_plus;
+ *lversion = 201703;
+ return 0;
+ case DW_LANG_C_plus_plus_20:
+ *lname = DW_LANG_C_plus_plus;
+ *lversion = 202002;
+ return 0;
+ case DW_LANG_C17:
+ *lname = DW_LNAME_C;
+ *lversion = 201710;
+ return 0;
+ case DW_LANG_Fortran18:
+ *lname = DW_LNAME_Fortran;
+ *lversion = 2018;
+ return 0;
+ case DW_LANG_Ada2005:
+ *lname = DW_LNAME_Ada;
+ *lversion = 2005;
+ return 0;
+ case DW_LANG_Ada2012:
+ *lname = DW_LNAME_Ada;
+ *lversion = 2012;
+ return 0;
+ case DW_LANG_HIP:
+ *lname = DW_LNAME_HIP;
+ *lversion = 0;
+ return 0;
+ case DW_LANG_Assembly:
+ case DW_LANG_Mips_Assembler:
+ *lname = DW_LNAME_Assembly;
+ *lversion = 0;
+ return 0;
+ case DW_LANG_C_sharp:
+ *lname = DW_LNAME_C_sharp;
+ *lversion = 0;
+ return 0;
+ case DW_LANG_Mojo:
+ *lname = DW_LNAME_Mojo;
+ *lversion = 0;
+ return 0;
+ case DW_LANG_GLSL:
+ *lname = DW_LNAME_GLSL;
+ *lversion = 0;
+ return 0;
+ case DW_LANG_GLSL_ES:
+ *lname = DW_LNAME_GLSL_ES;
+ *lversion = 0;
+ return 0;
+ case DW_LANG_HLSL:
+ *lname = DW_LNAME_HLSL;
+ *lversion = 0;
+ return 0;
+ case DW_LANG_OpenCL_CPP:
+ *lname = DW_LNAME_OpenCL_CPP;
+ *lversion = 0;
+ return 0;
+ case DW_LANG_CPP_for_OpenCL:
+ *lname = DW_LNAME_CPP_for_OpenCL;
+ *lversion = 0;
+ return 0;
+ case DW_LANG_SYCL:
+ *lname = DW_LNAME_SYCL;
+ *lversion = 0;
+ return 0;
+ case DW_LANG_C_plus_plus_23:
+ *lname = DW_LNAME_C_plus_plus;
+ *lversion = 202302;
+ return 0;
+ case DW_LANG_Odin:
+ *lname = DW_LNAME_Odin;
+ *lversion = 0;
+ return 0;
+ case DW_LANG_P4:
+ *lname = DW_LNAME_P4;
+ *lversion = 0;
+ return 0;
+ case DW_LANG_Metal:
+ *lname = DW_LNAME_Metal;
+ *lversion = 0;
+ return 0;
+ case DW_LANG_C23:
+ *lname = DW_LNAME_C;
+ *lversion = 202311;
+ return 0;
+ case DW_LANG_Fortran23:
+ *lname = DW_LNAME_Fortran;
+ *lversion = 2023;
+ return 0;
+ case DW_LANG_Ruby:
+ *lname = DW_LNAME_Ruby;
+ *lversion = 0;
+ return 0;
+ case DW_LANG_Move:
+ *lname = DW_LNAME_Move;
+ *lversion = 0;
+ return 0;
+ case DW_LANG_Hylo:
+ *lname = DW_LNAME_Hylo;
+ *lversion = 0;
+ return 0;
+ default:
+ __libdw_seterrno (DWARF_E_UNKNOWN_LANGUAGE);
+ return -1;
+ }
+}
+
NEW_VERSION (dwarf_srclang, ELFUTILS_0.143)
int
dwarf_srclang (Dwarf_Die *die)
}
NEW_INTDEF (dwarf_srclang)
OLD_VERSION (dwarf_srclang, ELFUTILS_0.122)
+
+int
+dwarf_language (Dwarf_Die *cudie, Dwarf_Word *lname, Dwarf_Word *lversion)
+{
+ Dwarf_Attribute attr;
+ Dwarf_Word val;
+
+ int res = INTUSE(dwarf_formudata) (INTUSE(dwarf_attr_integrate)
+ (cudie, DW_AT_language_name, &attr),
+ &val);
+ if (res == 0)
+ {
+ *lname = val;
+ if (lversion != NULL)
+ {
+ /* We like to get the version, but given we already have the
+ lang, we will ignore errors here and just return zero as
+ version. */
+ res = INTUSE(dwarf_formudata) (INTUSE(dwarf_attr_integrate)
+ (cudie, DW_AT_language_version,
+ &attr), &val);
+ *lversion = (res == 0) ? val : 0;
+ }
+ }
+ else
+ {
+ /* Try the get the old style pre DWARF6 DW_AT_LANG and translate
+ that to the new language name/version style. */
+ res = INTUSE(dwarf_formudata) (INTUSE(dwarf_attr_integrate)
+ (cudie, DW_AT_language, &attr), &val);
+ if (res == 0)
+ {
+ Dwarf_Word version;
+ res = srclang_to_language (val, lname, (lversion == NULL
+ ? &version : lversion));
+ }
+ }
+
+ return res;
+}
+INTDEF (dwarf_language)
/* Return array order attribute of DIE. */
extern int dwarf_arrayorder (Dwarf_Die *die);
-/* Return source language attribute of DIE. */
-extern int dwarf_srclang (Dwarf_Die *die);
+/* Return DW_LANG source language of CU DIE.
+ Returns the DW_LANG constant on success, -1 otherwise. */
+extern int dwarf_srclang (Dwarf_Die *cudie);
+
+/* Provides the DW_LNAME source language and version of the given CU
+ DIE. LVERSION may be NULL. Returns zero on success. */
+extern int dwarf_language (Dwarf_Die *cudie,
+ Dwarf_Word *lname,
+ Dwarf_Word *lversion) __nonnull_attribute__ (2);
/* Get abbreviation at given offset for given DIE. */
For DW_TAG_array_type it can apply much more complex rules. */
extern int dwarf_aggregate_size (Dwarf_Die *die, Dwarf_Word *size);
-/* Given a language code, as returned by dwarf_srclan, get the default
- lower bound for a subrange type without a lower bound attribute.
- Returns zero on success or -1 on failure when the given language
- wasn't recognized. */
+/* Given a DW_LANG language code, as returned by dwarf_srclang, get
+ the default lower bound for a subrange type without a lower bound
+ attribute. Returns zero on success or -1 on failure when the given
+ language wasn't recognized. */
extern int dwarf_default_lower_bound (int lang, Dwarf_Sword *result)
__nonnull_attribute__ (2);
+/* Given a DW_LNAME language code, as returned by dwarf_language, get
+ the default lower bound for a subrange type without a lower bound
+ attribute. Returns zero on success or -1 on failure when the given
+ language wasn't recognized. */
+extern int dwarf_language_lower_bound (Dwarf_Word lname, Dwarf_Sword *result)
+ __nonnull_attribute__ (2);
+
/* Return scope DIEs containing PC address.
Sets *SCOPES to a malloc'd array of Dwarf_Die structures,
and returns the number of elements in the array.
dwfl_frame_unwound_source;
dwfl_unwound_source_str;
} ELFUTILS_0.191;
+
+ELFUTILS_0.193 {
+ global:
+ dwarf_language;
+ dwarf_language_lower_bound;
+} ELFUTILS_0.192;
INTDECL (dwarf_haschildren)
INTDECL (dwarf_haspc)
INTDECL (dwarf_highpc)
+INTDECL (dwarf_language)
+INTDECL (dwarf_language_lower_bound)
INTDECL (dwarf_lowpc)
INTDECL (dwarf_nextcu)
INTDECL (dwarf_next_unit)
elfstrtab dwfl-proc-attach \
elfshphehdr elfstrmerge dwelfgnucompressed elfgetchdr \
elfgetzdata elfputzdata zstrptr emptyfile vendorelf \
- fillfile dwarf_default_lower_bound dwarf-die-addr-die \
+ fillfile dwarf_default_lower_bound \
+ dwarf_language_lower_bound dwarf-die-addr-die \
get-units-invalid get-units-split attr-integrate-skel \
all-dwarf-ranges unit-info next_cfi \
elfcopy addsections xlate_notes elfrdwrnop \
run-compress-test.sh \
run-readelf-zdebug.sh run-readelf-zdebug-rel.sh \
emptyfile vendorelf fillfile dwarf_default_lower_bound \
+ dwarf_language_lower_bound \
run-dwarf-die-addr-die.sh \
run-get-units-invalid.sh run-get-units-split.sh \
run-attr-integrate-skel.sh \
vendorelf_LDADD = $(libelf)
fillfile_LDADD = $(libelf)
dwarf_default_lower_bound_LDADD = $(libdw)
+dwarf_language_lower_bound_LDADD = $(libdw)
dwarf_die_addr_die_LDADD = $(libdw)
get_units_invalid_LDADD = $(libdw)
get_units_split_LDADD = $(libdw)
--- /dev/null
+/* Test all DW_LNAME constants are handled by dwarf_language_lower_bound.
+
+ Copyright (C) 2016 Red Hat, Inc.
+ Copyright (C) 2024, 2025 Mark J. Wielaard <mark@klomp.org>
+ This file is part of elfutils.
+
+ This file is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+#include ELFUTILS_HEADER(dw)
+#include "../libdw/known-dwarf.h"
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static void
+test_lang (const char *name, Dwarf_Word lang)
+{
+ Dwarf_Sword low;
+ int res = dwarf_language_lower_bound (lang, &low);
+
+ if (res != 0)
+ {
+ printf ("dwarf_language_lower_bound failed (%d) for %s\n", res, name);
+ exit (-1);
+ }
+
+ /* All currently known lower bounds are either zero or one, but
+ they don't have to. Update test once one is a different value. */
+ if (low != 0 && low != 1)
+ {
+ printf ("unexpected lower bound %" PRId64 " for %s\n", low, name);
+ exit (-1);
+ }
+
+ printf ("%s: %" PRId64 "\n", name, low);
+}
+
+int
+main (int argc __attribute__ ((unused)), char *argv[] __attribute__ ((unused)))
+{
+ Dwarf_Sword low;
+ /* Bad language code must fail. */
+ if (dwarf_language_lower_bound (-1, &low) == 0)
+ {
+ printf ("Bad lang code -1 succeeded (%" PRId64 ")\n", low);
+ exit (-1);
+ }
+
+ /* Test all known language codes. */
+#define DWARF_ONE_KNOWN_DW_LNAME(NAME, CODE) test_lang (#NAME, CODE);
+ DWARF_ALL_KNOWN_DW_LNAME
+#undef DWARF_ONE_KNOWN_DW_LNAME
+
+ return 0;
+}