diff options
| -rw-r--r-- | libdw/ChangeLog | 12 | ||||
| -rw-r--r-- | libdw/Makefile.am | 3 | ||||
| -rw-r--r-- | libdw/dwarf_begin_elf.c | 21 | ||||
| -rw-r--r-- | libdw/dwarf_getsrclines.c | 16 | ||||
| -rw-r--r-- | libdw/dwarf_next_lines.c | 197 | ||||
| -rw-r--r-- | libdw/libdw.h | 18 | ||||
| -rw-r--r-- | libdw/libdw.map | 5 | ||||
| -rw-r--r-- | src/ChangeLog | 6 | ||||
| -rw-r--r-- | src/readelf.c | 78 | ||||
| -rw-r--r-- | tests/ChangeLog | 14 | ||||
| -rw-r--r-- | tests/Makefile.am | 7 | ||||
| -rw-r--r-- | tests/next-files.c | 93 | ||||
| -rw-r--r-- | tests/next-lines.c | 144 | ||||
| -rwxr-xr-x | tests/run-next-files.sh | 165 | ||||
| -rwxr-xr-x | tests/run-next-lines.sh | 116 | ||||
| -rw-r--r-- | tests/testfile-only-debug-line.bz2 | bin | 0 -> 2514 bytes |
16 files changed, 833 insertions, 62 deletions
diff --git a/libdw/ChangeLog b/libdw/ChangeLog index 11de763f..4e4fd265 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,3 +1,15 @@ +2018-06-25 Mark Wielaard <[email protected]> + + * Makefile.am (libdw_a_SOURCES): Add dwarf_next_lines.c. + * libdw.h (dwarf_next_lines): New function declaration. + * libdw.map (ELFUTILS_0.173): New section. + * dwarf_next_lines.c: New files. + * dwarf_begin_elf.c (check_section): Don't error out when elf + decompression fails. + (valid_p): Allow just a single .debug_line section. + * dwarf_getsrclines.c (read_srclines): Keep files relative if comp_dir + is missing. + 2018-06-22 Mark Wielaard <[email protected]> * dwarf_nextcu.c (__libdw_next_unit): Set next_off to -1 when it would diff --git a/libdw/Makefile.am b/libdw/Makefile.am index 41df4f3b..7a3d5322 100644 --- a/libdw/Makefile.am +++ b/libdw/Makefile.am @@ -91,7 +91,8 @@ libdw_a_SOURCES = dwarf_begin.c dwarf_begin_elf.c dwarf_end.c dwarf_getelf.c \ dwarf_getalt.c dwarf_setalt.c dwarf_cu_getdwarf.c \ dwarf_cu_die.c dwarf_peel_type.c dwarf_default_lower_bound.c \ dwarf_die_addr_die.c dwarf_get_units.c \ - libdw_find_split_unit.c dwarf_cu_info.c + libdw_find_split_unit.c dwarf_cu_info.c \ + dwarf_next_lines.c if MAINTAINER_MODE BUILT_SOURCES = $(srcdir)/known-dwarf.h diff --git a/libdw/dwarf_begin_elf.c b/libdw/dwarf_begin_elf.c index 513af2b1..e1542c75 100644 --- a/libdw/dwarf_begin_elf.c +++ b/libdw/dwarf_begin_elf.c @@ -156,17 +156,9 @@ check_section (Dwarf *result, GElf_Ehdr *ehdr, Elf_Scn *scn, bool inscngrp) { if (elf_compress (scn, 0, 0) < 0) { - /* If we failed to decompress the section and it's the - debug_info section, then fail with specific error rather - than the generic NO_DWARF. Without debug_info we can't do - anything (see also valid_p()). */ - if (cnt == IDX_debug_info) - { - Dwarf_Sig8_Hash_free (&result->sig8_hash); - __libdw_seterrno (DWARF_E_COMPRESSED_ERROR); - free (result); - return NULL; - } + /* It would be nice if we could fail with a specific error. + But we don't know if this was an essential section or not. + So just continue for now. See also valid_p(). */ return result; } } @@ -214,11 +206,10 @@ valid_p (Dwarf *result) /* We looked at all the sections. Now determine whether all the sections with debugging information we need are there. - XXX Which sections are absolutely necessary? Add tests if - necessary. For now we require only .debug_info. Hopefully this - is correct. */ + Require at least one section that can be read "standalone". */ if (likely (result != NULL) - && unlikely (result->sectiondata[IDX_debug_info] == NULL)) + && unlikely (result->sectiondata[IDX_debug_info] == NULL + && result->sectiondata[IDX_debug_line] == NULL)) { Dwarf_Sig8_Hash_free (&result->sig8_hash); __libdw_seterrno (DWARF_E_NO_DWARF); diff --git a/libdw/dwarf_getsrclines.c b/libdw/dwarf_getsrclines.c index 85105387..1432b1db 100644 --- a/libdw/dwarf_getsrclines.c +++ b/libdw/dwarf_getsrclines.c @@ -508,11 +508,10 @@ read_srclines (Dwarf *dbg, { /* This value could be NULL in case the DW_AT_comp_dir was not present. We cannot do much in this case. - The easiest thing is to convert the path in an - absolute path. */ + Just keep the file relative. */ cp = stpcpy (cp, dirarray[diridx].dir); + *cp++ = '/'; } - *cp++ = '/'; strcpy (cp, fname); assert (strlen (new_file->info.name) < dirarray[diridx].len + 1 + fnamelen + 1); @@ -803,11 +802,12 @@ read_srclines (Dwarf *dbg, if (dirarray[diridx].dir != NULL) /* This value could be NULL in case the DW_AT_comp_dir was not present. We - cannot do much in this case. The easiest - thing is to convert the path in an - absolute path. */ - cp = stpcpy (cp, dirarray[diridx].dir); - *cp++ = '/'; + cannot do much in this case. Just + keep the file relative. */ + { + cp = stpcpy (cp, dirarray[diridx].dir); + *cp++ = '/'; + } strcpy (cp, fname); } diff --git a/libdw/dwarf_next_lines.c b/libdw/dwarf_next_lines.c new file mode 100644 index 00000000..9b76b47e --- /dev/null +++ b/libdw/dwarf_next_lines.c @@ -0,0 +1,197 @@ +/* Iterate through the debug line table. + Copyright (C) 2018 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <libdwP.h> + + +int +dwarf_next_lines (Dwarf *dbg, Dwarf_Off off, + Dwarf_Off *next_off, Dwarf_CU **cu, + Dwarf_Files **srcfiles, size_t *nfiles, + Dwarf_Lines **srclines, size_t *nlines) +{ + /* Ignore existing errors. */ + if (dbg == NULL) + return -1; + + Elf_Data *lines = dbg->sectiondata[IDX_debug_line]; + if (lines == NULL) + { + __libdw_seterrno (DWARF_E_NO_DEBUG_LINE); + return -1; + } + + if (off == (Dwarf_Off) -1 + || lines->d_size < 4 + || off >= lines->d_size) + { + *next_off = (Dwarf_Off) -1; + return 1; + } + + /* Read enough of the header to know where the next table is and + whether we need to lookup the CU (version < 5). */ + const unsigned char *linep = lines->d_buf + off; + const unsigned char *lineendp = lines->d_buf + lines->d_size; + + if ((size_t) (lineendp - linep) < 4) + { + invalid_data: + __libdw_seterrno (DWARF_E_INVALID_DEBUG_LINE); + return -1; + } + + *next_off = off + 4; + Dwarf_Word unit_length = read_4ubyte_unaligned_inc (dbg, linep); + if (unit_length == DWARF3_LENGTH_64_BIT) + { + if ((size_t) (lineendp - linep) < 8) + goto invalid_data; + unit_length = read_8ubyte_unaligned_inc (dbg, linep); + *next_off += 8; + } + + if (unit_length > (size_t) (lineendp - linep)) + goto invalid_data; + + *next_off += unit_length; + lineendp = linep + unit_length; + + if ((size_t) (lineendp - linep) < 2) + goto invalid_data; + uint_fast16_t version = read_2ubyte_unaligned_inc (dbg, linep); + + Dwarf_Die cudie; + if (version < 5) + { + /* We need to find the matching CU to get the comp_dir. Use the + given CU as hint where to start searching. Normally it will + be the next CU that has a statement list. */ + Dwarf_CU *given_cu = *cu; + Dwarf_CU *next_cu = given_cu; + bool found = false; + while (dwarf_get_units (dbg, next_cu, &next_cu, NULL, NULL, + &cudie, NULL) == 0) + { + if (dwarf_hasattr (&cudie, DW_AT_stmt_list)) + { + Dwarf_Attribute attr; + Dwarf_Word stmt_off; + if (dwarf_formudata (dwarf_attr (&cudie, DW_AT_stmt_list, &attr), + &stmt_off) == 0 + && stmt_off == off) + { + found = true; + break; + } + } + else if (off == 0 + && (next_cu->unit_type == DW_UT_split_compile + || next_cu->unit_type == DW_UT_split_type)) + { + /* For split units (in .dwo files) there is only one table + at offset zero (containing just the files, no lines). */ + found = true; + break; + } + } + + if (!found && given_cu != NULL) + { + /* The CUs might be in a different order from the line + tables. Need to do a linear search (but stop at the given + CU, since we already searched those. */ + next_cu = NULL; + while (dwarf_get_units (dbg, next_cu, &next_cu, NULL, NULL, + &cudie, NULL) == 0 + && next_cu != given_cu) + { + Dwarf_Attribute attr; + Dwarf_Word stmt_off; + if (dwarf_formudata (dwarf_attr (&cudie, DW_AT_stmt_list, &attr), + &stmt_off) == 0 + && stmt_off == off) + { + found = true; + break; + } + } + } + + if (found) + *cu = next_cu; + else + *cu = NULL; + } + else + *cu = NULL; + + const char *comp_dir; + unsigned address_size; + if (*cu != NULL) + { + comp_dir = __libdw_getcompdir (&cudie); + address_size = (*cu)->address_size; + } + else + { + comp_dir = NULL; + + size_t esize; + char *ident = elf_getident (dbg->elf, &esize); + if (ident == NULL || esize < EI_NIDENT) + goto invalid_data; + address_size = ident[EI_CLASS] == ELFCLASS32 ? 4 : 8; + } + + if (__libdw_getsrclines (dbg, off, comp_dir, address_size, + srclines, srcfiles) != 0) + return -1; + + if (nlines != NULL) + { + if (srclines != NULL && *srclines != NULL) + *nlines = (*srclines)->nlines; + else + *nlines = 0; + } + + if (nfiles != NULL) + { + if (srcfiles != NULL && *srcfiles != NULL) + *nfiles = (*srcfiles)->nfiles; + else + *nfiles = 0; + } + + return 0; +} diff --git a/libdw/libdw.h b/libdw/libdw.h index a871eb29..b500aa86 100644 --- a/libdw/libdw.h +++ b/libdw/libdw.h @@ -716,6 +716,24 @@ extern int dwarf_getsrcdirs (Dwarf_Files *files, const char *const **result, size_t *ndirs) __nonnull_attribute__ (2, 3); +/* Iterates through the debug line units. Returns 0 on success, -1 on + error or 1 if there are no more units. To start iterating use zero + for OFF and set *CU to NULL. On success NEXT_OFF will be set to + the next offset to use. The *CU will be set if this line table + needed a specific CU and needs to be given when calling + dwarf_next_lines again (to help dwarf_next_lines quickly find the + next CU). *CU might be set to NULL when it couldn't be found (the + compilation directory entry will be the empty string in that case) + or for DWARF 5 or later tables, which are self contained. SRCFILES + and SRCLINES may be NULL if the caller is not interested in the + actual line or file table. On success and when not NULL, NFILES + and NLINES will be set to the number of files in the file table and + number of lines in the line table. */ +extern int dwarf_next_lines (Dwarf *dwarf, Dwarf_Off off, + Dwarf_Off *next_off, Dwarf_CU **cu, + Dwarf_Files **srcfiles, size_t *nfiles, + Dwarf_Lines **srclines, size_t *nlines) + __nonnull_attribute__ (3,4); /* Return location expression, decoded as a list of operations. */ extern int dwarf_getlocation (Dwarf_Attribute *attr, Dwarf_Op **expr, diff --git a/libdw/libdw.map b/libdw/libdw.map index 17c99f61..b3e84d5d 100644 --- a/libdw/libdw.map +++ b/libdw/libdw.map @@ -352,3 +352,8 @@ ELFUTILS_0.171 { dwarf_getabbrevattr_data; dwarf_cu_info; } ELFUTILS_0.170; + +ELFUTILS_0.173 { + global: + dwarf_next_lines; +} ELFUTILS_0.171; diff --git a/src/ChangeLog b/src/ChangeLog index 54bb9254..6d962bbb 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,9 @@ +2018-06-25 Mark Wielaard <[email protected]> + + * readelf.c (print_decoded_line_section): Use dwarf_next_lines + instead of dwarf_nextcu. + (print_debug_line_section): Don't explicitly lookup CU. + 2018-06-15 Mark Wielaard <[email protected]> * readelf.c (attr_callback): Only print block as expressions if it diff --git a/src/readelf.c b/src/readelf.c index 41720469..faed61a6 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -7824,23 +7824,51 @@ print_decoded_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, size_t address_size = elf_getident (ebl->elf, NULL)[EI_CLASS] == ELFCLASS32 ? 4 : 8; - Dwarf_Off cuoffset; - Dwarf_Off ncuoffset = 0; - size_t hsize; - while (dwarf_nextcu (dbg, cuoffset = ncuoffset, &ncuoffset, &hsize, - NULL, NULL, NULL) == 0) + Dwarf_Lines *lines; + size_t nlines; + Dwarf_Off off, next_off = 0; + Dwarf_CU *cu = NULL; + while (dwarf_next_lines (dbg, off = next_off, &next_off, &cu, NULL, NULL, + &lines, &nlines) == 0) { Dwarf_Die cudie; - if (dwarf_offdie (dbg, cuoffset + hsize, &cudie) == NULL) - continue; + if (cu != NULL && dwarf_cu_info (cu, NULL, NULL, &cudie, + NULL, NULL, NULL, NULL) == 0) + printf (" CU [%" PRIx64 "] %s\n", + dwarf_dieoffset (&cudie), dwarf_diename (&cudie)); + else + { + /* DWARF5 lines can be independent of any CU, but they probably + are used by some CU. Determine the CU this block is for. */ + Dwarf_Off cuoffset; + Dwarf_Off ncuoffset = 0; + size_t hsize; + while (dwarf_nextcu (dbg, cuoffset = ncuoffset, &ncuoffset, &hsize, + NULL, NULL, NULL) == 0) + { + if (dwarf_offdie (dbg, cuoffset + hsize, &cudie) == NULL) + continue; + Dwarf_Attribute stmt_list; + if (dwarf_attr (&cudie, DW_AT_stmt_list, &stmt_list) == NULL) + continue; + Dwarf_Word lineoff; + if (dwarf_formudata (&stmt_list, &lineoff) != 0) + continue; + if (lineoff == off) + { + /* Found the CU. */ + cu = cudie.cu; + break; + } + } - size_t nlines; - Dwarf_Lines *lines; - if (dwarf_getsrclines (&cudie, &lines, &nlines) != 0) - continue; + if (cu != NULL) + printf (" CU [%" PRIx64 "] %s\n", + dwarf_dieoffset (&cudie), dwarf_diename (&cudie)); + else + printf (" No CU\n"); + } - printf (" CU [%" PRIx64 "] %s\n", - dwarf_dieoffset (&cudie), dwarf_diename (&cudie)); printf (" line:col SBPE* disc isa op address" " (Statement Block Prologue Epilogue *End)\n"); const char *last_file = ""; @@ -8504,30 +8532,6 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, size_t line = 1; uint_fast8_t is_stmt = default_is_stmt; - /* Determine the CU this block is for. */ - Dwarf_Off cuoffset; - Dwarf_Off ncuoffset = 0; - size_t hsize; - while (dwarf_nextcu (dbg, cuoffset = ncuoffset, &ncuoffset, &hsize, - NULL, NULL, NULL) == 0) - { - Dwarf_Die cudie; - if (dwarf_offdie (dbg, cuoffset + hsize, &cudie) == NULL) - continue; - Dwarf_Attribute stmt_list; - if (dwarf_attr (&cudie, DW_AT_stmt_list, &stmt_list) == NULL) - continue; - Dwarf_Word lineoff; - if (dwarf_formudata (&stmt_list, &lineoff) != 0) - continue; - if (lineoff == start_offset) - { - /* Found the CU. */ - address_size = cudie.cu->address_size; - break; - } - } - /* Apply the "operation advance" from a special opcode or DW_LNS_advance_pc (as per DWARF4 6.2.5.1). */ unsigned int op_addr_advance; diff --git a/tests/ChangeLog b/tests/ChangeLog index c4942860..8eb63316 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,17 @@ +2018-06-25 Mark Wielaard <[email protected]> + + * next-files.c: New file. + * next-lines.c: Likewise. + * run-next-files.sh: New test. + * run-next-lines.sh: Likewise. + * testfile-only-debug-line.bz2: New test file. + * Makefile.am (check_PROGRAMS): Add next-files and next-lines. + (TESTS): Add run-next-files.sh and run-next-lines.sh. + (EXTRA_DIST): Add run-next-files.sh, run-next-lines.sh and + testfile-only-debug-line.bz2. + (next_lines_LDADD): New variable. + (next_files_LDADD): Likewise. + 2018-06-16 Yonghong Song <[email protected]> * run-reloc-bpf.sh: New test. diff --git a/tests/Makefile.am b/tests/Makefile.am index bdb82fc0..7b29fd83 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -38,7 +38,8 @@ endif check_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \ showptable update1 update2 update3 update4 test-nlist \ - show-die-info get-files get-lines get-pubnames \ + show-die-info get-files next-files get-lines next-lines \ + get-pubnames \ get-aranges allfcts line2addr addrscopes funcscopes \ show-abbrev hash newscn ecp dwflmodtest \ find-prologues funcretval allregs rdwrmmap \ @@ -77,6 +78,7 @@ backtrace-child-biarch$(EXEEXT): backtrace-child.c TESTS = run-arextract.sh run-arsymtest.sh run-ar.sh newfile test-nlist \ update1 update2 update3 update4 \ run-show-die-info.sh run-get-files.sh run-get-lines.sh \ + run-next-files.sh run-next-lines.sh \ run-get-pubnames.sh run-get-aranges.sh run-allfcts.sh \ run-show-abbrev.sh run-line2addr.sh hash \ newscn run-strip-test.sh run-strip-test2.sh \ @@ -173,6 +175,7 @@ endif EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \ run-show-die-info.sh run-get-files.sh run-get-lines.sh \ + run-next-files.sh run-next-lines.sh testfile-only-debug-line.bz2 \ run-get-pubnames.sh run-get-aranges.sh \ run-show-abbrev.sh run-strip-test.sh \ run-strip-test2.sh run-ecp-test.sh run-ecp-test2.sh \ @@ -470,7 +473,9 @@ show_die_info_LDADD = $(libdw) $(libelf) get_pubnames_LDADD = $(libdw) $(libelf) show_abbrev_LDADD = $(libdw) $(libelf) get_lines_LDADD = $(libdw) $(libelf) +next_lines_LDADD = $(libdw) $(libelf) get_files_LDADD = $(libdw) $(libelf) +next_files_LDADD = $(libdw) $(libelf) get_aranges_LDADD = $(libdw) $(libelf) allfcts_LDADD = $(libdw) $(libelf) line2addr_LDADD = $(libdw) $(argp_LDADD) diff --git a/tests/next-files.c b/tests/next-files.c new file mode 100644 index 00000000..9de5c8b0 --- /dev/null +++ b/tests/next-files.c @@ -0,0 +1,93 @@ +/* A variant of get-files test that uses dwarf_next_lines. + Copyright (C) 2002, 2004, 2005, 2007, 2014, 2018 Red Hat, Inc. + 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 <fcntl.h> +#include <inttypes.h> +#include <libelf.h> +#include ELFUTILS_HEADER(dw) +#include <stdio.h> +#include <unistd.h> + + +int +main (int argc, char *argv[]) +{ + int result = 0; + int cnt; + + for (cnt = 1; cnt < argc; ++cnt) + { + int fd = open (argv[cnt], O_RDONLY); + + Dwarf *dbg = dwarf_begin (fd, DWARF_C_READ); + if (dbg == NULL) + { + printf ("%s not usable\n", argv[cnt]); + result = 1; + if (fd != -1) + close (fd); + continue; + } + + Dwarf_Off off; + Dwarf_Off next_off = 0; + Dwarf_CU *cu = NULL; + Dwarf_Files *files; + size_t nfiles; + int res; + while ((res = dwarf_next_lines (dbg, off = next_off, &next_off, &cu, + &files, &nfiles, NULL, NULL)) == 0) + { + printf ("off = %" PRIu64 "\n", off); + + const char *const *dirs; + size_t ndirs; + if (dwarf_getsrcdirs (files, &dirs, &ndirs) != 0) + { + printf ("%s: cannot get include directories\n", argv[cnt]); + result = 1; + break; + } + + if (dirs[0] == NULL) + puts (" dirs[0] = (null)"); + else + printf (" dirs[0] = \"%s\"\n", dirs[0]); + for (size_t i = 1; i < ndirs; ++i) + printf (" dirs[%zu] = \"%s\"\n", i, dirs[i]); + + for (size_t i = 0; i < nfiles; ++i) + printf (" file[%zu] = \"%s\"\n", i, + dwarf_filesrc (files, i, NULL, NULL)); + } + + if (res < 0) + { + printf ("dwarf_next_lines failed: %s\n", dwarf_errmsg (-1)); + result = 1; + } + + dwarf_end (dbg); + close (fd); + } + + return result; +} diff --git a/tests/next-lines.c b/tests/next-lines.c new file mode 100644 index 00000000..cfb74cde --- /dev/null +++ b/tests/next-lines.c @@ -0,0 +1,144 @@ +/* A variant of get-lines that uses dwarf_next_lines. + Copyright (C) 2002, 2004, 2018 Red Hat, Inc. + 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 <fcntl.h> +#include <inttypes.h> +#include <libelf.h> +#include ELFUTILS_HEADER(dw) +#include <stdio.h> +#include <string.h> +#include <unistd.h> + + +int +main (int argc, char *argv[]) +{ + int result = 0; + int cnt; + + for (cnt = 1; cnt < argc; ++cnt) + { + int fd = open (argv[cnt], O_RDONLY); + + Dwarf *dbg = dwarf_begin (fd, DWARF_C_READ); + if (dbg == NULL) + { + printf ("%s not usable: %s\n", argv[cnt], dwarf_errmsg (-1)); + close (fd); + continue; + } + + Dwarf_Off off; + Dwarf_Off next_off = 0; + Dwarf_CU *cu = NULL; + Dwarf_Lines *lb; + size_t nlb; + int res; + while ((res = dwarf_next_lines (dbg, off = next_off, &next_off, &cu, + NULL, NULL, &lb, &nlb)) == 0) + { + printf ("off = %" PRIu64 "\n", off); + printf (" %zu lines\n", nlb); + + for (size_t i = 0; i < nlb; ++i) + { + Dwarf_Line *l = dwarf_onesrcline (lb, i); + if (l == NULL) + { + printf ("%s: cannot get individual line\n", argv[cnt]); + result = 1; + break; + } + + Dwarf_Addr addr; + if (dwarf_lineaddr (l, &addr) != 0) + addr = 0; + const char *file = dwarf_linesrc (l, NULL, NULL); + int line; + if (dwarf_lineno (l, &line) != 0) + line = 0; + + printf ("%" PRIx64 ": %s:%d:", (uint64_t) addr, + file ?: "???", line); + + /* Getting the file path through the Dwarf_Files should + result in the same path. */ + Dwarf_Files *files; + size_t idx; + if (dwarf_line_file (l, &files, &idx) != 0) + { + printf ("%s: cannot get file from line (%zd): %s\n", + argv[cnt], i, dwarf_errmsg (-1)); + result = 1; + break; + } + const char *path = dwarf_filesrc (files, idx, NULL, NULL); + if ((path == NULL && file != NULL) + || (path != NULL && file == NULL) + || (strcmp (file, path) != 0)) + { + printf ("%s: line %zd srcline (%s) != file srcline (%s)\n", + argv[cnt], i, file ?: "???", path ?: "???"); + result = 1; + break; + } + + int column; + if (dwarf_linecol (l, &column) != 0) + column = 0; + if (column >= 0) + printf ("%d:", column); + + bool is_stmt; + if (dwarf_linebeginstatement (l, &is_stmt) != 0) + is_stmt = false; + bool end_sequence; + if (dwarf_lineendsequence (l, &end_sequence) != 0) + end_sequence = false; + bool basic_block; + if (dwarf_lineblock (l, &basic_block) != 0) + basic_block = false; + bool prologue_end; + if (dwarf_lineprologueend (l, &prologue_end) != 0) + prologue_end = false; + bool epilogue_begin; + if (dwarf_lineepiloguebegin (l, &epilogue_begin) != 0) + epilogue_begin = false; + + printf (" is_stmt:%s, end_seq:%s, bb:%s, prologue:%s, epilogue:%s\n", + is_stmt ? "yes" : "no", end_sequence ? "yes" : "no", + basic_block ? "yes" : "no", prologue_end ? "yes" : "no", + epilogue_begin ? "yes" : "no"); + } + } + + if (res < 0) + { + printf ("dwarf_next_lines failed: %s\n", dwarf_errmsg (-1)); + result = 1; + } + + dwarf_end (dbg); + close (fd); + } + + return result; +} diff --git a/tests/run-next-files.sh b/tests/run-next-files.sh new file mode 100755 index 00000000..7a3b6d0f --- /dev/null +++ b/tests/run-next-files.sh @@ -0,0 +1,165 @@ +#! /bin/sh +# Variant of run-get-files that uses dwarf_next_lines. +# Copyright (C) 2018 Red Hat, Inc. +# 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/>. + +. $srcdir/test-subr.sh + +testfiles testfile testfile2 + +testrun_compare ${abs_builddir}/next-files testfile testfile2 <<\EOF +off = 0 + dirs[0] = "/home/drepper/gnu/new-bu/build/ttt" + file[0] = "???" + file[1] = "/home/drepper/gnu/new-bu/build/ttt/m.c" +off = 75 + dirs[0] = "/home/drepper/gnu/new-bu/build/ttt" + file[0] = "???" + file[1] = "/home/drepper/gnu/new-bu/build/ttt/b.c" + file[2] = "/usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h" + file[3] = "/usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h" + file[4] = "/usr/include/bits/types.h" + file[5] = "/usr/include/bits/sched.h" + file[6] = "/usr/include/bits/pthreadtypes.h" + file[7] = "/usr/include/stdio.h" + file[8] = "/usr/include/libio.h" + file[9] = "/usr/include/wchar.h" + file[10] = "/usr/include/_G_config.h" + file[11] = "/usr/include/gconv.h" +off = 480 + dirs[0] = "/home/drepper/gnu/new-bu/build/ttt" + file[0] = "???" + file[1] = "/home/drepper/gnu/new-bu/build/ttt/f.c" +off = 0 + dirs[0] = "/shoggoth/drepper" + file[0] = "???" + file[1] = "/shoggoth/drepper/b.c" + file[2] = "/home/geoffk/objs/laurel-000912-branch/lib/gcc-lib/powerpc-unknown-linux-gnu/2.96-laurel-000912/include/stddef.h" + file[3] = "/home/geoffk/objs/laurel-000912-branch/lib/gcc-lib/powerpc-unknown-linux-gnu/2.96-laurel-000912/include/stdarg.h" + file[4] = "/shoggoth/drepper/<built-in>" + file[5] = "/usr/include/bits/types.h" + file[6] = "/usr/include/stdio.h" + file[7] = "/usr/include/libio.h" + file[8] = "/usr/include/_G_config.h" +off = 418 + dirs[0] = "/shoggoth/drepper" + file[0] = "???" + file[1] = "/shoggoth/drepper/f.c" +off = 485 + dirs[0] = "/shoggoth/drepper" + file[0] = "???" + file[1] = "/shoggoth/drepper/m.c" +EOF + +# see tests/testfile-dwarf-45.source +testfiles testfile-splitdwarf-4 testfile-hello4.dwo testfile-world4.dwo +testfiles testfile-splitdwarf-5 testfile-hello5.dwo testfile-world5.dwo + +testrun_compare ${abs_builddir}/next-files testfile-splitdwarf-4 testfile-hello4.dwo testfile-world4.dwo <<\EOF +off = 0 + dirs[0] = "/home/mark/src/elfutils/tests" + dirs[1] = "/opt/local/install/gcc/lib/gcc/x86_64-pc-linux-gnu/9.0.0/include" + file[0] = "???" + file[1] = "/home/mark/src/elfutils/tests/hello.c" + file[2] = "/home/mark/src/elfutils/tests/hello.h" + file[3] = "/opt/local/install/gcc/lib/gcc/x86_64-pc-linux-gnu/9.0.0/include/stddef.h" +off = 612 + dirs[0] = "/home/mark/src/elfutils/tests" + dirs[1] = "/usr/include" + file[0] = "???" + file[1] = "/home/mark/src/elfutils/tests/world.c" + file[2] = "/home/mark/src/elfutils/tests/hello.h" + file[3] = "/usr/include/stdlib.h" +off = 0 + dirs[0] = "/home/mark/src/elfutils/tests" + dirs[1] = "/opt/local/install/gcc/lib/gcc/x86_64-pc-linux-gnu/9.0.0/include" + file[0] = "???" + file[1] = "/home/mark/src/elfutils/tests/hello.c" + file[2] = "/home/mark/src/elfutils/tests/hello.h" + file[3] = "/opt/local/install/gcc/lib/gcc/x86_64-pc-linux-gnu/9.0.0/include/stddef.h" +off = 0 + dirs[0] = "/home/mark/src/elfutils/tests" + dirs[1] = "/usr/include" + file[0] = "???" + file[1] = "/home/mark/src/elfutils/tests/world.c" + file[2] = "/home/mark/src/elfutils/tests/hello.h" + file[3] = "/usr/include/stdlib.h" +EOF + +# No problem with dirs[0] for DWARF5 line tables. +testrun_compare ${abs_builddir}/next-files testfile-splitdwarf-5 testfile-hello5.dwo testfile-world5.dwo <<\EOF +off = 0 + dirs[0] = "/home/mark/src/elfutils/tests" + dirs[1] = "/opt/local/install/gcc/lib/gcc/x86_64-pc-linux-gnu/9.0.0/include" + file[0] = "/home/mark/src/elfutils/tests/hello.c" + file[1] = "/home/mark/src/elfutils/tests/hello.c" + file[2] = "/home/mark/src/elfutils/tests/hello.h" + file[3] = "/opt/local/install/gcc/lib/gcc/x86_64-pc-linux-gnu/9.0.0/include/stddef.h" +off = 655 + dirs[0] = "/home/mark/src/elfutils/tests" + dirs[1] = "/usr/include" + file[0] = "/home/mark/src/elfutils/tests/world.c" + file[1] = "/home/mark/src/elfutils/tests/world.c" + file[2] = "/home/mark/src/elfutils/tests/hello.h" + file[3] = "/usr/include/stdlib.h" +off = 0 + dirs[0] = "/home/mark/src/elfutils/tests" + dirs[1] = "/opt/local/install/gcc/lib/gcc/x86_64-pc-linux-gnu/9.0.0/include" + file[0] = "/home/mark/src/elfutils/tests/hello.c" + file[1] = "/home/mark/src/elfutils/tests/hello.c" + file[2] = "/home/mark/src/elfutils/tests/hello.h" + file[3] = "/opt/local/install/gcc/lib/gcc/x86_64-pc-linux-gnu/9.0.0/include/stddef.h" +off = 0 + dirs[0] = "/home/mark/src/elfutils/tests" + dirs[1] = "/usr/include" + file[0] = "/home/mark/src/elfutils/tests/world.c" + file[1] = "/home/mark/src/elfutils/tests/world.c" + file[2] = "/home/mark/src/elfutils/tests/hello.h" + file[3] = "/usr/include/stdlib.h" +EOF + +# Created from testfile using +# cp testfile testfile-only-debug-line +# eu-strip -g --keep-section .debug_line +# +# Note how the comp dir cannot be retrieved and some files become relative. +testfiles testfile-only-debug-line +testrun_compare ${abs_builddir}/next-files testfile-only-debug-line <<\EOF +off = 0 + dirs[0] = (null) + file[0] = "???" + file[1] = "m.c" +off = 75 + dirs[0] = (null) + file[0] = "???" + file[1] = "b.c" + file[2] = "/usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stddef.h" + file[3] = "/usr/lib/gcc-lib/i386-redhat-linux/2.96/include/stdarg.h" + file[4] = "/usr/include/bits/types.h" + file[5] = "/usr/include/bits/sched.h" + file[6] = "/usr/include/bits/pthreadtypes.h" + file[7] = "/usr/include/stdio.h" + file[8] = "/usr/include/libio.h" + file[9] = "/usr/include/wchar.h" + file[10] = "/usr/include/_G_config.h" + file[11] = "/usr/include/gconv.h" +off = 480 + dirs[0] = (null) + file[0] = "???" + file[1] = "f.c" +EOF + +exit 0 diff --git a/tests/run-next-lines.sh b/tests/run-next-lines.sh new file mode 100755 index 00000000..84aee1c7 --- /dev/null +++ b/tests/run-next-lines.sh @@ -0,0 +1,116 @@ +#! /bin/sh +# Variant of run-get-lines that uses dwarf_next_lines. +# Copyright (C) 2018 Red Hat, Inc. +# 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/>. + +. $srcdir/test-subr.sh + +testfiles testfile testfile2 testfilenolines + +testrun_compare ${abs_builddir}/next-lines testfile testfile2 <<\EOF +off = 0 + 5 lines +804842c: /home/drepper/gnu/new-bu/build/ttt/m.c:5:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +8048432: /home/drepper/gnu/new-bu/build/ttt/m.c:6:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +804844d: /home/drepper/gnu/new-bu/build/ttt/m.c:7:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +8048458: /home/drepper/gnu/new-bu/build/ttt/m.c:8:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +804845a: /home/drepper/gnu/new-bu/build/ttt/m.c:8:0: is_stmt:yes, end_seq:yes, bb:no, prologue:no, epilogue:no +off = 75 + 4 lines +804845c: /home/drepper/gnu/new-bu/build/ttt/b.c:4:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +804845f: /home/drepper/gnu/new-bu/build/ttt/b.c:5:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +8048464: /home/drepper/gnu/new-bu/build/ttt/b.c:6:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +8048466: /home/drepper/gnu/new-bu/build/ttt/b.c:6:0: is_stmt:yes, end_seq:yes, bb:no, prologue:no, epilogue:no +off = 480 + 4 lines +8048468: /home/drepper/gnu/new-bu/build/ttt/f.c:3:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +804846b: /home/drepper/gnu/new-bu/build/ttt/f.c:4:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +8048470: /home/drepper/gnu/new-bu/build/ttt/f.c:5:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +8048472: /home/drepper/gnu/new-bu/build/ttt/f.c:5:0: is_stmt:yes, end_seq:yes, bb:no, prologue:no, epilogue:no +off = 0 + 4 lines +10000470: /shoggoth/drepper/b.c:4:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +1000047c: /shoggoth/drepper/b.c:5:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +10000480: /shoggoth/drepper/b.c:6:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +10000490: /shoggoth/drepper/b.c:6:0: is_stmt:yes, end_seq:yes, bb:no, prologue:no, epilogue:no +off = 418 + 4 lines +10000490: /shoggoth/drepper/f.c:3:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +1000049c: /shoggoth/drepper/f.c:4:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +100004a0: /shoggoth/drepper/f.c:5:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +100004b0: /shoggoth/drepper/f.c:5:0: is_stmt:yes, end_seq:yes, bb:no, prologue:no, epilogue:no +off = 485 + 5 lines +100004b0: /shoggoth/drepper/m.c:5:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +100004cc: /shoggoth/drepper/m.c:6:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +100004e8: /shoggoth/drepper/m.c:7:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +100004f4: /shoggoth/drepper/m.c:8:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +10000514: /shoggoth/drepper/m.c:8:0: is_stmt:yes, end_seq:yes, bb:no, prologue:no, epilogue:no +EOF + +# - lines.c +# int ft; +# +# int +# main (int argc, char **argv) +# { +# return ft - 42; +# } +# +# - nolines.c +# int ft = 42; +# +# gcc -g -c lines.c +# gcc -g -c nolines.c +# gcc -g -o testfilenolines lines.o nolines.o + +testrun_compare ${abs_builddir}/next-lines testfilenolines <<\EOF +off = 0 + 4 lines +400474: /home/mark/src/tests/lines.c:5:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +40047f: /home/mark/src/tests/lines.c:6:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +400488: /home/mark/src/tests/lines.c:7:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +40048a: /home/mark/src/tests/lines.c:7:0: is_stmt:yes, end_seq:yes, bb:no, prologue:no, epilogue:no +off = 59 + 0 lines +EOF + +# See run-next-files. +# Note no, comp_dir, so all paths are relative. +testfiles testfile-only-debug-line +testrun_compare ${abs_builddir}/next-lines testfile-only-debug-line <<\EOF +off = 0 + 5 lines +804842c: m.c:5:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +8048432: m.c:6:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +804844d: m.c:7:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +8048458: m.c:8:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +804845a: m.c:8:0: is_stmt:yes, end_seq:yes, bb:no, prologue:no, epilogue:no +off = 75 + 4 lines +804845c: b.c:4:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +804845f: b.c:5:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +8048464: b.c:6:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +8048466: b.c:6:0: is_stmt:yes, end_seq:yes, bb:no, prologue:no, epilogue:no +off = 480 + 4 lines +8048468: f.c:3:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +804846b: f.c:4:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +8048470: f.c:5:0: is_stmt:yes, end_seq:no, bb:no, prologue:no, epilogue:no +8048472: f.c:5:0: is_stmt:yes, end_seq:yes, bb:no, prologue:no, epilogue:no +EOF + +exit 0 diff --git a/tests/testfile-only-debug-line.bz2 b/tests/testfile-only-debug-line.bz2 Binary files differnew file mode 100644 index 00000000..a931bcd4 --- /dev/null +++ b/tests/testfile-only-debug-line.bz2 |
