diff mbox series

[backtrace] Avoid segfault

Message ID 2839e296-39b7-d1e1-5bd7-62fdba33b156@acm.org
State New
Headers show
Series [backtrace] Avoid segfault | expand

Commit Message

Nathan Sidwell Jan. 25, 2019, 12:11 a.m. UTC
I just tripped over a segfault in libbacktrace.  We apply strrchr to a 
possibly NULL filename, with predictable results when it is.

elf.c:3044 passes NULL as the filename parm:
	  ret = elf_add (state, NULL, d, base_address, error_callback, data,
			 fileline_fn, found_sym, found_dwarf, NULL, 0, 1, NULL,
			 0);

This gets to elf_open_debugfile_by_debuglink which passes it on through:
   ddescriptor = elf_find_debugfile_by_debuglink (state, filename,
						 debuglink_name,
						 error_callback, data);

this patch avoids the strrchr when filename is null.  I reordered the 
way prefix & prefix len got set, finding it prefereable to:
   slash  = filename ? NULL : strrchr (filename, '/');
but if you prefer to avoid the assignment in the conditional I'm fine 
with that too.

ok?

nathan

Comments

Ian Lance Taylor Jan. 25, 2019, 12:51 a.m. UTC | #1
On Thu, Jan 24, 2019 at 4:11 PM Nathan Sidwell <nathan@acm.org> wrote:
>
> I just tripped over a segfault in libbacktrace.  We apply strrchr to a
> possibly NULL filename, with predictable results when it is.
>
> elf.c:3044 passes NULL as the filename parm:
>           ret = elf_add (state, NULL, d, base_address, error_callback, data,
>                          fileline_fn, found_sym, found_dwarf, NULL, 0, 1, NULL,
>                          0);
>
> This gets to elf_open_debugfile_by_debuglink which passes it on through:
>    ddescriptor = elf_find_debugfile_by_debuglink (state, filename,
>                                                  debuglink_name,
>                                                  error_callback, data);
>
> this patch avoids the strrchr when filename is null.  I reordered the
> way prefix & prefix len got set, finding it prefereable to:
>    slash  = filename ? NULL : strrchr (filename, '/');
> but if you prefer to avoid the assignment in the conditional I'm fine
> with that too.

Yeah, please don't do an assignment in a conditional.

Why don't we just pass "" instead of NULL in the call to elf_add?  If
that works, that is OK.

Thanks.

Ian
Tom de Vries Jan. 25, 2019, 1:17 p.m. UTC | #2
On 25-01-19 01:51, Ian Lance Taylor wrote:
> On Thu, Jan 24, 2019 at 4:11 PM Nathan Sidwell <nathan@acm.org> wrote:
>>
>> I just tripped over a segfault in libbacktrace.  We apply strrchr to a
>> possibly NULL filename, with predictable results when it is.
>>
>> elf.c:3044 passes NULL as the filename parm:
>>           ret = elf_add (state, NULL, d, base_address, error_callback, data,
>>                          fileline_fn, found_sym, found_dwarf, NULL, 0, 1, NULL,
>>                          0);
>>
>> This gets to elf_open_debugfile_by_debuglink which passes it on through:
>>    ddescriptor = elf_find_debugfile_by_debuglink (state, filename,
>>                                                  debuglink_name,
>>                                                  error_callback, data);
>>
>> this patch avoids the strrchr when filename is null.  I reordered the
>> way prefix & prefix len got set, finding it prefereable to:
>>    slash  = filename ? NULL : strrchr (filename, '/');
>> but if you prefer to avoid the assignment in the conditional I'm fine
>> with that too.
> 
> Yeah, please don't do an assignment in a conditional.
> 
> Why don't we just pass "" instead of NULL in the call to elf_add?  If
> that works, that is OK.
> 

With this refactoring preamble ...
[libbacktrace] Rename dtest to btest_gnudebuglink

Create a pattern rule for copying an existing test-case, separating out the
debug information into a .debug file, and referencing the .debug file from
the copied test-case using a .gnu_debuglink.

2019-01-25  Tom de Vries  <tdevries@suse.de>

	* Makefile.am: Rewrite dtest rule into "%_gnudebuglink" pattern rule.
	(TESTS): Rename dtest to btest_gnudebuglink.
	* Makefile.in: Regenerate.

---
 libbacktrace/Makefile.am |  8 ++++----
 libbacktrace/Makefile.in | 14 +++++++-------
 2 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/libbacktrace/Makefile.am b/libbacktrace/Makefile.am
index bf90ebdb2d5..2f1d9af89c3 100644
--- a/libbacktrace/Makefile.am
+++ b/libbacktrace/Makefile.am
@@ -255,11 +255,11 @@ endif HAVE_PTHREAD
 
 if HAVE_OBJCOPY_DEBUGLINK
 
-TESTS += dtest
+TESTS += btest_gnudebuglink
 
-dtest: btest
-	$(OBJCOPY) --only-keep-debug btest btest.debug
-	$(OBJCOPY) --strip-debug --add-gnu-debuglink=btest.debug btest dtest
+%_gnudebuglink: %
+	$(OBJCOPY) --only-keep-debug $< $@.debug
+	$(OBJCOPY) --strip-debug --add-gnu-debuglink=$@.debug $< $@
 
 endif HAVE_OBJCOPY_DEBUGLINK
 
diff --git a/libbacktrace/Makefile.in b/libbacktrace/Makefile.in
index d55e0501171..0b73e3d6981 100644
--- a/libbacktrace/Makefile.in
+++ b/libbacktrace/Makefile.in
@@ -130,7 +130,7 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3)
 @HAVE_ZLIB_TRUE@@NATIVE_TRUE@am__append_4 = -lz
 @HAVE_ZLIB_TRUE@@NATIVE_TRUE@am__append_5 = -lz
 @HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__append_6 = ttest ttest_alloc
-@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am__append_7 = dtest
+@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am__append_7 = btest_gnudebuglink
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__append_8 = ctestg ctesta \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctestg_alloc \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctesta_alloc
@@ -1585,9 +1585,9 @@ btest_dwz.log: btest_dwz
 	--log-file $$b.log --trs-file $$b.trs \
 	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
 	"$$tst" $(AM_TESTS_FD_REDIRECT)
-dtest.log: dtest
-	@p='dtest'; \
-	b='dtest'; \
+btest_gnudebuglink.log: btest_gnudebuglink
+	@p='btest_gnudebuglink'; \
+	b='btest_gnudebuglink'; \
 	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
 	--log-file $$b.log --trs-file $$b.trs \
 	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
@@ -1767,9 +1767,9 @@ uninstall-am:
 @NATIVE_TRUE@	$(SHELL) $(srcdir)/../move-if-change tmp-edtest2_build.c edtest2_build.c
 @NATIVE_TRUE@	echo timestamp > $@
 
-@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@dtest: btest
-@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@	$(OBJCOPY) --only-keep-debug btest btest.debug
-@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@	$(OBJCOPY) --strip-debug --add-gnu-debuglink=btest.debug btest dtest
+@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@%_gnudebuglink: %
+@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@	$(OBJCOPY) --only-keep-debug $< $@.debug
+@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@	$(OBJCOPY) --strip-debug --add-gnu-debuglink=$@.debug $< $@
 alloc.lo: config.h backtrace.h internal.h
 backtrace.lo: config.h backtrace.h internal.h
 btest.lo: (INCDIR)/filenames.h backtrace.h backtrace-supported.h
Tom de Vries Jan. 25, 2019, 1:28 p.m. UTC | #3
On 25-01-19 14:17, Tom de Vries wrote:
> On 25-01-19 01:51, Ian Lance Taylor wrote:
>> On Thu, Jan 24, 2019 at 4:11 PM Nathan Sidwell <nathan@acm.org> wrote:
>>>
>>> I just tripped over a segfault in libbacktrace.  We apply strrchr to a
>>> possibly NULL filename, with predictable results when it is.
>>>
>>> elf.c:3044 passes NULL as the filename parm:
>>>           ret = elf_add (state, NULL, d, base_address, error_callback, data,
>>>                          fileline_fn, found_sym, found_dwarf, NULL, 0, 1, NULL,
>>>                          0);
>>>
>>> This gets to elf_open_debugfile_by_debuglink which passes it on through:
>>>    ddescriptor = elf_find_debugfile_by_debuglink (state, filename,
>>>                                                  debuglink_name,
>>>                                                  error_callback, data);
>>>
>>> this patch avoids the strrchr when filename is null.  I reordered the
>>> way prefix & prefix len got set, finding it prefereable to:
>>>    slash  = filename ? NULL : strrchr (filename, '/');
>>> but if you prefer to avoid the assignment in the conditional I'm fine
>>> with that too.
>>
>> Yeah, please don't do an assignment in a conditional.
>>
>> Why don't we just pass "" instead of NULL in the call to elf_add?  If
>> that works, that is OK.
>>
> 
> With this refactoring preamble ...

... I can more easily add a test-case btest_dwz_gnudebuglink, which
triggers a segfault due to strrchr being called with a NULL string.

This patch fixes it by passing "" instead of NULL, in the call to
elf_add at line 3083 (for .gnu_debugaltlink), not the call to elf_add at
line 3044 (for .gnu_debuglink) mentioned above.

Nathan, does this fix the problem for you? If not, can you provide a
reproducer, or give a hint on how one could be constructed?

Thanks,
- Tom
[libbacktrace] Fix strrchr segfault

Currently, when handling a libbacktrace testcase t with .gnu_debuglink to
t.debug, and t.debug having a .gnu_debugaltlink to t.alt.debug, an segfault
is triggered in when calling strrchr with a NULL string from
elf_find_debugfile_by_debuglink.  The NULL string originates from the elf_add
called for the .gnu_debugaltlink, which uses NULL as filename argument.

Fix this by using "" as filename argument instead.

2019-01-25  Tom de Vries  <tdevries@suse.de>

	* elf.c (elf_add): When handling .gnu_debugaltlink, Call elf_add with
	filename == "".
	* Makefile.am (TESTS): Add btest_dwz_gnudebuglink.
	* Makefile.in: Regenerate.

---
 libbacktrace/Makefile.am |  6 ++++++
 libbacktrace/Makefile.in | 22 +++++++++++++++-------
 libbacktrace/elf.c       |  2 +-
 3 files changed, 22 insertions(+), 8 deletions(-)

diff --git a/libbacktrace/Makefile.am b/libbacktrace/Makefile.am
index 2f1d9af89c3..997a535dff4 100644
--- a/libbacktrace/Makefile.am
+++ b/libbacktrace/Makefile.am
@@ -190,6 +190,12 @@ if HAVE_DWZ
 
 TESTS += btest_dwz
 
+if HAVE_OBJCOPY_DEBUGLINK
+
+TESTS += btest_dwz_gnudebuglink
+
+endif HAVE_OBJCOPY_DEBUGLINK
+
 endif HAVE_DWZ
 
 stest_SOURCES = stest.c
diff --git a/libbacktrace/Makefile.in b/libbacktrace/Makefile.in
index 0b73e3d6981..f04577066f8 100644
--- a/libbacktrace/Makefile.in
+++ b/libbacktrace/Makefile.in
@@ -127,11 +127,12 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3)
 @NATIVE_TRUE@	ztest ztest_alloc edtest edtest_alloc
 @NATIVE_TRUE@am__append_2 = allocfail.sh
 @HAVE_DWZ_TRUE@@NATIVE_TRUE@am__append_3 = btest_dwz
-@HAVE_ZLIB_TRUE@@NATIVE_TRUE@am__append_4 = -lz
+@HAVE_DWZ_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am__append_4 = btest_dwz_gnudebuglink
 @HAVE_ZLIB_TRUE@@NATIVE_TRUE@am__append_5 = -lz
-@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__append_6 = ttest ttest_alloc
-@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am__append_7 = btest_gnudebuglink
-@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__append_8 = ctestg ctesta \
+@HAVE_ZLIB_TRUE@@NATIVE_TRUE@am__append_6 = -lz
+@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__append_7 = ttest ttest_alloc
+@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am__append_8 = btest_gnudebuglink
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__append_9 = ctestg ctesta \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctestg_alloc \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctesta_alloc
 subdir = .
@@ -789,7 +790,7 @@ libbacktrace_la_LIBADD = \
 
 libbacktrace_la_DEPENDENCIES = $(libbacktrace_la_LIBADD)
 TESTS = $(check_PROGRAMS) $(am__append_2) $(am__append_3) \
-	$(am__append_7)
+	$(am__append_4) $(am__append_8)
 @NATIVE_TRUE@check_LTLIBRARIES = libbacktrace_alloc.la \
 @NATIVE_TRUE@	libbacktrace_noformat.la \
 @NATIVE_TRUE@	libbacktrace_instrumented_alloc.la
@@ -834,9 +835,9 @@ TESTS = $(check_PROGRAMS) $(am__append_2) $(am__append_3) \
 @NATIVE_TRUE@stest_alloc_LDADD = libbacktrace_alloc.la
 @NATIVE_TRUE@ztest_SOURCES = ztest.c testlib.c
 @NATIVE_TRUE@ztest_CFLAGS = -DSRCDIR=\"$(srcdir)\"
-@NATIVE_TRUE@ztest_LDADD = libbacktrace.la $(am__append_4) \
+@NATIVE_TRUE@ztest_LDADD = libbacktrace.la $(am__append_5) \
 @NATIVE_TRUE@	$(CLOCK_GETTIME_LINK)
-@NATIVE_TRUE@ztest_alloc_LDADD = libbacktrace_alloc.la $(am__append_5) \
+@NATIVE_TRUE@ztest_alloc_LDADD = libbacktrace_alloc.la $(am__append_6) \
 @NATIVE_TRUE@	$(CLOCK_GETTIME_LINK)
 @NATIVE_TRUE@ztest_alloc_SOURCES = $(ztest_SOURCES)
 @NATIVE_TRUE@ztest_alloc_CFLAGS = $(ztest_CFLAGS)
@@ -1585,6 +1586,13 @@ btest_dwz.log: btest_dwz
 	--log-file $$b.log --trs-file $$b.trs \
 	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
 	"$$tst" $(AM_TESTS_FD_REDIRECT)
