dwarf_language returns a DW_LNAME constant for a CU Die. If the CU Die has a DW_AT_language_name attribute dwarf_language will return it and the DW_AT_language_version attribute value. Otherwise dwarf_language will lookup the (old style) DW_AT_language attribute and translate the DW_LANG constant into a DW_LNAME constant and version using a new static function srclang_to_language.
The dwarf_language_lower_bound function works just like the dwarf_default_lower_bound function, but takes a DW_LNAME constant instead of a DW_LANG constant. Adds a new test to make sure dwarf_language_lower_bound handles all known DW_LNAME constants. * NEWS: Add new functions. * libdw/libdw.map (ELFUTILS_0.193): New section with new functions. * libdw/libdw.h (dwarf_srclang): Add comment explaining this returns DW_LANG constants. (dwarf_language): New function. (dwarf_default_lower_bound): Add comment explaining this works on DW_LANG constants. (dwarf_language_lower_bound): New function. * libdw/libdwP.h: INTDECL dwarf_language and dwarf_language_lower_bound. * libdw/dwarf_srclang.c (srclang_to_language): New function. (dwarf_language): Likewise. * libdw/dwarf_default_lower_bound.c (dwarf_language_lower_bound): New function. * libdw/dwarf_getfuncs.c (dwarf_getfuncs): Use dwarf_language and dwarf_language_lower_bound. * libdw/dwarf_aggregate_size.c (array_size): Likewise. * tests/dwarf_language_lower_bound.c: New test. * tests/Makefile.am (check_PROGRAMS): Add dwarf_language_lower_bound. (TESTS): Likewise. (dwarf_language_lower_bound_LDADD): New variable. Signed-off-by: Mark Wielaard <m...@klomp.org> --- NEWS | 2 + libdw/dwarf_aggregate_size.c | 8 +- libdw/dwarf_default_lower_bound.c | 68 ++++++- libdw/dwarf_getfuncs.c | 12 +- libdw/dwarf_srclang.c | 311 +++++++++++++++++++++++++++++ libdw/libdw.h | 26 ++- libdw/libdw.map | 6 + libdw/libdwP.h | 2 + tests/Makefile.am | 5 +- tests/dwarf_language_lower_bound.c | 72 +++++++ 10 files changed, 493 insertions(+), 19 deletions(-) create mode 100644 tests/dwarf_language_lower_bound.c diff --git a/NEWS b/NEWS index 4cb5b2260fec..664c125b6eaa 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,8 @@ Version 0.193 (one after 0.192) 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 diff --git a/libdw/dwarf_aggregate_size.c b/libdw/dwarf_aggregate_size.c index 8216ae42e424..6579212abe96 100644 --- a/libdw/dwarf_aggregate_size.c +++ b/libdw/dwarf_aggregate_size.c @@ -1,5 +1,6 @@ /* Compute size of an aggregate type from DWARF. Copyright (C) 2010, 2014, 2016 Red Hat, Inc. + Copyright (C) 2025, Mark J. Wielaard <m...@klomp.org> This file is part of elfutils. This file is free software; you can redistribute it and/or modify @@ -131,10 +132,11 @@ array_size (Dwarf_Die *die, Dwarf_Word *size, } 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)) diff --git a/libdw/dwarf_default_lower_bound.c b/libdw/dwarf_default_lower_bound.c index f04ae46de0c5..7cc808b22488 100644 --- a/libdw/dwarf_default_lower_bound.c +++ b/libdw/dwarf_default_lower_bound.c @@ -1,6 +1,6 @@ /* Get the default subrange lower bound for a given language. Copyright (C) 2016 Red Hat, Inc. - Copyright (C) 2024 Mark J. Wielaard <m...@klomp.org> + Copyright (C) 2024, 2025 Mark J. Wielaard <m...@klomp.org> This file is part of elfutils. This file is free software; you can redistribute it and/or modify @@ -125,3 +125,69 @@ dwarf_default_lower_bound (int lang, Dwarf_Sword *result) } } 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) diff --git a/libdw/dwarf_getfuncs.c b/libdw/dwarf_getfuncs.c index f6968f0081d4..bfc5f5727bbd 100644 --- a/libdw/dwarf_getfuncs.c +++ b/libdw/dwarf_getfuncs.c @@ -1,6 +1,6 @@ /* Get function information. Copyright (C) 2005, 2013, 2015 Red Hat, Inc. - Copyright (C) 2024 Mark J. Wielaard <m...@klomp.org> + Copyright (C) 2024, 2025 Mark J. Wielaard <m...@klomp.org> This file is part of elfutils. Written by Ulrich Drepper <drep...@redhat.com>, 2005. @@ -101,13 +101,9 @@ dwarf_getfuncs (Dwarf_Die *cudie, int (*callback) (Dwarf_Die *, void *), || 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), diff --git a/libdw/dwarf_srclang.c b/libdw/dwarf_srclang.c index 77bd58c2f703..aede449c69b6 100644 --- a/libdw/dwarf_srclang.c +++ b/libdw/dwarf_srclang.c @@ -1,5 +1,6 @@ /* Return source language attribute of DIE. Copyright (C) 2003-2010 Red Hat, Inc. + Copyright (C) 2025 Mark J. Wielaard <m...@klomp.org> This file is part of elfutils. Written by Ulrich Drepper <drep...@redhat.com>, 2003. @@ -35,6 +36,275 @@ #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) @@ -48,3 +318,44 @@ 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) diff --git a/libdw/libdw.h b/libdw/libdw.h index ec4713a6772a..9096f301f6e3 100644 --- a/libdw/libdw.h +++ b/libdw/libdw.h @@ -579,8 +579,15 @@ extern int dwarf_bitoffset (Dwarf_Die *die); /* 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. */ @@ -829,13 +836,20 @@ extern int dwarf_getlocation_attr (Dwarf_Attribute *attr, 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. diff --git a/libdw/libdw.map b/libdw/libdw.map index bc53385f61a6..e7baf3c4da2f 100644 --- a/libdw/libdw.map +++ b/libdw/libdw.map @@ -385,3 +385,9 @@ ELFUTILS_0.192 { dwfl_frame_unwound_source; dwfl_unwound_source_str; } ELFUTILS_0.191; + +ELFUTILS_0.193 { + global: + dwarf_language; + dwarf_language_lower_bound; +} ELFUTILS_0.192; diff --git a/libdw/libdwP.h b/libdw/libdwP.h index 0cff5c26cb82..7d9c12607c0c 100644 --- a/libdw/libdwP.h +++ b/libdw/libdwP.h @@ -496,6 +496,8 @@ INTDECL (dwarf_hasattr) 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) diff --git a/tests/Makefile.am b/tests/Makefile.am index 335f192583da..bf5a9b228126 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -56,7 +56,8 @@ check_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \ 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 \ @@ -203,6 +204,7 @@ TESTS = run-arextract.sh run-arsymtest.sh run-ar.sh newfile test-nlist \ 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 \ @@ -864,6 +866,7 @@ emptyfile_LDADD = $(libelf) 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) diff --git a/tests/dwarf_language_lower_bound.c b/tests/dwarf_language_lower_bound.c new file mode 100644 index 000000000000..6bb534ac72f3 --- /dev/null +++ b/tests/dwarf_language_lower_bound.c @@ -0,0 +1,72 @@ +/* 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 <m...@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; +} -- 2.48.1