+btest_dwz_gnudebuglink.log: btest_dwz_gnudebuglink
+	@p='btest_dwz_gnudebuglink'; \
+	b='btest_dwz_gnudebuglink'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
 btest_gnudebuglink.log: btest_gnudebuglink
 	@p='btest_gnudebuglink'; \
 	b='btest_gnudebuglink'; \
diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c
index 01cf6f9cff7..632477f3099 100644
--- a/libbacktrace/elf.c
+++ b/libbacktrace/elf.c
@@ -3080,7 +3080,7 @@ elf_add (struct backtrace_state *state, const char *filename, int descriptor,
 	  if (debugaltlink_view_valid)
 	    backtrace_release_view (state, &debugaltlink_view, error_callback,
 				    data);
-	  ret = elf_add (state, NULL, d, base_address, error_callback, data,
+	  ret = elf_add (state, "", d, base_address, error_callback, data,
 			 fileline_fn, found_sym, found_dwarf, NULL, 0, 1, NULL,
 			 0);
 	  if (ret < 0)
Ian Lance Taylor Jan. 25, 2019, 2:21 p.m. UTC | #4
On Fri, Jan 25, 2019 at 5:17 AM Tom de Vries <tdevries@suse.de> wrote:
>
> On 25-01-19 01:51, Ian Lance Taylor wrote:
> > On Thu, Jan 24, 2019 at 4:11 PM Nathan Sidwell <nathan@acm.org> wrote:
> >>
> >> I just tripped over a segfault in libbacktrace.  We apply strrchr to a
> >> possibly NULL filename, with predictable results when it is.
> >>
> >> elf.c:3044 passes NULL as the filename parm:
> >>           ret = elf_add (state, NULL, d, base_address, error_callback, data,
> >>                          fileline_fn, found_sym, found_dwarf, NULL, 0, 1, NULL,
> >>                          0);
> >>
> >> This gets to elf_open_debugfile_by_debuglink which passes it on through:
> >>    ddescriptor = elf_find_debugfile_by_debuglink (state, filename,
> >>                                                  debuglink_name,
> >>                                                  error_callback, data);
> >>
> >> this patch avoids the strrchr when filename is null.  I reordered the
> >> way prefix & prefix len got set, finding it prefereable to:
> >>    slash  = filename ? NULL : strrchr (filename, '/');
> >> but if you prefer to avoid the assignment in the conditional I'm fine
> >> with that too.
> >
> > Yeah, please don't do an assignment in a conditional.
> >
> > Why don't we just pass "" instead of NULL in the call to elf_add?  If
> > that works, that is OK.
> >
>
> With this refactoring preamble ...

This is OK.

Thanks.

Ian
Ian Lance Taylor Jan. 25, 2019, 2:23 p.m. UTC | #5
On Fri, Jan 25, 2019 at 5:27 AM Tom de Vries <tdevries@suse.de> wrote:
>
> On 25-01-19 14:17, Tom de Vries wrote:
> > On 25-01-19 01:51, Ian Lance Taylor wrote:
> >> On Thu, Jan 24, 2019 at 4:11 PM Nathan Sidwell <nathan@acm.org> wrote:
> >>>
> >>> I just tripped over a segfault in libbacktrace.  We apply strrchr to a
> >>> possibly NULL filename, with predictable results when it is.
> >>>
> >>> elf.c:3044 passes NULL as the filename parm:
> >>>           ret = elf_add (state, NULL, d, base_address, error_callback, data,
> >>>                          fileline_fn, found_sym, found_dwarf, NULL, 0, 1, NULL,
> >>>                          0);
> >>>
> >>> This gets to elf_open_debugfile_by_debuglink which passes it on through:
> >>>    ddescriptor = elf_find_debugfile_by_debuglink (state, filename,
> >>>                                                  debuglink_name,
> >>>                                                  error_callback, data);
> >>>
> >>> this patch avoids the strrchr when filename is null.  I reordered the
> >>> way prefix & prefix len got set, finding it prefereable to:
> >>>    slash  = filename ? NULL : strrchr (filename, '/');
> >>> but if you prefer to avoid the assignment in the conditional I'm fine
> >>> with that too.
> >>
> >> Yeah, please don't do an assignment in a conditional.
> >>
> >> Why don't we just pass "" instead of NULL in the call to elf_add?  If
> >> that works, that is OK.
> >>
> >
> > With this refactoring preamble ...
>
> ... I can more easily add a test-case btest_dwz_gnudebuglink, which
> triggers a segfault due to strrchr being called with a NULL string.
>
> This patch fixes it by passing "" instead of NULL, in the call to
> elf_add at line 3083 (for .gnu_debugaltlink), not the call to elf_add at
> line 3044 (for .gnu_debuglink) mentioned above.
>
> Nathan, does this fix the problem for you? If not, can you provide a
> reproducer, or give a hint on how one could be constructed?

This is OK.

s/Call/call/ in the ChangeLog entry.

Thanks.

Ian
Nathan Sidwell Jan. 25, 2019, 5:15 p.m. UTC | #6
On 1/25/19 5:28 AM, Tom de Vries wrote:
>
> This patch fixes it by passing "" instead of NULL, in the call to
> elf_add at line 3083 (for .gnu_debugaltlink), not the call to elf_add at
> line 3044 (for .gnu_debuglink) mentioned above.
> 
> Nathan, does this fix the problem for you? If not, can you provide a
> reproducer, or give a hint on how one could be constructed?

I still hit the problem, and am installing this as sufficiently obvious. 
  I'm on a fedora system debugging pr88995.  The debuglink_name is 
"../../.dwz/isl-0.16.1-7.fc29.x86_64"

I'm not sure why this is triggering now -- maybe my debuginfo packages 
are out of date?

nathan
Marek Polacek Jan. 25, 2019, 5:20 p.m. UTC | #7
On Fri, Jan 25, 2019 at 12:15:28PM -0500, Nathan Sidwell wrote:
> On 1/25/19 5:28 AM, Tom de Vries wrote:
> > 
> > This patch fixes it by passing "" instead of NULL, in the call to
> > elf_add at line 3083 (for .gnu_debugaltlink), not the call to elf_add at
> > line 3044 (for .gnu_debuglink) mentioned above.
> > 
> > Nathan, does this fix the problem for you? If not, can you provide a
> > reproducer, or give a hint on how one could be constructed?
> 
> I still hit the problem, and am installing this as sufficiently obvious.
> I'm on a fedora system debugging pr88995.  The debuglink_name is
> "../../.dwz/isl-0.16.1-7.fc29.x86_64"
> 
> I'm not sure why this is triggering now -- maybe my debuginfo packages are
> out of date?

I'm seeing this too.  I've resolved it by uninstalling libmpc-debuginfo.  If I
put it back, the crash in libbacktrace reappears.  Again the problem was
a null filename and so strchr crashed.  Thanks for looking into this Nathan.

Marek
Tom de Vries Jan. 27, 2019, 9:16 p.m. UTC | #8
On 25-01-19 18:15, Nathan Sidwell wrote:
> On 1/25/19 5:28 AM, Tom de Vries wrote:
>>
>> This patch fixes it by passing "" instead of NULL, in the call to
>> elf_add at line 3083 (for .gnu_debugaltlink), not the call to elf_add at
>> line 3044 (for .gnu_debuglink) mentioned above.
>>
>> Nathan, does this fix the problem for you? If not, can you provide a
>> reproducer, or give a hint on how one could be constructed?
> 
> I still hit the problem, and am installing this as sufficiently obvious.
>  I'm on a fedora system debugging pr88995.  The debuglink_name is
> "../../.dwz/isl-0.16.1-7.fc29.x86_64"
> 

I've managed to reproduce this segfault instance by adding a test-case
that uses both build-id and dwz.

OK for trunk?

Thanks,
- Tom
[libbacktrace] Add test-cases exercising build-id and dwz

Add test-cases b2test_buildid and b3test_dwz_buildid.

The last one triggers the segfault fixed by "[backtrace] Avoid segfault"
( r268275 ).

2019-01-27  Tom de Vries  <tdevries@suse.de>

	* Makefile.am (check_PROGRAMS): Add b2test and b3test.
	(TESTS): Add b2test_buildid, b3test_dwz and b3test_dwz_buildid.
	* Makefile.in: Regenerate.
	* configure.ac (HAVE_ELF): Set with AM_CONDITIONAL.
	* configure: Regenerate.
	* elf.c (SYSTEM_BUILD_ID_DIR): Factor out of ...
	(elf_open_debugfile_by_buildid): ... here.

---
 libbacktrace/Makefile.am  |  53 +++++++++++
 libbacktrace/Makefile.in  | 223 ++++++++++++++++++++++++++++++++++++++--------
 libbacktrace/configure    |  18 +++-
 libbacktrace/configure.ac |   1 +
 libbacktrace/elf.c        |   4 +-
 5 files changed, 257 insertions(+), 42 deletions(-)

diff --git a/libbacktrace/Makefile.am b/libbacktrace/Makefile.am
index 997a535dff4..becba1ae1f0 100644
--- a/libbacktrace/Makefile.am
+++ b/libbacktrace/Makefile.am
@@ -103,6 +103,25 @@ libbacktrace_noformat_la_LIBADD = $(BACKTRACE_FILE) $(VIEW_FILE) $(ALLOC_FILE)
 
 libbacktrace_noformat_la_DEPENDENCIES = $(libbacktrace_noformat_la_LIBADD)
 
+if HAVE_ELF
+
+check_LTLIBRARIES += libbacktrace_elf_for_test.la
+
+libbacktrace_elf_for_test_la_SOURCES = $(libbacktrace_la_SOURCES)
+libbacktrace_elf_for_test_la_LIBADD = $(BACKTRACE_FILE) elf_for_test.lo \
+	$(VIEW_FILE) $(ALLOC_FILE)
+
+elf_for_test.c: elf.c
+	PWD=$$(pwd -P); \
+	BUILD_ID_DIR="usr/lib/debug/.build-id/"; \
+	SEARCH='#define SYSTEM_BUILD_ID_DIR'; \
+	REPLACE="#define SYSTEM_BUILD_ID_DIR \"$$PWD/$$BUILD_ID_DIR\""; \
+	$(SED) "s%^$$SEARCH.*\$$%$$REPLACE%" \
+		$< \
+		> $@
+
+endif HAVE_ELF
+
 xcoff_%.c: xcoff.c
 	SEARCH='#error "Unknown BACKTRACE_XCOFF_SIZE"'; \
 	REPLACE='#undef BACKTRACE_XCOFF_SIZE\
@@ -166,6 +185,30 @@ allocfail.sh: allocfail
 
 TESTS += allocfail.sh
 
+if HAVE_ELF
+
+b2test_SOURCES = $(btest_SOURCES)
+b2test_CFLAGS = $(btest_CFLAGS)
+b2test_LDADD = libbacktrace_elf_for_test.la
+
+# The file b2test_buildid is an objcopy of b2test, so these programs share the
+# same build-id.  The first time b2test is run, there's no corresponding debug
+# file at ./usr/lib/debug/.build-id/aa/bb..zz.debug.  The second time b2test is
+# run, the .debug file has been created for b2test_buildid, which is now picked
+# up by b2test as well.
+check_PROGRAMS += b2test
+TESTS += b2test_buildid
+
+b3test_SOURCES = $(btest_SOURCES)
+b3test_CFLAGS = $(btest_CFLAGS)
+b3test_LDADD = libbacktrace_elf_for_test.la
+
+# These programs share the same build-id.  See b2test for more details.
+check_PROGRAMS += b3test
+TESTS += b3test_dwz b3test_dwz_buildid
+
+endif HAVE_ELF
+
 btest_SOURCES = btest.c testlib.c
 btest_CFLAGS = $(AM_CFLAGS) -g -O
 btest_LDADD = libbacktrace.la
@@ -269,6 +312,16 @@ TESTS += btest_gnudebuglink
 
 endif HAVE_OBJCOPY_DEBUGLINK
 
+%_buildid: %
+	buildid=$$(readelf -n $< | grep "Build ID" | $(AWK) '{print $$3}'); \
+	  prefix=$$(echo $$buildid | $(SED) 's/.//3g'); \
+	  remainder=$$(echo $$buildid | $(SED) 's/^.\{2\}//'); \
+	  pwd=$$(pwd -P); \
+	  dir=$$pwd/usr/lib/debug/.build-id; \
+	  mkdir -p $$dir/$$prefix; \
+	  $(OBJCOPY) --only-keep-debug $< $$dir/$$prefix/$$remainder.debug
+	$(OBJCOPY) --strip-debug $< $@
+
 if HAVE_COMPRESSED_DEBUG
 
 ctestg_SOURCES = btest.c testlib.c
diff --git a/libbacktrace/Makefile.in b/libbacktrace/Makefile.in
index f04577066f8..1d84b67d0d5 100644
--- a/libbacktrace/Makefile.in
+++ b/libbacktrace/Makefile.in
@@ -120,19 +120,33 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 target_triplet = @target@
-check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3)
-@NATIVE_TRUE@am__append_1 = test_elf test_xcoff_32 test_xcoff_64 \
+check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
+	$(am__EXEEXT_4) $(am__EXEEXT_5)
+@HAVE_ELF_TRUE@@NATIVE_TRUE@am__append_1 = libbacktrace_elf_for_test.la
+@NATIVE_TRUE@am__append_2 = test_elf test_xcoff_32 test_xcoff_64 \
 @NATIVE_TRUE@	test_pecoff test_unknown unittest unittest_alloc \
-@NATIVE_TRUE@	allocfail btest btest_alloc stest stest_alloc \
-@NATIVE_TRUE@	ztest ztest_alloc edtest edtest_alloc
-@NATIVE_TRUE@am__append_2 = allocfail.sh
-@HAVE_DWZ_TRUE@@NATIVE_TRUE@am__append_3 = btest_dwz
-@HAVE_DWZ_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am__append_4 = btest_dwz_gnudebuglink
-@HAVE_ZLIB_TRUE@@NATIVE_TRUE@am__append_5 = -lz
-@HAVE_ZLIB_TRUE@@NATIVE_TRUE@am__append_6 = -lz
-@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__append_7 = ttest ttest_alloc
-@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am__append_8 = btest_gnudebuglink
-@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__append_9 = ctestg ctesta \
+@NATIVE_TRUE@	allocfail
+@NATIVE_TRUE@am__append_3 = allocfail.sh
+
+# The file b2test_buildid is an objcopy of b2test, so these programs share the
+# same build-id.  The first time b2test is run, there's no corresponding debug
+# file at ./usr/lib/debug/.build-id/aa/bb..zz.debug.  The second time b2test is
+# run, the .debug file has been created for b2test_buildid, which is now picked
+# up by b2test as well.
+
+# These programs share the same build-id.  See b2test for more details.
+@HAVE_ELF_TRUE@@NATIVE_TRUE@am__append_4 = b2test b3test
+@HAVE_ELF_TRUE@@NATIVE_TRUE@am__append_5 = b2test_buildid b3test_dwz \
+@HAVE_ELF_TRUE@@NATIVE_TRUE@	b3test_dwz_buildid
+@NATIVE_TRUE@am__append_6 = btest btest_alloc stest stest_alloc ztest \
+@NATIVE_TRUE@	ztest_alloc edtest edtest_alloc
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@am__append_7 = btest_dwz
+@HAVE_DWZ_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am__append_8 = btest_dwz_gnudebuglink
+@HAVE_ZLIB_TRUE@@NATIVE_TRUE@am__append_9 = -lz
+@HAVE_ZLIB_TRUE@@NATIVE_TRUE@am__append_10 = -lz
+@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__append_11 = ttest ttest_alloc
+@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am__append_12 = btest_gnudebuglink
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__append_13 = ctestg ctesta \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctestg_alloc \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctesta_alloc
 subdir = .
@@ -172,6 +186,16 @@ am__objects_1 = atomic.lo dwarf.lo fileline.lo posix.lo print.lo \
 @NATIVE_TRUE@am_libbacktrace_alloc_la_OBJECTS = $(am__objects_1)
 libbacktrace_alloc_la_OBJECTS = $(am_libbacktrace_alloc_la_OBJECTS)
 @NATIVE_TRUE@am_libbacktrace_alloc_la_rpath =
+@HAVE_ELF_TRUE@@NATIVE_TRUE@libbacktrace_elf_for_test_la_DEPENDENCIES =  \
+@HAVE_ELF_TRUE@@NATIVE_TRUE@	$(am__DEPENDENCIES_1) \
+@HAVE_ELF_TRUE@@NATIVE_TRUE@	elf_for_test.lo \
+@HAVE_ELF_TRUE@@NATIVE_TRUE@	$(am__DEPENDENCIES_1) \
+@HAVE_ELF_TRUE@@NATIVE_TRUE@	$(am__DEPENDENCIES_1)
+@HAVE_ELF_TRUE@@NATIVE_TRUE@am_libbacktrace_elf_for_test_la_OBJECTS =  \
+@HAVE_ELF_TRUE@@NATIVE_TRUE@	$(am__objects_1)
+libbacktrace_elf_for_test_la_OBJECTS =  \
+	$(am_libbacktrace_elf_for_test_la_OBJECTS)
+@HAVE_ELF_TRUE@@NATIVE_TRUE@am_libbacktrace_elf_for_test_la_rpath =
 @NATIVE_TRUE@am_libbacktrace_instrumented_alloc_la_OBJECTS =  \
 @NATIVE_TRUE@	$(am__objects_1)
 libbacktrace_instrumented_alloc_la_OBJECTS =  \
@@ -184,14 +208,16 @@ libbacktrace_noformat_la_OBJECTS =  \
 @NATIVE_TRUE@am__EXEEXT_1 = test_elf$(EXEEXT) test_xcoff_32$(EXEEXT) \
 @NATIVE_TRUE@	test_xcoff_64$(EXEEXT) test_pecoff$(EXEEXT) \
 @NATIVE_TRUE@	test_unknown$(EXEEXT) unittest$(EXEEXT) \
-@NATIVE_TRUE@	unittest_alloc$(EXEEXT) allocfail$(EXEEXT) \
-@NATIVE_TRUE@	btest$(EXEEXT) btest_alloc$(EXEEXT) \
+@NATIVE_TRUE@	unittest_alloc$(EXEEXT) allocfail$(EXEEXT)
+@HAVE_ELF_TRUE@@NATIVE_TRUE@am__EXEEXT_2 = b2test$(EXEEXT) \
+@HAVE_ELF_TRUE@@NATIVE_TRUE@	b3test$(EXEEXT)
+@NATIVE_TRUE@am__EXEEXT_3 = btest$(EXEEXT) btest_alloc$(EXEEXT) \
 @NATIVE_TRUE@	stest$(EXEEXT) stest_alloc$(EXEEXT) \
 @NATIVE_TRUE@	ztest$(EXEEXT) ztest_alloc$(EXEEXT) \
 @NATIVE_TRUE@	edtest$(EXEEXT) edtest_alloc$(EXEEXT)
-@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__EXEEXT_2 = ttest$(EXEEXT) \
+@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__EXEEXT_4 = ttest$(EXEEXT) \
 @HAVE_PTHREAD_TRUE@@NATIVE_TRUE@	ttest_alloc$(EXEEXT)
-@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__EXEEXT_3 =  \
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__EXEEXT_5 =  \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctestg$(EXEEXT) \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctesta$(EXEEXT) \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctestg_alloc$(EXEEXT) \
@@ -201,6 +227,24 @@ libbacktrace_noformat_la_OBJECTS =  \
 allocfail_OBJECTS = $(am_allocfail_OBJECTS)
 @NATIVE_TRUE@allocfail_DEPENDENCIES =  \
 @NATIVE_TRUE@	libbacktrace_instrumented_alloc.la
+@NATIVE_TRUE@am__objects_2 = b2test-btest.$(OBJEXT) \
+@NATIVE_TRUE@	b2test-testlib.$(OBJEXT)
+@HAVE_ELF_TRUE@@NATIVE_TRUE@am_b2test_OBJECTS = $(am__objects_2)
+b2test_OBJECTS = $(am_b2test_OBJECTS)
+@HAVE_ELF_TRUE@@NATIVE_TRUE@b2test_DEPENDENCIES =  \
+@HAVE_ELF_TRUE@@NATIVE_TRUE@	libbacktrace_elf_for_test.la
+b2test_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(b2test_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+@NATIVE_TRUE@am__objects_3 = b3test-btest.$(OBJEXT) \
+@NATIVE_TRUE@	b3test-testlib.$(OBJEXT)
+@HAVE_ELF_TRUE@@NATIVE_TRUE@am_b3test_OBJECTS = $(am__objects_3)
+b3test_OBJECTS = $(am_b3test_OBJECTS)
+@HAVE_ELF_TRUE@@NATIVE_TRUE@b3test_DEPENDENCIES =  \
+@HAVE_ELF_TRUE@@NATIVE_TRUE@	libbacktrace_elf_for_test.la
+b3test_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(b3test_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
 @NATIVE_TRUE@am_btest_OBJECTS = btest-btest.$(OBJEXT) \
 @NATIVE_TRUE@	btest-testlib.$(OBJEXT)
 btest_OBJECTS = $(am_btest_OBJECTS)
@@ -208,9 +252,9 @@ btest_OBJECTS = $(am_btest_OBJECTS)
 btest_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
 	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(btest_CFLAGS) $(CFLAGS) \
 	$(AM_LDFLAGS) $(LDFLAGS) -o $@
-@NATIVE_TRUE@am__objects_2 = btest_alloc-btest.$(OBJEXT) \
+@NATIVE_TRUE@am__objects_4 = btest_alloc-btest.$(OBJEXT) \
 @NATIVE_TRUE@	btest_alloc-testlib.$(OBJEXT)
-@NATIVE_TRUE@am_btest_alloc_OBJECTS = $(am__objects_2)
+@NATIVE_TRUE@am_btest_alloc_OBJECTS = $(am__objects_4)
 btest_alloc_OBJECTS = $(am_btest_alloc_OBJECTS)
 @NATIVE_TRUE@btest_alloc_DEPENDENCIES = libbacktrace_alloc.la
 btest_alloc_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
@@ -224,10 +268,10 @@ ctesta_OBJECTS = $(am_ctesta_OBJECTS)
 ctesta_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
 	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(ctesta_CFLAGS) $(CFLAGS) \
 	$(ctesta_LDFLAGS) $(LDFLAGS) -o $@
-@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__objects_3 = ctesta_alloc-btest.$(OBJEXT) \
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__objects_5 = ctesta_alloc-btest.$(OBJEXT) \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctesta_alloc-testlib.$(OBJEXT)
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am_ctesta_alloc_OBJECTS =  \
-@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	$(am__objects_3)
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	$(am__objects_5)
 ctesta_alloc_OBJECTS = $(am_ctesta_alloc_OBJECTS)
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ctesta_alloc_DEPENDENCIES = libbacktrace_alloc.la
 ctesta_alloc_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
@@ -241,10 +285,10 @@ ctestg_OBJECTS = $(am_ctestg_OBJECTS)
 ctestg_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
 	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(ctestg_CFLAGS) $(CFLAGS) \
 	$(ctestg_LDFLAGS) $(LDFLAGS) -o $@
-@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__objects_4 = ctestg_alloc-btest.$(OBJEXT) \
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__objects_6 = ctestg_alloc-btest.$(OBJEXT) \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctestg_alloc-testlib.$(OBJEXT)
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am_ctestg_alloc_OBJECTS =  \
-@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	$(am__objects_4)
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	$(am__objects_6)
 ctestg_alloc_OBJECTS = $(am_ctestg_alloc_OBJECTS)
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ctestg_alloc_DEPENDENCIES = libbacktrace_alloc.la
 ctestg_alloc_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
@@ -254,16 +298,16 @@ ctestg_alloc_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
 @NATIVE_TRUE@	edtest2_build.$(OBJEXT) testlib.$(OBJEXT)
 edtest_OBJECTS = $(am_edtest_OBJECTS)
 @NATIVE_TRUE@edtest_DEPENDENCIES = libbacktrace.la
-@NATIVE_TRUE@am__objects_5 = edtest.$(OBJEXT) edtest2_build.$(OBJEXT) \
+@NATIVE_TRUE@am__objects_7 = edtest.$(OBJEXT) edtest2_build.$(OBJEXT) \
 @NATIVE_TRUE@	testlib.$(OBJEXT)
-@NATIVE_TRUE@am_edtest_alloc_OBJECTS = $(am__objects_5)
+@NATIVE_TRUE@am_edtest_alloc_OBJECTS = $(am__objects_7)
 edtest_alloc_OBJECTS = $(am_edtest_alloc_OBJECTS)
 @NATIVE_TRUE@edtest_alloc_DEPENDENCIES = libbacktrace_alloc.la
 @NATIVE_TRUE@am_stest_OBJECTS = stest.$(OBJEXT)
 stest_OBJECTS = $(am_stest_OBJECTS)
 @NATIVE_TRUE@stest_DEPENDENCIES = libbacktrace.la
-@NATIVE_TRUE@am__objects_6 = stest.$(OBJEXT)
-@NATIVE_TRUE@am_stest_alloc_OBJECTS = $(am__objects_6)
+@NATIVE_TRUE@am__objects_8 = stest.$(OBJEXT)
+@NATIVE_TRUE@am_stest_alloc_OBJECTS = $(am__objects_8)
 stest_alloc_OBJECTS = $(am_stest_alloc_OBJECTS)
 @NATIVE_TRUE@stest_alloc_DEPENDENCIES = libbacktrace_alloc.la
 @NATIVE_TRUE@am_test_elf_OBJECTS = test_format.$(OBJEXT) \
@@ -298,11 +342,11 @@ ttest_OBJECTS = $(am_ttest_OBJECTS)
 ttest_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
 	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(ttest_CFLAGS) $(CFLAGS) \
 	$(AM_LDFLAGS) $(LDFLAGS) -o $@
-@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__objects_7 =  \
+@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__objects_9 =  \
 @HAVE_PTHREAD_TRUE@@NATIVE_TRUE@	ttest_alloc-ttest.$(OBJEXT) \
 @HAVE_PTHREAD_TRUE@@NATIVE_TRUE@	ttest_alloc-testlib.$(OBJEXT)
 @HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am_ttest_alloc_OBJECTS =  \
-@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@	$(am__objects_7)
+@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@	$(am__objects_9)
 ttest_alloc_OBJECTS = $(am_ttest_alloc_OBJECTS)
 @HAVE_PTHREAD_TRUE@@NATIVE_TRUE@ttest_alloc_DEPENDENCIES =  \
 @HAVE_PTHREAD_TRUE@@NATIVE_TRUE@	libbacktrace_alloc.la
@@ -313,8 +357,8 @@ ttest_alloc_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
 @NATIVE_TRUE@	testlib.$(OBJEXT)
 unittest_OBJECTS = $(am_unittest_OBJECTS)
 @NATIVE_TRUE@unittest_DEPENDENCIES = libbacktrace.la
-@NATIVE_TRUE@am__objects_8 = unittest.$(OBJEXT) testlib.$(OBJEXT)
-@NATIVE_TRUE@am_unittest_alloc_OBJECTS = $(am__objects_8)
+@NATIVE_TRUE@am__objects_10 = unittest.$(OBJEXT) testlib.$(OBJEXT)
+@NATIVE_TRUE@am_unittest_alloc_OBJECTS = $(am__objects_10)
 unittest_alloc_OBJECTS = $(am_unittest_alloc_OBJECTS)
 @NATIVE_TRUE@unittest_alloc_DEPENDENCIES = libbacktrace_alloc.la
 @NATIVE_TRUE@am_ztest_OBJECTS = ztest-ztest.$(OBJEXT) \
@@ -325,9 +369,9 @@ ztest_OBJECTS = $(am_ztest_OBJECTS)
 ztest_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
 	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(ztest_CFLAGS) $(CFLAGS) \
 	$(AM_LDFLAGS) $(LDFLAGS) -o $@
-@NATIVE_TRUE@am__objects_9 = ztest_alloc-ztest.$(OBJEXT) \
+@NATIVE_TRUE@am__objects_11 = ztest_alloc-ztest.$(OBJEXT) \
 @NATIVE_TRUE@	ztest_alloc-testlib.$(OBJEXT)
-@NATIVE_TRUE@am_ztest_alloc_OBJECTS = $(am__objects_9)
+@NATIVE_TRUE@am_ztest_alloc_OBJECTS = $(am__objects_11)
 ztest_alloc_OBJECTS = $(am_ztest_alloc_OBJECTS)
 @NATIVE_TRUE@ztest_alloc_DEPENDENCIES = libbacktrace_alloc.la \
 @NATIVE_TRUE@	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
@@ -369,9 +413,11 @@ am__v_CCLD_0 = @echo "  CCLD    " $@;
 am__v_CCLD_1 = 
 SOURCES = $(libbacktrace_la_SOURCES) $(EXTRA_libbacktrace_la_SOURCES) \
 	$(libbacktrace_alloc_la_SOURCES) \
+	$(libbacktrace_elf_for_test_la_SOURCES) \
 	$(libbacktrace_instrumented_alloc_la_SOURCES) \
 	$(libbacktrace_noformat_la_SOURCES) $(allocfail_SOURCES) \
-	$(btest_SOURCES) $(btest_alloc_SOURCES) $(ctesta_SOURCES) \
+	$(b2test_SOURCES) $(b3test_SOURCES) $(btest_SOURCES) \
+	$(btest_alloc_SOURCES) $(ctesta_SOURCES) \
 	$(ctesta_alloc_SOURCES) $(ctestg_SOURCES) \
 	$(ctestg_alloc_SOURCES) $(edtest_SOURCES) \
 	$(edtest_alloc_SOURCES) $(stest_SOURCES) \
@@ -789,10 +835,10 @@ libbacktrace_la_LIBADD = \
 	$(ALLOC_FILE)
 
 libbacktrace_la_DEPENDENCIES = $(libbacktrace_la_LIBADD)
-TESTS = $(check_PROGRAMS) $(am__append_2) $(am__append_3) \
-	$(am__append_4) $(am__append_8)
+TESTS = $(check_PROGRAMS) $(am__append_3) $(am__append_5) \
+	$(am__append_7) $(am__append_8) $(am__append_12)
 @NATIVE_TRUE@check_LTLIBRARIES = libbacktrace_alloc.la \
-@NATIVE_TRUE@	libbacktrace_noformat.la \
+@NATIVE_TRUE@	libbacktrace_noformat.la $(am__append_1) \
 @NATIVE_TRUE@	libbacktrace_instrumented_alloc.la
 @NATIVE_TRUE@libbacktrace_alloc_la_SOURCES = $(libbacktrace_la_SOURCES)
 @NATIVE_TRUE@libbacktrace_alloc_la_LIBADD = $(BACKTRACE_FILE) $(FORMAT_FILE) read.lo alloc.lo
@@ -800,6 +846,10 @@ TESTS = $(check_PROGRAMS) $(am__append_2) $(am__append_3) \
 @NATIVE_TRUE@libbacktrace_noformat_la_SOURCES = $(libbacktrace_la_SOURCES)
 @NATIVE_TRUE@libbacktrace_noformat_la_LIBADD = $(BACKTRACE_FILE) $(VIEW_FILE) $(ALLOC_FILE)
 @NATIVE_TRUE@libbacktrace_noformat_la_DEPENDENCIES = $(libbacktrace_noformat_la_LIBADD)
+@HAVE_ELF_TRUE@@NATIVE_TRUE@libbacktrace_elf_for_test_la_SOURCES = $(libbacktrace_la_SOURCES)
+@HAVE_ELF_TRUE@@NATIVE_TRUE@libbacktrace_elf_for_test_la_LIBADD = $(BACKTRACE_FILE) elf_for_test.lo \
+@HAVE_ELF_TRUE@@NATIVE_TRUE@	$(VIEW_FILE) $(ALLOC_FILE)
+
 @NATIVE_TRUE@test_elf_SOURCES = test_format.c testlib.c
 @NATIVE_TRUE@test_elf_LDADD = libbacktrace_noformat.la elf.lo
 @NATIVE_TRUE@test_xcoff_32_SOURCES = test_format.c testlib.c
@@ -823,6 +873,12 @@ TESTS = $(check_PROGRAMS) $(am__append_2) $(am__append_3) \
 
 @NATIVE_TRUE@allocfail_SOURCES = allocfail.c testlib.c
 @NATIVE_TRUE@allocfail_LDADD = libbacktrace_instrumented_alloc.la
+@HAVE_ELF_TRUE@@NATIVE_TRUE@b2test_SOURCES = $(btest_SOURCES)
+@HAVE_ELF_TRUE@@NATIVE_TRUE@b2test_CFLAGS = $(btest_CFLAGS)
+@HAVE_ELF_TRUE@@NATIVE_TRUE@b2test_LDADD = libbacktrace_elf_for_test.la
+@HAVE_ELF_TRUE@@NATIVE_TRUE@b3test_SOURCES = $(btest_SOURCES)
+@HAVE_ELF_TRUE@@NATIVE_TRUE@b3test_CFLAGS = $(btest_CFLAGS)
+@HAVE_ELF_TRUE@@NATIVE_TRUE@b3test_LDADD = libbacktrace_elf_for_test.la
 @NATIVE_TRUE@btest_SOURCES = btest.c testlib.c
 @NATIVE_TRUE@btest_CFLAGS = $(AM_CFLAGS) -g -O
 @NATIVE_TRUE@btest_LDADD = libbacktrace.la
@@ -835,10 +891,10 @@ TESTS = $(check_PROGRAMS) $(am__append_2) $(am__append_3) \
 @NATIVE_TRUE@stest_alloc_LDADD = libbacktrace_alloc.la
 @NATIVE_TRUE@ztest_SOURCES = ztest.c testlib.c
 @NATIVE_TRUE@ztest_CFLAGS = -DSRCDIR=\"$(srcdir)\"
-@NATIVE_TRUE@ztest_LDADD = libbacktrace.la $(am__append_5) \
-@NATIVE_TRUE@	$(CLOCK_GETTIME_LINK)
-@NATIVE_TRUE@ztest_alloc_LDADD = libbacktrace_alloc.la $(am__append_6) \
+@NATIVE_TRUE@ztest_LDADD = libbacktrace.la $(am__append_9) \
 @NATIVE_TRUE@	$(CLOCK_GETTIME_LINK)
+@NATIVE_TRUE@ztest_alloc_LDADD = libbacktrace_alloc.la \
+@NATIVE_TRUE@	$(am__append_10) $(CLOCK_GETTIME_LINK)
 @NATIVE_TRUE@ztest_alloc_SOURCES = $(ztest_SOURCES)
 @NATIVE_TRUE@ztest_alloc_CFLAGS = $(ztest_CFLAGS)
 @NATIVE_TRUE@edtest_SOURCES = edtest.c edtest2_build.c testlib.c
@@ -971,6 +1027,9 @@ libbacktrace.la: $(libbacktrace_la_OBJECTS) $(libbacktrace_la_DEPENDENCIES) $(EX
 libbacktrace_alloc.la: $(libbacktrace_alloc_la_OBJECTS) $(libbacktrace_alloc_la_DEPENDENCIES) $(EXTRA_libbacktrace_alloc_la_DEPENDENCIES) 
 	$(AM_V_CCLD)$(LINK) $(am_libbacktrace_alloc_la_rpath) $(libbacktrace_alloc_la_OBJECTS) $(libbacktrace_alloc_la_LIBADD) $(LIBS)
 
+libbacktrace_elf_for_test.la: $(libbacktrace_elf_for_test_la_OBJECTS) $(libbacktrace_elf_for_test_la_DEPENDENCIES) $(EXTRA_libbacktrace_elf_for_test_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(LINK) $(am_libbacktrace_elf_for_test_la_rpath) $(libbacktrace_elf_for_test_la_OBJECTS) $(libbacktrace_elf_for_test_la_LIBADD) $(LIBS)
+
 libbacktrace_instrumented_alloc.la: $(libbacktrace_instrumented_alloc_la_OBJECTS) $(libbacktrace_instrumented_alloc_la_DEPENDENCIES) $(EXTRA_libbacktrace_instrumented_alloc_la_DEPENDENCIES) 
 	$(AM_V_CCLD)$(LINK) $(am_libbacktrace_instrumented_alloc_la_rpath) $(libbacktrace_instrumented_alloc_la_OBJECTS) $(libbacktrace_instrumented_alloc_la_LIBADD) $(LIBS)
 
@@ -990,6 +1049,14 @@ allocfail$(EXEEXT): $(allocfail_OBJECTS) $(allocfail_DEPENDENCIES) $(EXTRA_alloc
 	@rm -f allocfail$(EXEEXT)
 	$(AM_V_CCLD)$(LINK) $(allocfail_OBJECTS) $(allocfail_LDADD) $(LIBS)
 
+b2test$(EXEEXT): $(b2test_OBJECTS) $(b2test_DEPENDENCIES) $(EXTRA_b2test_DEPENDENCIES) 
+	@rm -f b2test$(EXEEXT)
+	$(AM_V_CCLD)$(b2test_LINK) $(b2test_OBJECTS) $(b2test_LDADD) $(LIBS)
+
+b3test$(EXEEXT): $(b3test_OBJECTS) $(b3test_DEPENDENCIES) $(EXTRA_b3test_DEPENDENCIES) 
+	@rm -f b3test$(EXEEXT)
+	$(AM_V_CCLD)$(b3test_LINK) $(b3test_OBJECTS) $(b3test_LDADD) $(LIBS)
+
 btest$(EXEEXT): $(btest_OBJECTS) $(btest_DEPENDENCIES) $(EXTRA_btest_DEPENDENCIES) 
 	@rm -f btest$(EXEEXT)
 	$(AM_V_CCLD)$(btest_LINK) $(btest_OBJECTS) $(btest_LDADD) $(LIBS)
@@ -1089,6 +1156,30 @@ distclean-compile:
 .c.lo:
 	$(AM_V_CC)$(LTCOMPILE) -c -o $@ $<
 
+b2test-btest.o: btest.c
+	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(b2test_CFLAGS) $(CFLAGS) -c -o b2test-btest.o `test -f 'btest.c' || echo '$(srcdir)/'`btest.c
+
+b2test-btest.obj: btest.c
+	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(b2test_CFLAGS) $(CFLAGS) -c -o b2test-btest.obj `if test -f 'btest.c'; then $(CYGPATH_W) 'btest.c'; else $(CYGPATH_W) '$(srcdir)/btest.c'; fi`
+
+b2test-testlib.o: testlib.c
+	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(b2test_CFLAGS) $(CFLAGS) -c -o b2test-testlib.o `test -f 'testlib.c' || echo '$(srcdir)/'`testlib.c
+
+b2test-testlib.obj: testlib.c
+	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(b2test_CFLAGS) $(CFLAGS) -c -o b2test-testlib.obj `if test -f 'testlib.c'; then $(CYGPATH_W) 'testlib.c'; else $(CYGPATH_W) '$(srcdir)/testlib.c'; fi`
+
+b3test-btest.o: btest.c
+	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(b3test_CFLAGS) $(CFLAGS) -c -o b3test-btest.o `test -f 'btest.c' || echo '$(srcdir)/'`btest.c
+
+b3test-btest.obj: btest.c
+	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(b3test_CFLAGS) $(CFLAGS) -c -o b3test-btest.obj `if test -f 'btest.c'; then $(CYGPATH_W) 'btest.c'; else $(CYGPATH_W) '$(srcdir)/btest.c'; fi`
+
+b3test-testlib.o: testlib.c
+	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(b3test_CFLAGS) $(CFLAGS) -c -o b3test-testlib.o `test -f 'testlib.c' || echo '$(srcdir)/'`testlib.c
+
+b3test-testlib.obj: testlib.c
+	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(b3test_CFLAGS) $(CFLAGS) -c -o b3test-testlib.obj `if test -f 'testlib.c'; then $(CYGPATH_W) 'testlib.c'; else $(CYGPATH_W) '$(srcdir)/testlib.c'; fi`
+
 btest-btest.o: btest.c
 	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(btest_CFLAGS) $(CFLAGS) -c -o btest-btest.o `test -f 'btest.c' || echo '$(srcdir)/'`btest.c
 
@@ -1474,6 +1565,20 @@ allocfail.log: allocfail$(EXEEXT)
 	--log-file $$b.log --trs-file $$b.trs \
 	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
 	"$$tst" $(AM_TESTS_FD_REDIRECT)
+b2test.log: b2test$(EXEEXT)
+	@p='b2test$(EXEEXT)'; \
+	b='b2test'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+b3test.log: b3test$(EXEEXT)
+	@p='b3test$(EXEEXT)'; \
+	b='b3test'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
 btest.log: btest$(EXEEXT)
 	@p='btest$(EXEEXT)'; \
 	b='btest'; \
@@ -1579,6 +1684,27 @@ allocfail.sh.log: allocfail.sh
 	--log-file $$b.log --trs-file $$b.trs \
 	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
 	"$$tst" $(AM_TESTS_FD_REDIRECT)
+b2test_buildid.log: b2test_buildid
+	@p='b2test_buildid'; \
+	b='b2test_buildid'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+b3test_dwz.log: b3test_dwz
+	@p='b3test_dwz'; \
+	b='b3test_dwz'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+b3test_dwz_buildid.log: b3test_dwz_buildid
+	@p='b3test_dwz_buildid'; \
+	b='b3test_dwz_buildid'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
 btest_dwz.log: btest_dwz
 	@p='btest_dwz'; \
 	b='btest_dwz'; \
@@ -1749,6 +1875,15 @@ uninstall-am:
 .PRECIOUS: Makefile
 
 
+@HAVE_ELF_TRUE@@NATIVE_TRUE@elf_for_test.c: elf.c
+@HAVE_ELF_TRUE@@NATIVE_TRUE@	PWD=$$(pwd -P); \
+@HAVE_ELF_TRUE@@NATIVE_TRUE@	BUILD_ID_DIR="usr/lib/debug/.build-id/"; \
+@HAVE_ELF_TRUE@@NATIVE_TRUE@	SEARCH='#define SYSTEM_BUILD_ID_DIR'; \
+@HAVE_ELF_TRUE@@NATIVE_TRUE@	REPLACE="#define SYSTEM_BUILD_ID_DIR \"$$PWD/$$BUILD_ID_DIR\""; \
+@HAVE_ELF_TRUE@@NATIVE_TRUE@	$(SED) "s%^$$SEARCH.*\$$%$$REPLACE%" \
+@HAVE_ELF_TRUE@@NATIVE_TRUE@		$< \
+@HAVE_ELF_TRUE@@NATIVE_TRUE@		> $@
+
 @NATIVE_TRUE@xcoff_%.c: xcoff.c
 @NATIVE_TRUE@	SEARCH='#error "Unknown BACKTRACE_XCOFF_SIZE"'; \
 @NATIVE_TRUE@	REPLACE='#undef BACKTRACE_XCOFF_SIZE\
@@ -1778,6 +1913,16 @@ uninstall-am:
 @HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@%_gnudebuglink: %
 @HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@	$(OBJCOPY) --only-keep-debug $< $@.debug
 @HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@	$(OBJCOPY) --strip-debug --add-gnu-debuglink=$@.debug $< $@
+
+@NATIVE_TRUE@%_buildid: %
+@NATIVE_TRUE@	buildid=$$(readelf -n $< | grep "Build ID" | $(AWK) '{print $$3}'); \
+@NATIVE_TRUE@	  prefix=$$(echo $$buildid | $(SED) 's/.//3g'); \
+@NATIVE_TRUE@	  remainder=$$(echo $$buildid | $(SED) 's/^.\{2\}//'); \
+@NATIVE_TRUE@	  pwd=$$(pwd -P); \
+@NATIVE_TRUE@	  dir=$$pwd/usr/lib/debug/.build-id; \
+@NATIVE_TRUE@	  mkdir -p $$dir/$$prefix; \
+@NATIVE_TRUE@	  $(OBJCOPY) --only-keep-debug $< $$dir/$$prefix/$$remainder.debug
+@NATIVE_TRUE@	$(OBJCOPY) --strip-debug $< $@
 alloc.lo: config.h backtrace.h internal.h
 backtrace.lo: config.h backtrace.h internal.h
 btest.lo: (INCDIR)/filenames.h backtrace.h backtrace-supported.h
diff --git a/libbacktrace/configure b/libbacktrace/configure
index 2ea112bde68..7a902ce1eaa 100755
--- a/libbacktrace/configure
+++ b/libbacktrace/configure
@@ -651,6 +651,8 @@ ALLOC_FILE
 VIEW_FILE
 BACKTRACE_SUPPORTS_DATA
 BACKTRACE_SUPPORTED
+HAVE_ELF_FALSE
+HAVE_ELF_TRUE
 FORMAT_FILE
 BACKTRACE_SUPPORTS_THREADS
 PIC_FLAG
@@ -11489,7 +11491,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11492 "configure"
+#line 11494 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11595,7 +11597,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11598 "configure"
+#line 11600 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -12512,6 +12514,14 @@ cat >>confdefs.h <<_ACEOF
 #define BACKTRACE_ELF_SIZE $elfsize
 _ACEOF
 
+ if test "$FORMAT_FILE" = "elf.lo"; then
+  HAVE_ELF_TRUE=
+  HAVE_ELF_FALSE='#'
+else
+  HAVE_ELF_TRUE='#'
+  HAVE_ELF_FALSE=
+fi
+
 
 # XCOFF defines.
 xcoffsize=
@@ -13611,6 +13621,10 @@ if test -z "${HAVE_DWZ_TRUE}" && test -z "${HAVE_DWZ_FALSE}"; then
   as_fn_error $? "conditional \"HAVE_DWZ\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
+if test -z "${HAVE_ELF_TRUE}" && test -z "${HAVE_ELF_FALSE}"; then
+  as_fn_error $? "conditional \"HAVE_ELF\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
 if test -z "${HAVE_PTHREAD_TRUE}" && test -z "${HAVE_PTHREAD_FALSE}"; then
   as_fn_error $? "conditional \"HAVE_PTHREAD\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
diff --git a/libbacktrace/configure.ac b/libbacktrace/configure.ac
index c64bf3473bb..8c911e25ba3 100644
--- a/libbacktrace/configure.ac
+++ b/libbacktrace/configure.ac
@@ -259,6 +259,7 @@ elf64) elfsize=64 ;;
 *)     elfsize=unused
 esac
 AC_DEFINE_UNQUOTED([BACKTRACE_ELF_SIZE], [$elfsize], [ELF size: 32 or 64])
+AM_CONDITIONAL(HAVE_ELF, test "$FORMAT_FILE" = "elf.lo")
 
 # XCOFF defines.
 xcoffsize=
diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c
index 6fee865bece..d933052200c 100644
--- a/libbacktrace/elf.c
+++ b/libbacktrace/elf.c
@@ -809,6 +809,8 @@ elf_readlink (struct backtrace_state *state, const char *filename,
     }
 }
 
+#define SYSTEM_BUILD_ID_DIR "/usr/lib/debug/.build-id/"
+
 /* Open a separate debug info file, using the build ID to find it.
    Returns an open file descriptor, or -1.
 
@@ -821,7 +823,7 @@ elf_open_debugfile_by_buildid (struct backtrace_state *state,
 			       backtrace_error_callback error_callback,
 			       void *data)
 {
-  const char * const prefix = "/usr/lib/debug/.build-id/";
+  const char * const prefix = SYSTEM_BUILD_ID_DIR;
   const size_t prefix_len = strlen (prefix);
   const char * const suffix = ".debug";
   const size_t suffix_len = strlen (suffix);
Ian Lance Taylor Jan. 27, 2019, 9:53 p.m. UTC | #9
On Sun, Jan 27, 2019 at 1:16 PM Tom de Vries <tdevries@suse.de> wrote:
>
> On 25-01-19 18:15, Nathan Sidwell wrote:
> > On 1/25/19 5:28 AM, Tom de Vries wrote:
> >>
> >> This patch fixes it by passing "" instead of NULL, in the call to
> >> elf_add at line 3083 (for .gnu_debugaltlink), not the call to elf_add at
> >> line 3044 (for .gnu_debuglink) mentioned above.
> >>
> >> Nathan, does this fix the problem for you? If not, can you provide a
> >> reproducer, or give a hint on how one could be constructed?
> >
> > I still hit the problem, and am installing this as sufficiently obvious.
> >  I'm on a fedora system debugging pr88995.  The debuglink_name is
> > "../../.dwz/isl-0.16.1-7.fc29.x86_64"
> >
>
> I've managed to reproduce this segfault instance by adding a test-case
> that uses both build-id and dwz.
>
> OK for trunk?

> +elf_for_test.c: elf.c
> + PWD=$$(pwd -P); \
> + BUILD_ID_DIR="usr/lib/debug/.build-id/"; \
> + SEARCH='#define SYSTEM_BUILD_ID_DIR'; \
> + REPLACE="#define SYSTEM_BUILD_ID_DIR \"$$PWD/$$BUILD_ID_DIR\""; \
> + $(SED) "s%^$$SEARCH.*\$$%$$REPLACE%" \
> + $< \
> + > $@

You need to use a temporary file, such as $@.tmp, for the final sed
command, followed by a mv to $@.  Otherwise a failure in the sed will
leave what appears to be an up to date file.

Honestly I'm not sure this patch is worth doing.  It adds a lot of
complex mechanism in order to test a patch that is fairly obvious.
While it's good practice to add a test for every change, it's not good
practice for the testsuite to become so complex that it becomes in
itself difficult to maintain.

Ian
Tom de Vries Jan. 29, 2019, 8:25 a.m. UTC | #10
On 27-01-19 22:53, Ian Lance Taylor wrote:
> On Sun, Jan 27, 2019 at 1:16 PM Tom de Vries <tdevries@suse.de> wrote:
>>
>> On 25-01-19 18:15, Nathan Sidwell wrote:
>>> On 1/25/19 5:28 AM, Tom de Vries wrote:
>>>>
>>>> This patch fixes it by passing "" instead of NULL, in the call to
>>>> elf_add at line 3083 (for .gnu_debugaltlink), not the call to elf_add at
>>>> line 3044 (for .gnu_debuglink) mentioned above.
>>>>
>>>> Nathan, does this fix the problem for you? If not, can you provide a
>>>> reproducer, or give a hint on how one could be constructed?
>>>
>>> I still hit the problem, and am installing this as sufficiently obvious.
>>>  I'm on a fedora system debugging pr88995.  The debuglink_name is
>>> "../../.dwz/isl-0.16.1-7.fc29.x86_64"
>>>
>>
>> I've managed to reproduce this segfault instance by adding a test-case
>> that uses both build-id and dwz.
>>
>> OK for trunk?
> 
>> +elf_for_test.c: elf.c
>> + PWD=$$(pwd -P); \
>> + BUILD_ID_DIR="usr/lib/debug/.build-id/"; \
>> + SEARCH='#define SYSTEM_BUILD_ID_DIR'; \
>> + REPLACE="#define SYSTEM_BUILD_ID_DIR \"$$PWD/$$BUILD_ID_DIR\""; \
>> + $(SED) "s%^$$SEARCH.*\$$%$$REPLACE%" \
>> + $< \
>> + > $@
> 
> You need to use a temporary file, such as $@.tmp, for the final sed
> command, followed by a mv to $@.  Otherwise a failure in the sed will
> leave what appears to be an up to date file.
> 

Done.

Also, I've factored out a script install-debuginfo-for-buildid.sh,
hoping this will make things more readable/maintainable.

> Honestly I'm not sure this patch is worth doing.  It adds a lot of
> complex mechanism in order to test a patch that is fairly obvious.

Agreed, the patch is fairly obvious.

But at the moment, there's no test-case that exercises the build-id
support in libbacktrace. IMO, that alone would be a good reason to add
this test-case.

> While it's good practice to add a test for every change, it's not good
> practice for the testsuite to become so complex that it becomes in
> itself difficult to maintain.

Understood.

Please let me know if this is acceptable, or if I can do anything that
would make this easier to maintain.

Thanks,
- Tom
[libbacktrace] Add test-cases exercising build-id and dwz

Add test-cases b2test_buildid and b3test_dwz_buildid.

The last one triggers the segfault fixed by "[backtrace] Avoid segfault"
( r268275 ).

2019-01-27  Tom de Vries  <tdevries@suse.de>

	* install-debuginfo-for-buildid.sh.in: New script.
	* Makefile.am (check_PROGRAMS): Add b2test and b3test.
	(TESTS): Add b2test_buildid and b3test_dwz_buildid.
	* Makefile.in: Regenerate.
	* configure.ac (HAVE_ELF): Set with AM_CONDITIONAL.
	(READELF): Set with AC_CHECK_PROG.
	(install-debuginfo-for-buildid.sh): Generate with AC_CONFIG_FILES.
	* configure: Regenerate.
	* elf.c (SYSTEM_BUILD_ID_DIR): Factor out of ...
	(elf_open_debugfile_by_buildid): ... here.

---
 libbacktrace/Makefile.am                         |  50 ++++++
 libbacktrace/Makefile.in                         | 193 ++++++++++++++++++-----
 libbacktrace/configure                           |  60 ++++++-
 libbacktrace/configure.ac                        |   3 +
 libbacktrace/elf.c                               |   4 +-
 libbacktrace/install-debuginfo-for-buildid.sh.in |  27 ++++
 6 files changed, 294 insertions(+), 43 deletions(-)

diff --git a/libbacktrace/Makefile.am b/libbacktrace/Makefile.am
index 1c4ab07aa19..71a2ed478cc 100644
--- a/libbacktrace/Makefile.am
+++ b/libbacktrace/Makefile.am
@@ -108,6 +108,28 @@ libbacktrace_noformat_la_LIBADD = $(BACKTRACE_FILE) $(VIEW_FILE) $(ALLOC_FILE)
 
 libbacktrace_noformat_la_DEPENDENCIES = $(libbacktrace_noformat_la_LIBADD)
 
+if HAVE_ELF
+if HAVE_OBJCOPY_DEBUGLINK
+
+TEST_BUILD_ID_DIR=$(abs_builddir)/usr/lib/debug/.build-id/
+
+check_LTLIBRARIES += libbacktrace_elf_for_test.la
+
+libbacktrace_elf_for_test_la_SOURCES = $(libbacktrace_la_SOURCES)
+libbacktrace_elf_for_test_la_LIBADD = $(BACKTRACE_FILE) elf_for_test.lo \
+	$(VIEW_FILE) $(ALLOC_FILE)
+
+elf_for_test.c: elf.c
+	SEARCH='^#define SYSTEM_BUILD_ID_DIR.*$$'; \
+	REPLACE="#define SYSTEM_BUILD_ID_DIR \"$(TEST_BUILD_ID_DIR)\""; \
+	$(SED) "s%$$SEARCH%$$REPLACE%" \
+		$< \
+		> $@.tmp
+	mv $@.tmp $@
+
+endif HAVE_OBJCOPY_DEBUGLINK
+endif HAVE_ELF
+
 xcoff_%.c: xcoff.c
 	SEARCH='#error "Unknown BACKTRACE_XCOFF_SIZE"'; \
 	REPLACE='#undef BACKTRACE_XCOFF_SIZE\
@@ -172,6 +194,28 @@ allocfail.sh: allocfail
 
 TESTS += allocfail.sh
 
+if HAVE_ELF
+if HAVE_OBJCOPY_DEBUGLINK
+
+b2test_SOURCES = $(btest_SOURCES)
+b2test_CFLAGS = $(btest_CFLAGS)
+b2test_LDFLAGS = -Wl,--build-id
+b2test_LDADD = libbacktrace_elf_for_test.la
+
+check_PROGRAMS += b2test
+TESTS += b2test_buildid
+
+b3test_SOURCES = $(btest_SOURCES)
+b3test_CFLAGS = $(btest_CFLAGS)
+b3test_LDFLAGS = -Wl,--build-id
+b3test_LDADD = libbacktrace_elf_for_test.la
+
+check_PROGRAMS += b3test
+TESTS += b3test_dwz_buildid
+
+endif HAVE_OBJCOPY_DEBUGLINK
+endif HAVE_ELF
+
 btest_SOURCES = btest.c testlib.c
 btest_CFLAGS = $(AM_CFLAGS) -g -O
 btest_LDADD = libbacktrace.la
@@ -275,6 +319,12 @@ TESTS += btest_gnudebuglink
 
 endif HAVE_OBJCOPY_DEBUGLINK
 
+%_buildid: %
+	./install-debuginfo-for-buildid.sh \
+	  "$(TEST_BUILD_ID_DIR)" \
+	  $<
+	$(OBJCOPY) --strip-debug $< $@
+
 if HAVE_COMPRESSED_DEBUG
 
 ctestg_SOURCES = btest.c testlib.c
diff --git a/libbacktrace/Makefile.in b/libbacktrace/Makefile.in
index 862fc8ca314..a2b595e9bb0 100644
--- a/libbacktrace/Makefile.in
+++ b/libbacktrace/Makefile.in
@@ -120,22 +120,27 @@ POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
 target_triplet = @target@
-check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_5)
-TESTS = $(am__append_3) $(am__append_4) $(am__append_5) \
-	$(am__append_9) $(am__EXEEXT_5)
-@NATIVE_TRUE@am__append_1 = test_elf test_xcoff_32 test_xcoff_64 \
+check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_6)
+TESTS = $(am__append_4) $(am__append_6) $(am__append_7) \
+	$(am__append_8) $(am__append_12) $(am__EXEEXT_6)
+@HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am__append_1 = libbacktrace_elf_for_test.la
+@NATIVE_TRUE@am__append_2 = test_elf test_xcoff_32 test_xcoff_64 \
 @NATIVE_TRUE@	test_pecoff test_unknown unittest unittest_alloc \
 @NATIVE_TRUE@	btest btest_alloc stest stest_alloc ztest \
 @NATIVE_TRUE@	ztest_alloc edtest edtest_alloc
-@NATIVE_TRUE@am__append_2 = allocfail
-@NATIVE_TRUE@am__append_3 = allocfail.sh
-@HAVE_DWZ_TRUE@@NATIVE_TRUE@am__append_4 = btest_dwz
-@HAVE_DWZ_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am__append_5 = btest_dwz_gnudebuglink
-@HAVE_ZLIB_TRUE@@NATIVE_TRUE@am__append_6 = -lz
-@HAVE_ZLIB_TRUE@@NATIVE_TRUE@am__append_7 = -lz
-@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__append_8 = ttest ttest_alloc
-@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am__append_9 = btest_gnudebuglink
-@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__append_10 = ctestg ctesta \
+@NATIVE_TRUE@am__append_3 = allocfail
+@NATIVE_TRUE@am__append_4 = allocfail.sh
+@HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am__append_5 = b2test \
+@HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@	b3test
+@HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am__append_6 = b2test_buildid \
+@HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@	b3test_dwz_buildid
+@HAVE_DWZ_TRUE@@NATIVE_TRUE@am__append_7 = btest_dwz
+@HAVE_DWZ_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am__append_8 = btest_dwz_gnudebuglink
+@HAVE_ZLIB_TRUE@@NATIVE_TRUE@am__append_9 = -lz
+@HAVE_ZLIB_TRUE@@NATIVE_TRUE@am__append_10 = -lz
+@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__append_11 = ttest ttest_alloc
+@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am__append_12 = btest_gnudebuglink
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__append_13 = ctestg ctesta \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctestg_alloc \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctesta_alloc
 subdir = .
@@ -159,7 +164,8 @@ am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
  configure.lineno config.status.lineno
 mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
 CONFIG_HEADER = config.h
-CONFIG_CLEAN_FILES = backtrace-supported.h
+CONFIG_CLEAN_FILES = backtrace-supported.h \
+	install-debuginfo-for-buildid.sh
 CONFIG_CLEAN_VPATH_FILES =
 LTLIBRARIES = $(noinst_LTLIBRARIES)
 am__DEPENDENCIES_1 =
@@ -175,6 +181,14 @@ am__objects_1 = atomic.lo dwarf.lo fileline.lo posix.lo print.lo \
 @NATIVE_TRUE@am_libbacktrace_alloc_la_OBJECTS = $(am__objects_1)
 libbacktrace_alloc_la_OBJECTS = $(am_libbacktrace_alloc_la_OBJECTS)
 @NATIVE_TRUE@am_libbacktrace_alloc_la_rpath =
+@HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@libbacktrace_elf_for_test_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+@HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@	elf_for_test.lo \
+@HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@	$(am__DEPENDENCIES_1) \
+@HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@	$(am__DEPENDENCIES_1)
+@HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am_libbacktrace_elf_for_test_la_OBJECTS = $(am__objects_1)
+libbacktrace_elf_for_test_la_OBJECTS =  \
+	$(am_libbacktrace_elf_for_test_la_OBJECTS)
+@HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am_libbacktrace_elf_for_test_la_rpath =
 @NATIVE_TRUE@am_libbacktrace_instrumented_alloc_la_OBJECTS =  \
 @NATIVE_TRUE@	$(am__objects_1)
 libbacktrace_instrumented_alloc_la_OBJECTS =  \
@@ -185,7 +199,9 @@ libbacktrace_noformat_la_OBJECTS =  \
 	$(am_libbacktrace_noformat_la_OBJECTS)
 @NATIVE_TRUE@am_libbacktrace_noformat_la_rpath =
 @NATIVE_TRUE@am__EXEEXT_1 = allocfail$(EXEEXT)
-@NATIVE_TRUE@am__EXEEXT_2 = test_elf$(EXEEXT) test_xcoff_32$(EXEEXT) \
+@HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am__EXEEXT_2 = b2test$(EXEEXT) \
+@HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@	b3test$(EXEEXT)
+@NATIVE_TRUE@am__EXEEXT_3 = test_elf$(EXEEXT) test_xcoff_32$(EXEEXT) \
 @NATIVE_TRUE@	test_xcoff_64$(EXEEXT) test_pecoff$(EXEEXT) \
 @NATIVE_TRUE@	test_unknown$(EXEEXT) unittest$(EXEEXT) \
 @NATIVE_TRUE@	unittest_alloc$(EXEEXT) btest$(EXEEXT) \
@@ -193,19 +209,35 @@ libbacktrace_noformat_la_OBJECTS =  \
 @NATIVE_TRUE@	stest_alloc$(EXEEXT) ztest$(EXEEXT) \
 @NATIVE_TRUE@	ztest_alloc$(EXEEXT) edtest$(EXEEXT) \
 @NATIVE_TRUE@	edtest_alloc$(EXEEXT)
-@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__EXEEXT_3 = ttest$(EXEEXT) \
+@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__EXEEXT_4 = ttest$(EXEEXT) \
 @HAVE_PTHREAD_TRUE@@NATIVE_TRUE@	ttest_alloc$(EXEEXT)
-@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__EXEEXT_4 =  \
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__EXEEXT_5 =  \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctestg$(EXEEXT) \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctesta$(EXEEXT) \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctestg_alloc$(EXEEXT) \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctesta_alloc$(EXEEXT)
-am__EXEEXT_5 = $(am__EXEEXT_2) $(am__EXEEXT_3) $(am__EXEEXT_4)
+am__EXEEXT_6 = $(am__EXEEXT_3) $(am__EXEEXT_4) $(am__EXEEXT_5)
 @NATIVE_TRUE@am_allocfail_OBJECTS = allocfail.$(OBJEXT) \
 @NATIVE_TRUE@	testlib.$(OBJEXT)
 allocfail_OBJECTS = $(am_allocfail_OBJECTS)
 @NATIVE_TRUE@allocfail_DEPENDENCIES =  \
 @NATIVE_TRUE@	libbacktrace_instrumented_alloc.la
+@NATIVE_TRUE@am__objects_2 = b2test-btest.$(OBJEXT) \
+@NATIVE_TRUE@	b2test-testlib.$(OBJEXT)
+@HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am_b2test_OBJECTS = $(am__objects_2)
+b2test_OBJECTS = $(am_b2test_OBJECTS)
+@HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@b2test_DEPENDENCIES = libbacktrace_elf_for_test.la
+b2test_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(b2test_CFLAGS) $(CFLAGS) \
+	$(b2test_LDFLAGS) $(LDFLAGS) -o $@
+@NATIVE_TRUE@am__objects_3 = b3test-btest.$(OBJEXT) \
+@NATIVE_TRUE@	b3test-testlib.$(OBJEXT)
+@HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am_b3test_OBJECTS = $(am__objects_3)
+b3test_OBJECTS = $(am_b3test_OBJECTS)
+@HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@b3test_DEPENDENCIES = libbacktrace_elf_for_test.la
+b3test_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(b3test_CFLAGS) $(CFLAGS) \
+	$(b3test_LDFLAGS) $(LDFLAGS) -o $@
 @NATIVE_TRUE@am_btest_OBJECTS = btest-btest.$(OBJEXT) \
 @NATIVE_TRUE@	btest-testlib.$(OBJEXT)
 btest_OBJECTS = $(am_btest_OBJECTS)
@@ -213,9 +245,9 @@ btest_OBJECTS = $(am_btest_OBJECTS)
 btest_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
 	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(btest_CFLAGS) $(CFLAGS) \
 	$(AM_LDFLAGS) $(LDFLAGS) -o $@
-@NATIVE_TRUE@am__objects_2 = btest_alloc-btest.$(OBJEXT) \
+@NATIVE_TRUE@am__objects_4 = btest_alloc-btest.$(OBJEXT) \
 @NATIVE_TRUE@	btest_alloc-testlib.$(OBJEXT)
-@NATIVE_TRUE@am_btest_alloc_OBJECTS = $(am__objects_2)
+@NATIVE_TRUE@am_btest_alloc_OBJECTS = $(am__objects_4)
 btest_alloc_OBJECTS = $(am_btest_alloc_OBJECTS)
 @NATIVE_TRUE@btest_alloc_DEPENDENCIES = libbacktrace_alloc.la
 btest_alloc_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
@@ -229,10 +261,10 @@ ctesta_OBJECTS = $(am_ctesta_OBJECTS)
 ctesta_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
 	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(ctesta_CFLAGS) $(CFLAGS) \
 	$(ctesta_LDFLAGS) $(LDFLAGS) -o $@
-@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__objects_3 = ctesta_alloc-btest.$(OBJEXT) \
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__objects_5 = ctesta_alloc-btest.$(OBJEXT) \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctesta_alloc-testlib.$(OBJEXT)
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am_ctesta_alloc_OBJECTS =  \
-@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	$(am__objects_3)
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	$(am__objects_5)
 ctesta_alloc_OBJECTS = $(am_ctesta_alloc_OBJECTS)
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ctesta_alloc_DEPENDENCIES = libbacktrace_alloc.la
 ctesta_alloc_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
@@ -246,10 +278,10 @@ ctestg_OBJECTS = $(am_ctestg_OBJECTS)
 ctestg_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
 	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(ctestg_CFLAGS) $(CFLAGS) \
 	$(ctestg_LDFLAGS) $(LDFLAGS) -o $@
-@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__objects_4 = ctestg_alloc-btest.$(OBJEXT) \
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__objects_6 = ctestg_alloc-btest.$(OBJEXT) \
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	ctestg_alloc-testlib.$(OBJEXT)
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am_ctestg_alloc_OBJECTS =  \
-@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	$(am__objects_4)
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@	$(am__objects_6)
 ctestg_alloc_OBJECTS = $(am_ctestg_alloc_OBJECTS)
 @HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ctestg_alloc_DEPENDENCIES = libbacktrace_alloc.la
 ctestg_alloc_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
@@ -259,16 +291,16 @@ ctestg_alloc_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
 @NATIVE_TRUE@	edtest2_build.$(OBJEXT) testlib.$(OBJEXT)
 edtest_OBJECTS = $(am_edtest_OBJECTS)
 @NATIVE_TRUE@edtest_DEPENDENCIES = libbacktrace.la
-@NATIVE_TRUE@am__objects_5 = edtest.$(OBJEXT) edtest2_build.$(OBJEXT) \
+@NATIVE_TRUE@am__objects_7 = edtest.$(OBJEXT) edtest2_build.$(OBJEXT) \
 @NATIVE_TRUE@	testlib.$(OBJEXT)
-@NATIVE_TRUE@am_edtest_alloc_OBJECTS = $(am__objects_5)
+@NATIVE_TRUE@am_edtest_alloc_OBJECTS = $(am__objects_7)
 edtest_alloc_OBJECTS = $(am_edtest_alloc_OBJECTS)
 @NATIVE_TRUE@edtest_alloc_DEPENDENCIES = libbacktrace_alloc.la
 @NATIVE_TRUE@am_stest_OBJECTS = stest.$(OBJEXT)
 stest_OBJECTS = $(am_stest_OBJECTS)
 @NATIVE_TRUE@stest_DEPENDENCIES = libbacktrace.la
-@NATIVE_TRUE@am__objects_6 = stest.$(OBJEXT)
-@NATIVE_TRUE@am_stest_alloc_OBJECTS = $(am__objects_6)
+@NATIVE_TRUE@am__objects_8 = stest.$(OBJEXT)
+@NATIVE_TRUE@am_stest_alloc_OBJECTS = $(am__objects_8)
 stest_alloc_OBJECTS = $(am_stest_alloc_OBJECTS)
 @NATIVE_TRUE@stest_alloc_DEPENDENCIES = libbacktrace_alloc.la
 @NATIVE_TRUE@am_test_elf_OBJECTS = test_format.$(OBJEXT) \
@@ -303,11 +335,11 @@ ttest_OBJECTS = $(am_ttest_OBJECTS)
 ttest_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
 	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(ttest_CFLAGS) $(CFLAGS) \
 	$(AM_LDFLAGS) $(LDFLAGS) -o $@
-@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__objects_7 =  \
+@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__objects_9 =  \
 @HAVE_PTHREAD_TRUE@@NATIVE_TRUE@	ttest_alloc-ttest.$(OBJEXT) \
 @HAVE_PTHREAD_TRUE@@NATIVE_TRUE@	ttest_alloc-testlib.$(OBJEXT)
 @HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am_ttest_alloc_OBJECTS =  \
-@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@	$(am__objects_7)
+@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@	$(am__objects_9)
 ttest_alloc_OBJECTS = $(am_ttest_alloc_OBJECTS)
 @HAVE_PTHREAD_TRUE@@NATIVE_TRUE@ttest_alloc_DEPENDENCIES =  \
 @HAVE_PTHREAD_TRUE@@NATIVE_TRUE@	libbacktrace_alloc.la
@@ -318,8 +350,8 @@ ttest_alloc_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
 @NATIVE_TRUE@	testlib.$(OBJEXT)
 unittest_OBJECTS = $(am_unittest_OBJECTS)
 @NATIVE_TRUE@unittest_DEPENDENCIES = libbacktrace.la
-@NATIVE_TRUE@am__objects_8 = unittest.$(OBJEXT) testlib.$(OBJEXT)
-@NATIVE_TRUE@am_unittest_alloc_OBJECTS = $(am__objects_8)
+@NATIVE_TRUE@am__objects_10 = unittest.$(OBJEXT) testlib.$(OBJEXT)
+@NATIVE_TRUE@am_unittest_alloc_OBJECTS = $(am__objects_10)
 unittest_alloc_OBJECTS = $(am_unittest_alloc_OBJECTS)
 @NATIVE_TRUE@unittest_alloc_DEPENDENCIES = libbacktrace_alloc.la
 @NATIVE_TRUE@am_ztest_OBJECTS = ztest-ztest.$(OBJEXT) \
@@ -330,9 +362,9 @@ ztest_OBJECTS = $(am_ztest_OBJECTS)
 ztest_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
 	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(ztest_CFLAGS) $(CFLAGS) \
 	$(AM_LDFLAGS) $(LDFLAGS) -o $@
-@NATIVE_TRUE@am__objects_9 = ztest_alloc-ztest.$(OBJEXT) \
+@NATIVE_TRUE@am__objects_11 = ztest_alloc-ztest.$(OBJEXT) \
 @NATIVE_TRUE@	ztest_alloc-testlib.$(OBJEXT)
-@NATIVE_TRUE@am_ztest_alloc_OBJECTS = $(am__objects_9)
+@NATIVE_TRUE@am_ztest_alloc_OBJECTS = $(am__objects_11)
 ztest_alloc_OBJECTS = $(am_ztest_alloc_OBJECTS)
 @NATIVE_TRUE@ztest_alloc_DEPENDENCIES = libbacktrace_alloc.la \
 @NATIVE_TRUE@	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
@@ -374,9 +406,11 @@ am__v_CCLD_0 = @echo "  CCLD    " $@;
 am__v_CCLD_1 = 
 SOURCES = $(libbacktrace_la_SOURCES) $(EXTRA_libbacktrace_la_SOURCES) \
 	$(libbacktrace_alloc_la_SOURCES) \
+	$(libbacktrace_elf_for_test_la_SOURCES) \
 	$(libbacktrace_instrumented_alloc_la_SOURCES) \
 	$(libbacktrace_noformat_la_SOURCES) $(allocfail_SOURCES) \
-	$(btest_SOURCES) $(btest_alloc_SOURCES) $(ctesta_SOURCES) \
+	$(b2test_SOURCES) $(b3test_SOURCES) $(btest_SOURCES) \
+	$(btest_alloc_SOURCES) $(ctesta_SOURCES) \
 	$(ctesta_alloc_SOURCES) $(ctestg_SOURCES) \
 	$(ctestg_alloc_SOURCES) $(edtest_SOURCES) \
 	$(edtest_alloc_SOURCES) $(stest_SOURCES) \
@@ -683,6 +717,7 @@ PATH_SEPARATOR = @PATH_SEPARATOR@
 PIC_FLAG = @PIC_FLAG@
 PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
 RANLIB = @RANLIB@
+READELF = @READELF@
 SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
@@ -796,9 +831,9 @@ libbacktrace_la_LIBADD = \
 libbacktrace_la_DEPENDENCIES = $(libbacktrace_la_LIBADD)
 
 # Add test to this variable, if you want it to be build and run.
-BUILDTESTS = $(am__append_1) $(am__append_8) $(am__append_10)
+BUILDTESTS = $(am__append_2) $(am__append_11) $(am__append_13)
 @NATIVE_TRUE@check_LTLIBRARIES = libbacktrace_alloc.la \
-@NATIVE_TRUE@	libbacktrace_noformat.la \
+@NATIVE_TRUE@	libbacktrace_noformat.la $(am__append_1) \
 @NATIVE_TRUE@	libbacktrace_instrumented_alloc.la
 @NATIVE_TRUE@libbacktrace_alloc_la_SOURCES = $(libbacktrace_la_SOURCES)
 @NATIVE_TRUE@libbacktrace_alloc_la_LIBADD = $(BACKTRACE_FILE) $(FORMAT_FILE) read.lo alloc.lo
@@ -806,6 +841,11 @@ BUILDTESTS = $(am__append_1) $(am__append_8) $(am__append_10)
 @NATIVE_TRUE@libbacktrace_noformat_la_SOURCES = $(libbacktrace_la_SOURCES)
 @NATIVE_TRUE@libbacktrace_noformat_la_LIBADD = $(BACKTRACE_FILE) $(VIEW_FILE) $(ALLOC_FILE)
 @NATIVE_TRUE@libbacktrace_noformat_la_DEPENDENCIES = $(libbacktrace_noformat_la_LIBADD)
+@HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@TEST_BUILD_ID_DIR = $(abs_builddir)/usr/lib/debug/.build-id/
+@HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@libbacktrace_elf_for_test_la_SOURCES = $(libbacktrace_la_SOURCES)
+@HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@libbacktrace_elf_for_test_la_LIBADD = $(BACKTRACE_FILE) elf_for_test.lo \
+@HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@	$(VIEW_FILE) $(ALLOC_FILE)
+
 @NATIVE_TRUE@test_elf_SOURCES = test_format.c testlib.c
 @NATIVE_TRUE@test_elf_LDADD = libbacktrace_noformat.la elf.lo
 @NATIVE_TRUE@test_xcoff_32_SOURCES = test_format.c testlib.c
@@ -829,6 +869,14 @@ BUILDTESTS = $(am__append_1) $(am__append_8) $(am__append_10)
 
 @NATIVE_TRUE@allocfail_SOURCES = allocfail.c testlib.c
 @NATIVE_TRUE@allocfail_LDADD = libbacktrace_instrumented_alloc.la
+@HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@b2test_SOURCES = $(btest_SOURCES)
+@HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@b2test_CFLAGS = $(btest_CFLAGS)
+@HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@b2test_LDFLAGS = -Wl,--build-id
+@HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@b2test_LDADD = libbacktrace_elf_for_test.la
+@HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@b3test_SOURCES = $(btest_SOURCES)
+@HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@b3test_CFLAGS = $(btest_CFLAGS)
+@HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@b3test_LDFLAGS = -Wl,--build-id
+@HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@b3test_LDADD = libbacktrace_elf_for_test.la
 @NATIVE_TRUE@btest_SOURCES = btest.c testlib.c
 @NATIVE_TRUE@btest_CFLAGS = $(AM_CFLAGS) -g -O
 @NATIVE_TRUE@btest_LDADD = libbacktrace.la
@@ -841,10 +889,10 @@ BUILDTESTS = $(am__append_1) $(am__append_8) $(am__append_10)
 @NATIVE_TRUE@stest_alloc_LDADD = libbacktrace_alloc.la
 @NATIVE_TRUE@ztest_SOURCES = ztest.c testlib.c
 @NATIVE_TRUE@ztest_CFLAGS = -DSRCDIR=\"$(srcdir)\"
-@NATIVE_TRUE@ztest_LDADD = libbacktrace.la $(am__append_6) \
-@NATIVE_TRUE@	$(CLOCK_GETTIME_LINK)
-@NATIVE_TRUE@ztest_alloc_LDADD = libbacktrace_alloc.la $(am__append_7) \
+@NATIVE_TRUE@ztest_LDADD = libbacktrace.la $(am__append_9) \
 @NATIVE_TRUE@	$(CLOCK_GETTIME_LINK)
+@NATIVE_TRUE@ztest_alloc_LDADD = libbacktrace_alloc.la \
+@NATIVE_TRUE@	$(am__append_10) $(CLOCK_GETTIME_LINK)
 @NATIVE_TRUE@ztest_alloc_SOURCES = $(ztest_SOURCES)
 @NATIVE_TRUE@ztest_alloc_CFLAGS = $(ztest_CFLAGS)
 @NATIVE_TRUE@edtest_SOURCES = edtest.c edtest2_build.c testlib.c
@@ -948,6 +996,8 @@ distclean-hdr:
 	-rm -f config.h stamp-h1
 backtrace-supported.h: $(top_builddir)/config.status $(srcdir)/backtrace-supported.h.in
 	cd $(top_builddir) && $(SHELL) ./config.status $@
+install-debuginfo-for-buildid.sh: $(top_builddir)/config.status $(srcdir)/install-debuginfo-for-buildid.sh.in
+	cd $(top_builddir) && $(SHELL) ./config.status $@
 
 clean-checkLTLIBRARIES:
 	-test -z "$(check_LTLIBRARIES)" || rm -f $(check_LTLIBRARIES)
@@ -977,6 +1027,9 @@ libbacktrace.la: $(libbacktrace_la_OBJECTS) $(libbacktrace_la_DEPENDENCIES) $(EX
 libbacktrace_alloc.la: $(libbacktrace_alloc_la_OBJECTS) $(libbacktrace_alloc_la_DEPENDENCIES) $(EXTRA_libbacktrace_alloc_la_DEPENDENCIES) 
 	$(AM_V_CCLD)$(LINK) $(am_libbacktrace_alloc_la_rpath) $(libbacktrace_alloc_la_OBJECTS) $(libbacktrace_alloc_la_LIBADD) $(LIBS)
 
+libbacktrace_elf_for_test.la: $(libbacktrace_elf_for_test_la_OBJECTS) $(libbacktrace_elf_for_test_la_DEPENDENCIES) $(EXTRA_libbacktrace_elf_for_test_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(LINK) $(am_libbacktrace_elf_for_test_la_rpath) $(libbacktrace_elf_for_test_la_OBJECTS) $(libbacktrace_elf_for_test_la_LIBADD) $(LIBS)
+
 libbacktrace_instrumented_alloc.la: $(libbacktrace_instrumented_alloc_la_OBJECTS) $(libbacktrace_instrumented_alloc_la_DEPENDENCIES) $(EXTRA_libbacktrace_instrumented_alloc_la_DEPENDENCIES) 
 	$(AM_V_CCLD)$(LINK) $(am_libbacktrace_instrumented_alloc_la_rpath) $(libbacktrace_instrumented_alloc_la_OBJECTS) $(libbacktrace_instrumented_alloc_la_LIBADD) $(LIBS)
 
@@ -996,6 +1049,14 @@ allocfail$(EXEEXT): $(allocfail_OBJECTS) $(allocfail_DEPENDENCIES) $(EXTRA_alloc
 	@rm -f allocfail$(EXEEXT)
 	$(AM_V_CCLD)$(LINK) $(allocfail_OBJECTS) $(allocfail_LDADD) $(LIBS)
 
+b2test$(EXEEXT): $(b2test_OBJECTS) $(b2test_DEPENDENCIES) $(EXTRA_b2test_DEPENDENCIES) 
+	@rm -f b2test$(EXEEXT)
+	$(AM_V_CCLD)$(b2test_LINK) $(b2test_OBJECTS) $(b2test_LDADD) $(LIBS)
+
+b3test$(EXEEXT): $(b3test_OBJECTS) $(b3test_DEPENDENCIES) $(EXTRA_b3test_DEPENDENCIES) 
+	@rm -f b3test$(EXEEXT)
+	$(AM_V_CCLD)$(b3test_LINK) $(b3test_OBJECTS) $(b3test_LDADD) $(LIBS)
+
 btest$(EXEEXT): $(btest_OBJECTS) $(btest_DEPENDENCIES) $(EXTRA_btest_DEPENDENCIES) 
 	@rm -f btest$(EXEEXT)
 	$(AM_V_CCLD)$(btest_LINK) $(btest_OBJECTS) $(btest_LDADD) $(LIBS)
@@ -1095,6 +1156,30 @@ distclean-compile:
 .c.lo:
 	$(AM_V_CC)$(LTCOMPILE) -c -o $@ $<
 
+b2test-btest.o: btest.c
+	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(b2test_CFLAGS) $(CFLAGS) -c -o b2test-btest.o `test -f 'btest.c' || echo '$(srcdir)/'`btest.c
+
+b2test-btest.obj: btest.c
+	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(b2test_CFLAGS) $(CFLAGS) -c -o b2test-btest.obj `if test -f 'btest.c'; then $(CYGPATH_W) 'btest.c'; else $(CYGPATH_W) '$(srcdir)/btest.c'; fi`
+
+b2test-testlib.o: testlib.c
+	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(b2test_CFLAGS) $(CFLAGS) -c -o b2test-testlib.o `test -f 'testlib.c' || echo '$(srcdir)/'`testlib.c
+
+b2test-testlib.obj: testlib.c
+	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(b2test_CFLAGS) $(CFLAGS) -c -o b2test-testlib.obj `if test -f 'testlib.c'; then $(CYGPATH_W) 'testlib.c'; else $(CYGPATH_W) '$(srcdir)/testlib.c'; fi`
+
+b3test-btest.o: btest.c
+	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(b3test_CFLAGS) $(CFLAGS) -c -o b3test-btest.o `test -f 'btest.c' || echo '$(srcdir)/'`btest.c
+
+b3test-btest.obj: btest.c
+	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(b3test_CFLAGS) $(CFLAGS) -c -o b3test-btest.obj `if test -f 'btest.c'; then $(CYGPATH_W) 'btest.c'; else $(CYGPATH_W) '$(srcdir)/btest.c'; fi`
+
+b3test-testlib.o: testlib.c
+	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(b3test_CFLAGS) $(CFLAGS) -c -o b3test-testlib.o `test -f 'testlib.c' || echo '$(srcdir)/'`testlib.c
+
+b3test-testlib.obj: testlib.c
+	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(b3test_CFLAGS) $(CFLAGS) -c -o b3test-testlib.obj `if test -f 'testlib.c'; then $(CYGPATH_W) 'testlib.c'; else $(CYGPATH_W) '$(srcdir)/testlib.c'; fi`
+
 btest-btest.o: btest.c
 	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(btest_CFLAGS) $(CFLAGS) -c -o btest-btest.o `test -f 'btest.c' || echo '$(srcdir)/'`btest.c
 
@@ -1431,6 +1516,20 @@ allocfail.sh.log: allocfail.sh
 	--log-file $$b.log --trs-file $$b.trs \
 	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
 	"$$tst" $(AM_TESTS_FD_REDIRECT)
+b2test_buildid.log: b2test_buildid
+	@p='b2test_buildid'; \
+	b='b2test_buildid'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+b3test_dwz_buildid.log: b3test_dwz_buildid
+	@p='b3test_dwz_buildid'; \
+	b='b3test_dwz_buildid'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
 btest_dwz.log: btest_dwz
 	@p='btest_dwz'; \
 	b='btest_dwz'; \
@@ -1748,6 +1847,14 @@ uninstall-am:
 .PRECIOUS: Makefile
 
 
+@HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@elf_for_test.c: elf.c
+@HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@	SEARCH='^#define SYSTEM_BUILD_ID_DIR.*$$'; \
+@HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@	REPLACE="#define SYSTEM_BUILD_ID_DIR \"$(TEST_BUILD_ID_DIR)\""; \
+@HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@	$(SED) "s%$$SEARCH%$$REPLACE%" \
+@HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@		$< \
+@HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@		> $@.tmp
+@HAVE_ELF_TRUE@@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@	mv $@.tmp $@
+
 @NATIVE_TRUE@xcoff_%.c: xcoff.c
 @NATIVE_TRUE@	SEARCH='#error "Unknown BACKTRACE_XCOFF_SIZE"'; \
 @NATIVE_TRUE@	REPLACE='#undef BACKTRACE_XCOFF_SIZE\
@@ -1778,6 +1885,12 @@ uninstall-am:
 @HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@%_gnudebuglink: %
 @HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@	$(OBJCOPY) --only-keep-debug $< $@.debug
 @HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@	$(OBJCOPY) --strip-debug --add-gnu-debuglink=$@.debug $< $@
+
+@NATIVE_TRUE@%_buildid: %
+@NATIVE_TRUE@	./install-debuginfo-for-buildid.sh \
+@NATIVE_TRUE@	  "$(TEST_BUILD_ID_DIR)" \
+@NATIVE_TRUE@	  $<
+@NATIVE_TRUE@	$(OBJCOPY) --strip-debug $< $@
 alloc.lo: config.h backtrace.h internal.h
 backtrace.lo: config.h backtrace.h internal.h
 btest.lo: (INCDIR)/filenames.h backtrace.h backtrace-supported.h
diff --git a/libbacktrace/configure b/libbacktrace/configure
index 2ea112bde68..51d7cb4582a 100755
--- a/libbacktrace/configure
+++ b/libbacktrace/configure
@@ -637,6 +637,7 @@ NATIVE_FALSE
 NATIVE_TRUE
 HAVE_OBJCOPY_DEBUGLINK_FALSE
 HAVE_OBJCOPY_DEBUGLINK_TRUE
+READELF
 OBJCOPY
 HAVE_COMPRESSED_DEBUG_FALSE
 HAVE_COMPRESSED_DEBUG_TRUE
@@ -651,6 +652,8 @@ ALLOC_FILE
 VIEW_FILE
 BACKTRACE_SUPPORTS_DATA
 BACKTRACE_SUPPORTED
+HAVE_ELF_FALSE
+HAVE_ELF_TRUE
 FORMAT_FILE
 BACKTRACE_SUPPORTS_THREADS
 PIC_FLAG
@@ -11489,7 +11492,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11492 "configure"
+#line 11495 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -11595,7 +11598,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 11598 "configure"
+#line 11601 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -12512,6 +12515,14 @@ cat >>confdefs.h <<_ACEOF
 #define BACKTRACE_ELF_SIZE $elfsize
 _ACEOF
 
+ if test "$FORMAT_FILE" = "elf.lo"; then
+  HAVE_ELF_TRUE=
+  HAVE_ELF_FALSE='#'
+else
+  HAVE_ELF_TRUE='#'
+  HAVE_ELF_FALSE=
+fi
+
 
 # XCOFF defines.
 xcoffsize=
@@ -13400,6 +13411,43 @@ $as_echo "no" >&6; }
 fi
 
 
+# Extract the first word of "readelf", so it can be a program name with args.
+set dummy readelf; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_READELF+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$READELF"; then
+  ac_cv_prog_READELF="$READELF" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_READELF="readelf"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+READELF=$ac_cv_prog_READELF
+if test -n "$READELF"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $READELF" >&5
+$as_echo "$READELF" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether objcopy supports debuglink" >&5
 $as_echo_n "checking whether objcopy supports debuglink... " >&6; }
 if ${libbacktrace_cv_objcopy_debuglink+:} false; then :
@@ -13473,6 +13521,8 @@ fi
 
 ac_config_files="$ac_config_files Makefile backtrace-supported.h"
 
+ac_config_files="$ac_config_files install-debuginfo-for-buildid.sh"
+
 
 # We need multilib support, but only if configuring for the target.
 ac_config_commands="$ac_config_commands default"
@@ -13611,6 +13661,10 @@ if test -z "${HAVE_DWZ_TRUE}" && test -z "${HAVE_DWZ_FALSE}"; then
   as_fn_error $? "conditional \"HAVE_DWZ\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
+if test -z "${HAVE_ELF_TRUE}" && test -z "${HAVE_ELF_FALSE}"; then
+  as_fn_error $? "conditional \"HAVE_ELF\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
 if test -z "${HAVE_PTHREAD_TRUE}" && test -z "${HAVE_PTHREAD_FALSE}"; then
   as_fn_error $? "conditional \"HAVE_PTHREAD\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
@@ -14525,6 +14579,7 @@ do
     "gstdint.h") CONFIG_COMMANDS="$CONFIG_COMMANDS gstdint.h" ;;
     "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
     "backtrace-supported.h") CONFIG_FILES="$CONFIG_FILES backtrace-supported.h" ;;
+    "install-debuginfo-for-buildid.sh") CONFIG_FILES="$CONFIG_FILES install-debuginfo-for-buildid.sh" ;;
     "default") CONFIG_COMMANDS="$CONFIG_COMMANDS default" ;;
 
   *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
@@ -16140,6 +16195,7 @@ else
 fi
 
  ;;
+    "install-debuginfo-for-buildid.sh":F) chmod +x install-debuginfo-for-buildid.sh ;;
     "default":C) if test -n "$CONFIG_FILES"; then
    if test -n "${with_target_subdir}"; then
      # Multilibs need MULTISUBDIR defined correctly in certain makefiles so
diff --git a/libbacktrace/configure.ac b/libbacktrace/configure.ac
index c64bf3473bb..dd25095dcf8 100644
--- a/libbacktrace/configure.ac
+++ b/libbacktrace/configure.ac
@@ -259,6 +259,7 @@ elf64) elfsize=64 ;;
 *)     elfsize=unused
 esac
 AC_DEFINE_UNQUOTED([BACKTRACE_ELF_SIZE], [$elfsize], [ELF size: 32 or 64])
+AM_CONDITIONAL(HAVE_ELF, test "$FORMAT_FILE" = "elf.lo")
 
 # XCOFF defines.
 xcoffsize=
@@ -445,6 +446,7 @@ AM_CONDITIONAL(HAVE_COMPRESSED_DEBUG, test "$libgo_cv_ld_compress" = yes)
 
 AC_ARG_VAR(OBJCOPY, [location of objcopy])
 AC_CHECK_PROG(OBJCOPY, objcopy, objcopy,)
+AC_CHECK_PROG(READELF, readelf, readelf)
 AC_CACHE_CHECK([whether objcopy supports debuglink],
 [libbacktrace_cv_objcopy_debuglink],
 [if test -n "${with_target_subdir}"; then
@@ -472,6 +474,7 @@ else
 fi
 
 AC_CONFIG_FILES(Makefile backtrace-supported.h)
+AC_CONFIG_FILES(install-debuginfo-for-buildid.sh, chmod +x install-debuginfo-for-buildid.sh)
 
 # We need multilib support, but only if configuring for the target.
 AC_CONFIG_COMMANDS([default],
diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c
index 6fee865bece..d933052200c 100644
--- a/libbacktrace/elf.c
+++ b/libbacktrace/elf.c
@@ -809,6 +809,8 @@ elf_readlink (struct backtrace_state *state, const char *filename,
     }
 }
 
+#define SYSTEM_BUILD_ID_DIR "/usr/lib/debug/.build-id/"
+
 /* Open a separate debug info file, using the build ID to find it.
    Returns an open file descriptor, or -1.
 
@@ -821,7 +823,7 @@ elf_open_debugfile_by_buildid (struct backtrace_state *state,
 			       backtrace_error_callback error_callback,
 			       void *data)
 {
-  const char * const prefix = "/usr/lib/debug/.build-id/";
+  const char * const prefix = SYSTEM_BUILD_ID_DIR;
   const size_t prefix_len = strlen (prefix);
   const char * const suffix = ".debug";
   const size_t suffix_len = strlen (suffix);
diff --git a/libbacktrace/install-debuginfo-for-buildid.sh.in b/libbacktrace/install-debuginfo-for-buildid.sh.in
new file mode 100644
index 00000000000..59890d78359
--- /dev/null
+++ b/libbacktrace/install-debuginfo-for-buildid.sh.in
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+sed=@SED@
+awk=@AWK@
+grep=@GREP@
+objcopy=@OBJCOPY@
+readelf=@READELF@
+mkdir_p="@MKDIR_P@"
+build_id_dir="$1"
+src="$2"
+
+buildid=$($readelf -n $src \
+	      | $grep "Build ID" \
+	      | $awk '{print $3}')
+
+prefix=$(echo $buildid \
+	     | $sed 's/.//3g')
+
+remainder=$(echo $buildid \
+		| $sed 's/^.\{2\}//')
+
+dir=$build_id_dir/$prefix
+dst=$dir/$remainder.debug
+
+$mkdir_p $dir
+
+$objcopy --only-keep-debug $src $dst
Ian Lance Taylor Jan. 29, 2019, 3:04 p.m. UTC | #11
On Tue, Jan 29, 2019 at 12:24 AM Tom de Vries <tdevries@suse.de> wrote:
>
> On 27-01-19 22:53, Ian Lance Taylor wrote:
> > On Sun, Jan 27, 2019 at 1:16 PM Tom de Vries <tdevries@suse.de> wrote:
> >>
> >> On 25-01-19 18:15, Nathan Sidwell wrote:
> >>> On 1/25/19 5:28 AM, Tom de Vries wrote:
> >>>>
> >>>> This patch fixes it by passing "" instead of NULL, in the call to
> >>>> elf_add at line 3083 (for .gnu_debugaltlink), not the call to elf_add at
> >>>> line 3044 (for .gnu_debuglink) mentioned above.
> >>>>
> >>>> Nathan, does this fix the problem for you? If not, can you provide a
> >>>> reproducer, or give a hint on how one could be constructed?
> >>>
> >>> I still hit the problem, and am installing this as sufficiently obvious.
> >>>  I'm on a fedora system debugging pr88995.  The debuglink_name is
> >>> "../../.dwz/isl-0.16.1-7.fc29.x86_64"
> >>>
> >>
> >> I've managed to reproduce this segfault instance by adding a test-case
> >> that uses both build-id and dwz.
> >>
> >> OK for trunk?
> >
> >> +elf_for_test.c: elf.c
> >> + PWD=$$(pwd -P); \
> >> + BUILD_ID_DIR="usr/lib/debug/.build-id/"; \
> >> + SEARCH='#define SYSTEM_BUILD_ID_DIR'; \
> >> + REPLACE="#define SYSTEM_BUILD_ID_DIR \"$$PWD/$$BUILD_ID_DIR\""; \
> >> + $(SED) "s%^$$SEARCH.*\$$%$$REPLACE%" \
> >> + $< \
> >> + > $@
> >
> > You need to use a temporary file, such as $@.tmp, for the final sed
> > command, followed by a mv to $@.  Otherwise a failure in the sed will
> > leave what appears to be an up to date file.
> >
>
> Done.
>
> Also, I've factored out a script install-debuginfo-for-buildid.sh,
> hoping this will make things more readable/maintainable.
>
> > Honestly I'm not sure this patch is worth doing.  It adds a lot of
> > complex mechanism in order to test a patch that is fairly obvious.
>
> Agreed, the patch is fairly obvious.
>
> But at the moment, there's no test-case that exercises the build-id
> support in libbacktrace. IMO, that alone would be a good reason to add
> this test-case.
>
> > While it's good practice to add a test for every change, it's not good
> > practice for the testsuite to become so complex that it becomes in
> > itself difficult to maintain.
>
> Understood.
>
> Please let me know if this is acceptable, or if I can do anything that
> would make this easier to maintain.

I guess this is OK.

Please add a copyright header to the new shell script.  Also please
add a comment explaining what it does.

Thanks.

Ian
Segher Boessenkool Jan. 29, 2019, 11:16 p.m. UTC | #12
On Sun, Jan 27, 2019 at 01:53:18PM -0800, Ian Lance Taylor wrote:
> You need to use a temporary file, such as $@.tmp, for the final sed
> command, followed by a mv to $@.  Otherwise a failure in the sed will
> leave what appears to be an up to date file.

Or you just set .DELETE_ON_ERROR, we require GNU make after all so might
as well use it!


Segher
Ian Lance Taylor Jan. 30, 2019, 12:49 a.m. UTC | #13
On Tue, Jan 29, 2019 at 3:17 PM Segher Boessenkool
<segher@kernel.crashing.org> wrote:
>
> On Sun, Jan 27, 2019 at 01:53:18PM -0800, Ian Lance Taylor wrote:
> > You need to use a temporary file, such as $@.tmp, for the final sed
> > command, followed by a mv to $@.  Otherwise a failure in the sed will
> > leave what appears to be an up to date file.
>
> Or you just set .DELETE_ON_ERROR, we require GNU make after all so might
> as well use it!

It's useful, but it doesn't help if the file is partially written on
disk and then the computer crashes.  It also doesn't help if the
program is not careful to check for errors on writing to standard
output--many programs aren't--and the disk fills up after writing out
part of the file.  Yes, both cases have happened to me when I was a
release engineer aeons ago, so I try to be careful.

Ian
diff mbox series

Patch

2019-01-24  Nathan Sidwell  <nathan@acm.org>

	* elf.c (elf_find_debugfile_by_debuglink): Protect against
	FILENAME being NULL.

Index: libbacktrace/elf.c
===================================================================
--- libbacktrace/elf.c	(revision 268252)
+++ libbacktrace/elf.c	(working copy)
@@ -970,13 +970,9 @@  elf_find_debugfile_by_debuglink (struct
 
   /* Look for DEBUGLINK_NAME in the same directory as FILENAME.  */
 
-  slash = strrchr (filename, '/');
-  if (slash == NULL)
-    {
-      prefix = "";
-      prefix_len = 0;
-    }
-  else
+  prefix = "";
+  prefix_len = 0;
+  if (filename && (slash = strrchr (filename, '/') != NULL)
     {
       slash++;
       prefix = filename;