Age | Commit message (Collapse) | Author | Files | Lines |
|
When a symbol's block is set, the block has the runtime section offset
applied. So, it seems to me that the symbol implicitly is in the same
section as the block. Therefore, this patch sets the symbol's section
index at this same spot.
|
|
The previous patch hard-coded SECT_OFF_TEXT into the buildsym code.
After this, it's clear that there is only one caller of
compunit_symtab::set_block_line_section, and it always passes
SECT_OFF_TEXT. So, remove compunit_symtab::m_block_line_section and
use SECT_OFF_TEXT instead.
|
|
Right now, the section index passed to end_compunit_symtab is always
SECT_OFF_TEXT. Remove this parameter and simply always use
SECT_OFF_TEXT.
|
|
Most places in gdb that create a new symbol will apply a section
offset to the address. It seems to me that the choice of offset here
is also an implicit choice of the section. This is particularly true
if you examine fixup_section, which notes that it must be called
before such offsets are applied -- meaning that if any such call has
an effect, it's purely by accident.
This patch cleans up this area by tracking the section index and
applying it to a symbol when the address is set. This is done for
nearly every case -- the remaining cases will be handled in later
patches.
|
|
If fixup_section does not find a matching section, it arbitrarily
chooses the first one. However, it seems better to make this default
depend on the type of the symbol -- i.e., default data symbols to
.data and text symbols to .text.
I've also made fixup_section static, as it only has one caller.
|
|
This changes the cooked_index_functions to avoid an extra null check
now that checked_static_cast allows a null argument.
Approved-By: Simon Marchi <simon.marchi@efficios.com>
|
|
Test-case gdb.base/longjmp.exp handles both the case that there is a libc
longjmp probe, and the case that there isn't.
However, it only tests one of the two cases.
Use maint ignore-probes to test both cases, if possible.
Tested on x86_64-linux.
|
|
Test-case gdb.base/solib-corrupted.exp only works for a glibc without probes
interface, otherwise we run into:
...
XFAIL: gdb.base/solib-corrupted.exp: info probes
UNTESTED: gdb.base/solib-corrupted.exp: GDB is using probes
...
Fix this by using maint ignore-probes to simulate the absence of the relevant
probes.
Also, it requires glibc debuginfo, and if not present, it produces an XFAIL:
...
XFAIL: gdb.base/solib-corrupted.exp: make solibs looping
UNTESTED: gdb.base/solib-corrupted.exp: no _r_debug symbol has been found
...
This is incorrect, because an XFAIL indicates a known problem in the
environment. In this case, there is no problem: the environment is
functioning as expected when glibc debuginfo is not installed.
Fix this by using UNSUPPORTED instead, and make the message less cryptic:
...
UNSUPPORTED: gdb.base/solib-corrupted.exp: make solibs looping \
(glibc debuginfo required)
...
Finally, with glibc debuginfo present, we run into:
...
(gdb) PASS: gdb.base/solib-corrupted.exp: make solibs looping
info sharedlibrary^M
warning: Corrupted shared library list: 0x7ffff7ffe750 != 0x0^M
From To Syms Read Shared Object Library^M
0x00007ffff7dd4170 0x00007ffff7df4090 Yes /lib64/ld-linux-x86-64.so.2^M
(gdb) FAIL: gdb.base/solib-corrupted.exp: corrupted list \
(shared library list corrupted)
...
due to commit 44288716537 ("gdb, testsuite: extend gdb_test_multiple checks").
Fix this by rewriting into gdb_test_multiple and using -early.
Tested on x86_64-linux, with and without glibc debuginfo installed.
|
|
gprofng/ChangeLog
2023-02-07 Vladimir Mezentsev <vladimir.mezentsev@oracle.com>
PR gprofng/30093
* src/Dwarf.cc: add nullptr check.
* src/DwarfLib.cc: Likewise.
|
|
f.bfd_ptr is set too early to be a reliable indicator of good debug
info.
* dwarf2.c (_bfd_dwarf2_slurp_debug_info): Correct test for
debug info being previously found.
|
|
|
|
This commit addresses the issue in PR gdb/30087.
If a breakpoint with multiple locations has a thread condition, then
the 'info breakpoints' output is a little messed up, here's an example
of the current output:
(gdb) break foo thread 1
Breakpoint 2 at 0x401114: foo. (3 locations)
(gdb) break bar thread 1
Breakpoint 3 at 0x40110a: file /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c, line 32.
(gdb) info breakpoints
Num Type Disp Enb Address What
2 breakpoint keep y <MULTIPLE> thread 1
stop only in thread 1
2.1 y 0x0000000000401114 in foo at /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c:25
2.2 y 0x0000000000401146 in foo at /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c:25
2.3 y 0x0000000000401168 in foo at /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c:25
3 breakpoint keep y 0x000000000040110a in bar at /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c:32 thread 1
stop only in thread 1
Notice that, at the end of the location for breakpoint 3, the 'thread
1' condition is printed, but this is then repeated on the next line
with 'stop only in thread 1'.
In contrast, for breakpoint 2, the 'thread 1' appears randomly, in the
"What" column, though slightly offset, non of the separate locations
have the 'thread 1' information. Additionally for breakpoint 2 we
also get a 'stop only in thread 1' line.
There's two things going on here. First the randomly placed 'thread
1' for breakpoint 2 is due to a bug in print_one_breakpoint_location,
where we check the variable part_of_multiple instead of
header_of_multiple.
If I fix this oversight, then the output is now:
(gdb) break foo thread 1
Breakpoint 2 at 0x401114: foo. (3 locations)
(gdb) break bar thread 1
Breakpoint 3 at 0x40110a: file /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c, line 32.
(gdb) info breakpoints
Num Type Disp Enb Address What
2 breakpoint keep y <MULTIPLE>
stop only in thread 1
2.1 y 0x0000000000401114 in foo at /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c:25 thread 1
2.2 y 0x0000000000401146 in foo at /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c:25 thread 1
2.3 y 0x0000000000401168 in foo at /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c:25 thread 1
3 breakpoint keep y 0x000000000040110a in bar at /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c:32 thread 1
stop only in thread 1
The 'thread 1' condition is now displayed at the end of each location,
which makes the output the same for single location breakpoints and
multi-location breakpoints.
However, there's still some duplication here. Both breakpoints 2 and
3 include a 'stop only in thread 1' line, and it feels like the
additional 'thread 1' is redundant. In fact, there's a comment to
this very effect in the code:
/* FIXME: This seems to be redundant and lost here; see the
"stop only in" line a little further down. */
So, lets fix this FIXME. The new plan is to remove all the trailing
'thread 1' markers from the CLI output, we now get this:
(gdb) break foo thread 1
Breakpoint 2 at 0x401114: foo. (3 locations)
(gdb) break bar thread 1
Breakpoint 3 at 0x40110a: file /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c, line 32.
(gdb) info breakpoints
Num Type Disp Enb Address What
2 breakpoint keep y <MULTIPLE>
stop only in thread 1
2.1 y 0x0000000000401114 in foo at /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c:25
2.2 y 0x0000000000401146 in foo at /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c:25
2.3 y 0x0000000000401168 in foo at /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c:25
3 breakpoint keep y 0x000000000040110a in bar at /tmp/src/gdb/testsuite/gdb.base/thread-bp-multi-loc.c:32
stop only in thread 1
All of the above points are also true for the Ada 'task' breakpoint
condition, and the changes I've made also update how the task
information is printed, though in the case of the Ada task there was
no 'stop only in task XXX' line printed, so I've added one of those.
Obviously it can't be quite that easy. For MI backwards compatibility
I've retained the existing code (but now only for MI like outputs),
which ensures we should generate backwards compatible output.
I've extended an Ada test to cover the new task related output, and
updated all the tests I could find that checked for the old output.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30087
Approved-By: Pedro Alves <pedro@palves.net>
|
|
PR 30080 * doc/binutils.texi (nm): Update description of the 'n' symbol type.
|
|
I came across:
...
UNTESTED: gdb.ada/finish-var-size.exp: GCC too told for this test
...
The message only tells us that the compiler version too old, not what compiler
version is required.
Fix this by rewriting using required:
...
UNSUPPORTED: gdb.ada/finish-var-size.exp: require failed: \
expr [gcc_major_version] >= 12
...
Tested on x86_64-linux.
|
|
|
|
Remove the stale reference to INFO, which is now "this target
description info" now.
Change-Id: I35dbdb089048ed7cfffe730d3134ee391b176abf
|
|
The documentation for the 'handle' command does not cover all of the
features of the command, and in one case, is just wrong.
The user can specify 'all' as signal name, the documentation implies
that this will change the behaviour of all signals, in reality, this
changes all signals except SIGINT and SIGTRAP (the signals used by
GDB). I've updated the docs to list this limitation.
The 'handle' command also allows the user to specify multiple signals
for a single command, e.g. 'handle SIGFPE SIGILL nostop pass print',
however the documentation doesn't describe this, so I've updated the
docs to describe this feature.
|
|
When using a bss-plt we'll always trigger the RWX warning, which
disturbs gcc test results. On the other hand, there may be reason to
want the warning when gcc is configured with --enable-secureplt.
So turning off the warning entirely for powerpc might not be the best
solution. Instead, we'll turn off the warning whenever a bss-plt is
generated, unless the user explicitly asked for the warning.
bfd/
* elf32-ppc.c (ppc_elf_select_plt_layout): Set
no_warn_rwx_segments on generating a bss plt, unless explicity
enabled by the user. Also show the bss-plt warning when
--warn-rwx-segments is given without --bss-plt.
include/
* bfdlink.h (struct bfd_link_info): Add user_warn_rwx_segments.
ld/
* lexsup.c (parse_args): Set user_warn_rwx_segments.
* testsuite/ld-elf/elf.exp: Pass --secure-plt for powerpc to
the rwx tests.
|
|
Occasionally, I run into:
...
(gdb) PASS: gdb.threads/schedlock.exp: schedlock=on: cmd=continue: \
set scheduler-locking on
continue^M
Continuing.^M
PASS: gdb.threads/schedlock.exp: schedlock=on: cmd=continue: \
continue (with lock)
[Thread 0x7ffff746e700 (LWP 1339) exited]^M
No unwaited-for children left.^M
(gdb) Quit^M
(gdb) FAIL: gdb.threads/schedlock.exp: schedlock=on: cmd=continue: \
stop all threads (with lock) (timeout)
...
What happens is that this loop which is supposed to run "just short of forever":
...
/* Don't run forever. Run just short of it :) */
while (*myp > 0)
{
/* schedlock.exp: main loop. */
MAYBE_CALL_SOME_FUNCTION(); (*myp) ++;
}
...
finishes after 0x7fffffff iterations (when a signed wrap occurs), which on my
system takes only about 1.5 seconds.
Fix this by:
- changing the pointed-at type of myp from signed to unsigned, which makes the
wrap defined behaviour (and which also make the loop run twice as long,
which is already enough to make it impossible for me to reproduce the FAIL.
But let's try to solve this more structurally).
- changing the pointed-at type of myp from int to long long, making the wrap
unlikely.
- making sure the loop runs forever, by setting the loop condition to 1.
- making sure the loop still contains different lines (as far as debug info is
concerned) by incrementing a volatile counter in the loop.
- making sure the program doesn't run forever in case of trouble, by adding an
"alarm (30)".
Tested on x86_64-linux.
PR testsuite/30074
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30074
|
|
When creating a breakpoint or watchpoint, the 'thread' and 'task'
keywords can be used to create a thread or task specific breakpoint or
watchpoint.
Currently, a thread or task specific breakpoint can only apply for a
single thread or task, if multiple threads or tasks are specified when
creating the breakpoint (or watchpoint), then the last specified id
will be used.
The exception to the above is that when the 'thread' keyword is used
during the creation of a watchpoint, GDB will give an error if
'thread' is given more than once.
In this commit I propose making this behaviour consistent, if the
'thread' or 'task' keywords are used more than once when creating
either a breakpoint or watchpoint, then GDB will give an error.
I haven't updated the manual, we don't explicitly say that these
keywords can be repeated, and (to me), given the keyword takes a
single id, I don't think it makes much sense to repeat the keyword.
As such, I see this more as adding a missing error to GDB, rather than
making some big change. However, I have added an entry to the NEWS
file as I guess it is possible that some people might hit this new
error with an existing (I claim, badly written) GDB script.
I've added some new tests to check for the new error.
Just one test needed updating, gdb.linespec/keywords.exp, this test
did use the 'thread' keyword twice, and expected the breakpoint to be
created. Looking at what this test was for though, it was checking
the use of '-force-condition', and I don't think that being able to
repeat 'thread' was actually a critical part of this test.
As such, I've updated this test to expect the error when 'thread' is
repeated.
|
|
There are failure paths in _bfd_dwarf2_slurp_debug_info that can
result in altered section vmas. Also, when setting ET_REL section
vmas it's not too difficult to handle cases where the original vma was
non-zero, so do that too.
This patch was really in response to an addr2line buffer overflow
processing a fuzzed mips relocatable object file. The file had a
number of .debug_info sections with relocations that included lo16 and
hi16 relocs, and in that order. At least one section VMA was
non-zero. This resulted in processing of DWARF info twice, once via
the call to _bfd_dwarf2_find_nearest_line in
_bfd_mips_elf_find_nearest_line, and because that failed leaving VMAs
altered, the second via the call in _bfd_elf_find_nearest_line. The
first call left entries on mips_hi16_list pointing at buffers
allocated during the first call, the second call processed the
mips_hi16_list after the buffers had been freed. (At least when
running with asan and under valgrind. Under gdb with a non-asan
addr2line the second call allocated exactly the same buffer and the
bug didn't show.) Now I don't really care too much what happens with
fuzzed files, but the logic in _bfd_dwarf2_find_nearest_line is meant
to result in only one read of .debug_info, not multiple reads of the
same info when there are errors. This patch fixes that problem.
* dwarf2.c (struct adjusted_section): Add orig_vma.
(unset_sections): Reset vma to it.
(place_sections): Handle non-zero vma too. Save orig_vma.
(_bfd_dwarf2_slurp_debug_info): Tidy. Correct outdated comment.
On error returns after calling place_sections, call
unset_sections.
(_bfd_dwarf2_find_nearest_line_with_alt): Simplify call to
unset_sections.
|
|
|
|
|
|
|
|
The test gdb.threads/thread-specific-bp.exp tries to set non-stop mode
on a running target, something which the manual makes clear is not
allowed.
This commit restructures the test a little, we now set the non-stop
mode as part of the GDBFLAGS, so the mode will be set before GDB
connects to the target. As a consequence I'm able to move the
with_test_prefix out of the check_thread_specific_breakpoint proc.
The check_thread_specific_breakpoint proc is now called within a loop.
After this commit the gdb.threads/thread-specific-bp.exp test still
has some failures, this is because of an issue GDB currently has
printing "Thread ... exited" messages. This problem should be
addressed by this patch:
https://sourceware.org/pipermail/gdb-patches/2022-December/194694.html
when it is merged.
|
|
The Texas Instruments SoCs with AARCH64 host processors have stricter
alignment requirements than ones with ARM32 host processors. It's not
only the requirement for resource_table to be aligned to 8. But also
any loadable segment size must be a multiple of 4 [1].
The current PRU default linker script may output a segment size not
aligned to 4, which would cause firmware load failure on AARCH64 hosts.
Fix this by using COMMONPAGESIZE and MAXPAGESIZE to signify respectively
the section memory size requirement and the resource table section's
start address alignment. This would avoid penalizing the ARM32 hosts,
for which the default values (1 and 1) are sufficient.
For AARCH64 hosts, the alignments would be overwritten from GCC spec
files using the linker command line, e.g.:
-z common-page-size=4 -z max-page-size=8
[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/remoteproc/pru_rproc.c?h=v6.1#n555
ld/ChangeLog:
* scripttempl/pru.sc (_data_end): Remove the alignment.
(.data): Align output section size to COMMONPAGESIZE.
(.resource_table): Ditto.
Signed-off-by: Dimitar Dimitrov <dimitar@dinux.eu>
|
|
The popular method to load PRU firmware is through the remoteproc Linux
kernel driver. In order to save a few bytes from the firmware, the PRU
CRT0 is spared from calling memset for the bss segment [1]. Instead the
host loader is supposed to zero out the bss segment. This is important
for PRU, which typically has only 8KB for instruction memory.
The legacy non-mainline PRU host driver relied on the default
behaviour of the kernel core remoteproc [2]. That default is to zero
out the loadable memory regions not backed by file storage (i.e. the
bss sections). This worked for the libgloss' CRT0.
But the PRU loader merged in mainline Linux explicitly changes the
default behaviour [3]. It no longer is zeroing out memory regions.
Hence the bss sections are not initialized - neither by CRT0, nor by the
host loader.
This patch fixes the issue by aligning the GNU LD default linker script
with the mainline Linux kernel expectation. Since the mainline kernel
driver is submitted by the PRU manufacturer itself (Text Instruments),
we can consider that as defining the ABI.
This change has been tested on Beaglebone AI-64 [4]. Static counter
variables in the firmware are now always starting from zero, as
expected. There was only one new toolchain test failure in orphan3.d,
due to reordering of the output sections. I believe this is a harmless
issue. I could not rewrite the PASS criteria to ignore the output
section ordering, so I have disabled that test case for PRU.
[1] https://sourceware.org/git/?p=newlib-cygwin.git;a=blob;f=libgloss/pru/crt0.S;h=b3f0d53a93acc372f461007553e7688ca77753c9;hb=HEAD#l40
[2] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/remoteproc/remoteproc_elf_loader.c?h=v6.1#n228
[3] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/remoteproc/pru_rproc.c?h=v6.1#n641
[4] https://beagleboard.org/ai-64
ld/ChangeLog:
* scripttempl/pru.sc (.data): Merge .bss input sections into the
.data output section.
* testsuite/ld-elf/orphan3.d: Disable for PRU.
Signed-off-by: Dimitar Dimitrov <dimitar@dinux.eu>
|
|
|
|
[-Werror=overflow]
Regenerating BPF target using the maintainer mode emits:
.../opcodes/bpf-opc.c:57:11: error: conversion from ‘long unsigned int’ to ‘unsigned int’ changes value from ‘18446744073709486335’ to ‘4294902015’ [-Werror=overflow]
57 | 64, 64, 0xffffffffffff00ff, { { F (F_IMM32) }, { F (F_OFFSET16) }, { F (F_SRCLE) }, { F (F_OP_CODE) }, { F (F_DSTLE) }, { F (F_OP_SRC) }, { F (F_OP_CLASS) }, { 0 } }
The use of a narrow size to handle the mask CGEN in instruction format
is causing this error. Additionally eBPF `call' instructions
constructed by expressions using symbols (BPF_PSEUDO_CALL) emits
annotations in `src' field of the instruction, used to identify BPF
target endianness.
cpu/
* bpf.cpu (define-call-insn): Remove `src' field from
instruction mask.
include/
*opcode/cge.h (CGEN_IFMT): Adjust mask bit width.
opcodes/
* bpf-opc.c: Regenerate.
|
|
Move the implementation over to target_desc_info. Remove the
target_desc_info forward declaration in target-descriptions.h, it's no
longer needed.
Change-Id: Ic95060341685afe0b73af591ca6efe32f5e7e892
|
|
This function is now trivial, we can just copy inferior::tdesc_info
where needed.
Change-Id: I25185e2cd4ba1ef24a822d9e0eebec6e611d54d6
|
|
Remove this function, since it's now a trivial access to
inferior::tdesc_info.
Change-Id: I3e88a8214034f1a4163420b434be11f51eef462c
|
|
I initially made this field a unique pointer, to have automatic memory
management. But I then thought that the field didn't really need to be
allocated separately from struct inferior. So make it a regular
non-pointer field of inferior.
Remove target_desc_info_free, as it's no longer needed.
Change-Id: Ica2b97071226f31c40e86222a2f6922454df1229
|
|
In preparation for the following patch, where struct inferior needs to
"see" struct target_desc_info, move target_desc_info to the header file.
I initially moved the structure to target-descriptions.h, and later made
inferior.h include target-descriptions.h. This worked, but it then
occured to me that target_desc_info is really an inferior property that
involves a target description, so I think it makes sense to have it in
inferior.h.
Change-Id: I3e81d04faafcad431e294357389f3d4c601ee83d
|
|
Since allocate_target_description returns a target_desc_up, use
assignment to initialize the description variable.
Change-Id: Iab3311642c09b95648984f305936f4a4cde09440
|
|
Like with segment overrides on LEA, optimize away such a redundant
instruction prefix.
|
|
Swapping operands for commutative insns occurs outside of
optimize_encoding() and hence needs explicit checking for a request to
avoid any optimizations.
|
|
Dropping a meaningless segment prefix occurs outside of
optimize_encoding() and hence needs explicit checking for a request to
avoid any optimizations.
|
|
The alternative encoding is valid for MOV, but there's no such thing for
MOVABS.
|
|
Insn width granularity being 16 bits, producing byte granular output
isn't very useful. With there being a way to specific otherwise
unknown insns to the assembler, use that same representation (to be
precise: its <length>,<encoding> flavor) for disassembly.
|
|
Anti-fuzzer measures. The checks don't ensure the various elements in
the header are distinct, but that isn't important as far as making
sure we don't overrun the buffer containing all the elements. Also,
we now don't care about offsets where the corresponding count is zero.
* ecoff.c (_bfd_ecoff_slurp_symbolic_info): Sanity check offsets
in debug->symbolic_header.
|
|
|
|
This patch adds the foundation for GDB to be able to debug programs
offloaded to AMD GPUs using the AMD ROCm platform [1]. The latest
public release of the ROCm release at the time of writing is 5.4, so
this is what this patch targets.
The ROCm platform allows host programs to schedule bits of code for
execution on GPUs or similar accelerators. The programs running on GPUs
are typically referred to as `kernels` (not related to operating system
kernels).
Programs offloaded with the AMD ROCm platform can be written in the HIP
language [2], OpenCL and OpenMP, but we're going to focus on HIP here.
The HIP language consists of a C++ Runtime API and kernel language.
Here's an example of a very simple HIP program:
#include "hip/hip_runtime.h"
#include <cassert>
__global__ void
do_an_addition (int a, int b, int *out)
{
*out = a + b;
}
int
main ()
{
int *result_ptr, result;
/* Allocate memory for the device to write the result to. */
hipError_t error = hipMalloc (&result_ptr, sizeof (int));
assert (error == hipSuccess);
/* Run `do_an_addition` on one workgroup containing one work item. */
do_an_addition<<<dim3(1), dim3(1), 0, 0>>> (1, 2, result_ptr);
/* Copy result from device to host. Note that this acts as a synchronization
point, waiting for the kernel dispatch to complete. */
error = hipMemcpyDtoH (&result, result_ptr, sizeof (int));
assert (error == hipSuccess);
printf ("result is %d\n", result);
assert (result == 3);
return 0;
}
This program can be compiled with:
$ hipcc simple.cpp -g -O0 -o simple
... where `hipcc` is the HIP compiler, shipped with ROCm releases. This
generates an ELF binary for the host architecture, containing another
ELF binary with the device code. The ELF for the device can be
inspected with:
$ roc-obj-ls simple
1 host-x86_64-unknown-linux file://simple#offset=8192&size=0
1 hipv4-amdgcn-amd-amdhsa--gfx906 file://simple#offset=8192&size=34216
$ roc-obj-extract 'file://simple#offset=8192&size=34216'
$ file simple-offset8192-size34216.co
simple-offset8192-size34216.co: ELF 64-bit LSB shared object, *unknown arch 0xe0* version 1, dynamically linked, with debug_info, not stripped
^
amcgcn architecture that my `file` doesn't know about ----´
Running the program gives the very unimpressive result:
$ ./simple
result is 3
While running, this host program has copied the device program into the
GPU's memory and spawned an execution thread on it. The goal of this
GDB port is to let the user debug host threads and these GPU threads
simultaneously. Here's a sample session using a GDB with this patch
applied:
$ ./gdb -q -nx --data-directory=data-directory ./simple
Reading symbols from ./simple...
(gdb) break do_an_addition
Function "do_an_addition" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (do_an_addition) pending.
(gdb) r
Starting program: /home/smarchi/build/binutils-gdb-amdgpu/gdb/simple
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff5db7640 (LWP 1082911)]
[New Thread 0x7ffef53ff640 (LWP 1082913)]
[Thread 0x7ffef53ff640 (LWP 1082913) exited]
[New Thread 0x7ffdecb53640 (LWP 1083185)]
[New Thread 0x7ffff54bf640 (LWP 1083186)]
[Thread 0x7ffdecb53640 (LWP 1083185) exited]
[Switching to AMDGPU Wave 2:2:1:1 (0,0,0)/0]
Thread 6 hit Breakpoint 1, do_an_addition (a=<error reading variable: DWARF-2 expression error: `DW_OP_regx' operations must be used either alone or in conjunction with DW_OP_piece or DW_OP_bit_piece.>,
b=<error reading variable: DWARF-2 expression error: `DW_OP_regx' operations must be used either alone or in conjunction with DW_OP_piece or DW_OP_bit_piece.>,
out=<error reading variable: DWARF-2 expression error: `DW_OP_regx' operations must be used either alone or in conjunction with DW_OP_piece or DW_OP_bit_piece.>) at simple.cpp:24
24 *out = a + b;
(gdb) info inferiors
Num Description Connection Executable
* 1 process 1082907 1 (native) /home/smarchi/build/binutils-gdb-amdgpu/gdb/simple
(gdb) info threads
Id Target Id Frame
1 Thread 0x7ffff5dc9240 (LWP 1082907) "simple" 0x00007ffff5e9410b in ?? () from /opt/rocm-5.4.0/lib/libhsa-runtime64.so.1
2 Thread 0x7ffff5db7640 (LWP 1082911) "simple" __GI___ioctl (fd=3, request=3222817548) at ../sysdeps/unix/sysv/linux/ioctl.c:36
5 Thread 0x7ffff54bf640 (LWP 1083186) "simple" __GI___ioctl (fd=3, request=3222817548) at ../sysdeps/unix/sysv/linux/ioctl.c:36
* 6 AMDGPU Wave 2:2:1:1 (0,0,0)/0 do_an_addition (
a=<error reading variable: DWARF-2 expression error: `DW_OP_regx' operations must be used either alone or in conjunction with DW_OP_piece or DW_OP_bit_piece.>,
b=<error reading variable: DWARF-2 expression error: `DW_OP_regx' operations must be used either alone or in conjunction with DW_OP_piece or DW_OP_bit_piece.>,
out=<error reading variable: DWARF-2 expression error: `DW_OP_regx' operations must be used either alone or in conjunction with DW_OP_piece or DW_OP_bit_piece.>) at simple.cpp:24
(gdb) bt
Python Exception <class 'gdb.error'>: Unhandled dwarf expression opcode 0xe1
#0 do_an_addition (a=<error reading variable: DWARF-2 expression error: `DW_OP_regx' operations must be used either alone or in conjunction with DW_OP_piece or DW_OP_bit_piece.>,
b=<error reading variable: DWARF-2 expression error: `DW_OP_regx' operations must be used either alone or in conjunction with DW_OP_piece or DW_OP_bit_piece.>,
out=<error reading variable: DWARF-2 expression error: `DW_OP_regx' operations must be used either alone or in conjunction with DW_OP_piece or DW_OP_bit_piece.>) at simple.cpp:24
(gdb) continue
Continuing.
result is 3
warning: Temporarily disabling breakpoints for unloaded shared library "file:///home/smarchi/build/binutils-gdb-amdgpu/gdb/simple#offset=8192&size=67208"
[Thread 0x7ffff54bf640 (LWP 1083186) exited]
[Thread 0x7ffff5db7640 (LWP 1082911) exited]
[Inferior 1 (process 1082907) exited normally]
One thing to notice is the host and GPU threads appearing under
the same inferior. This is a design goal for us, as programmers tend to
think of the threads running on the GPU as part of the same program as
the host threads, so showing them in the same inferior in GDB seems
natural. Also, the host and GPU threads share a global memory space,
which fits the inferior model.
Another thing to notice is the error messages when trying to read
variables or printing a backtrace. This is expected for the moment,
since the AMD GPU compiler produces some DWARF that uses some
non-standard extensions:
https://llvm.org/docs/AMDGPUDwarfExtensionsForHeterogeneousDebugging.html
There were already some patches posted by Zoran Zaric earlier to make
GDB support these extensions:
https://inbox.sourceware.org/gdb-patches/20211105113849.118800-1-zoran.zaric@amd.com/
We think it's better to get the basic support for AMD GPU in first,
which will then give a better justification for GDB to support these
extensions.
GPU threads are named `AMDGPU Wave`: a wave is essentially a hardware
thread using the SIMT (single-instruction, multiple-threads) [3]
execution model.
GDB uses the amd-dbgapi library [4], included in the ROCm platform, for
a few things related to AMD GPU threads debugging. Different components
talk to the library, as show on the following diagram:
+---------------------------+ +-------------+ +------------------+
| GDB | amd-dbgapi target | <-> | AMD | | Linux kernel |
| +-------------------+ | Debugger | +--------+ |
| | amdgcn gdbarch | <-> | API | <=> | AMDGPU | |
| +-------------------+ | | | driver | |
| | solib-rocm | <-> | (dbgapi.so) | +--------+---------+
+---------------------------+ +-------------+
- The amd-dbgapi target is a target_ops implementation used to control
execution of GPU threads. While the debugging of host threads works
by using the ptrace / wait Linux kernel interface (as usual), control
of GPU threads is done through a special interface (dubbed `kfd`)
exposed by the `amdgpu` Linux kernel module. GDB doesn't interact
directly with `kfd`, but instead goes through the amd-dbgapi library
(AMD Debugger API on the diagram).
Since it provides execution control, the amd-dbgapi target should
normally be a process_stratum_target, not just a target_ops. More
on that later.
- The amdgcn gdbarch (describing the hardware architecture of the GPU
execution units) offloads some requests to the amd-dbgapi library,
so that knowledge about the various architectures doesn't need to be
duplicated and baked in GDB. This is for example for things like
the list of registers.
- The solib-rocm component is an solib provider that fetches the list of
code objects loaded on the device from the amd-dbgapi library, and
makes GDB read their symbols. This is very similar to other solib
providers that handle shared libraries, except that here the shared
libraries are the pieces of code loaded on the device.
Given that Linux host threads are managed by the linux-nat target, and
the GPU threads are managed by the amd-dbgapi target, having all threads
appear in the same inferior requires the two targets to be in that
inferior's target stack. However, there can only be one
process_stratum_target in a given target stack, since there can be only
one target per slot. To achieve it, we therefore resort the hack^W
solution of placing the amd-dbgapi target in the arch_stratum slot of
the target stack, on top of the linux-nat target. Doing so allows the
amd-dbgapi target to intercept target calls and handle them if they
concern GPU threads, and offload to beneath otherwise. See
amd_dbgapi_target::fetch_registers for a simple example:
void
amd_dbgapi_target::fetch_registers (struct regcache *regcache, int regno)
{
if (!ptid_is_gpu (regcache->ptid ()))
{
beneath ()->fetch_registers (regcache, regno);
return;
}
// handle it
}
ptids of GPU threads are crafted with the following pattern:
(pid, 1, wave id)
Where pid is the inferior's pid and "wave id" is the wave handle handed
to us by the amd-dbgapi library (in practice, a monotonically
incrementing integer). The idea is that on Linux systems, the
combination (pid != 1, lwp == 1) is not possible. lwp == 1 would always
belong to the init process, which would also have pid == 1 (and it's
improbable for the init process to offload work to the GPU and much less
for the user to debug it). We can therefore differentiate GPU and
non-GPU ptids this way. See ptid_is_gpu for more details.
Note that we believe that this scheme could break down in the context of
containers, where the initial process executed in a container has pid 1
(in its own pid namespace). For instance, if you were to execute a ROCm
program in a container, then spawn a GDB in that container and attach to
the process, it will likely not work. This is a known limitation. A
workaround for this is to have a dummy process (like a shell) fork and
execute the program of interest.
The amd-dbgapi target watches native inferiors, and "attaches" to them
using amd_dbgapi_process_attach, which gives it a notifier fd that is
registered in the event loop (see enable_amd_dbgapi). Note that this
isn't the same "attach" as in PTRACE_ATTACH, but being ptrace-attached
is a precondition for amd_dbgapi_process_attach to work. When the
debugged process enables the ROCm runtime, the amd-dbgapi target gets
notified through that fd, and pushes itself on the target stack of the
inferior. The amd-dbgapi target is then able to intercept target_ops
calls. If the debugged process disables the ROCm runtime, the
amd-dbgapi target unpushes itself from the target stack.
This way, the amd-dbgapi target's footprint stays minimal when debugging
a process that doesn't use the AMD ROCm platform, it does not intercept
target calls.
The amd-dbgapi library is found using pkg-config. Since enabling
support for the amdgpu architecture (amdgpu-tdep.c) depends on the
amd-dbgapi library being present, we have the following logic for
the interaction with --target and --enable-targets:
- if the user explicitly asks for amdgcn support with
--target=amdgcn-*-* or --enable-targets=amdgcn-*-*, we probe for
the amd-dbgapi and fail if not found
- if the user uses --enable-targets=all, we probe for amd-dbgapi,
enable amdgcn support if found, disable amdgcn support if not found
- if the user uses --enable-targets=all and --with-amd-dbgapi=yes,
we probe for amd-dbgapi, enable amdgcn if found and fail if not found
- if the user uses --enable-targets=all and --with-amd-dbgapi=no,
we do not probe for amd-dbgapi, disable amdgcn support
- otherwise, amd-dbgapi is not probed for and support for amdgcn is not
enabled
Finally, a simple test is included. It only tests hitting a breakpoint
in device code and resuming execution, pretty much like the example
shown above.
[1] https://docs.amd.com/category/ROCm_v5.4
[2] https://docs.amd.com/bundle/HIP-Programming-Guide-v5.4
[3] https://en.wikipedia.org/wiki/Single_instruction,_multiple_threads
[4] https://docs.amd.com/bundle/ROCDebugger-API-Guide-v5.4
Change-Id: I591edca98b8927b1e49e4b0abe4e304765fed9ee
Co-Authored-By: Zoran Zaric <zoran.zaric@amd.com>
Co-Authored-By: Laurent Morichetti <laurent.morichetti@amd.com>
Co-Authored-By: Tony Tye <Tony.Tye@amd.com>
Co-Authored-By: Lancelot SIX <lancelot.six@amd.com>
Co-Authored-By: Pedro Alves <pedro@palves.net>
|
|
In the ROCm port, we need to access the underlying stream of a
gdb_printing_disassembler, so make it public. The reason we need to
access it is to know whether it supports style escape code. We then
pass that information to a temporary string_file we use while
symbolizing addresses.
Change-Id: Ib95755a4a45b8f6478787993e9f904df60dd8dc1
Approved-By: Andrew Burgess <aburgess@redhat.com>
|
|
In ROCm-GDB, we install an solib provider for the GPU code objects on
top of the svr4 provider for the host, in order to add solibs
representing the GPU code objects to the solib list containing the host
process' shared libraries. We override the target_so_ops::handle_event
function pointer with our own, in which we call svr4_so_ops.handle_event
(which contains svr4_handle_solib_event) manually. When the host
(un)loads a library, the ROCm part of handle_event is a no-op. When the
GPU (un)loads a code object, we want the host side (svr4) to be a no-op.
The problem is that when handle_event is called because of a GPU event,
svr4_handle_solib_event gets called while not stopped at an svr4
probe. It then assumes this means there's a problem with the probes
interface and disables it through the following sequence of events:
- solib_event_probe_at return nullptr
- svr4_handle_solib_event returns early
- the make_scope_exit callback calls disable_probes_interface
We could fix that by making the ROCm handle_event callback check if an
svr4 probe is that the stop address, and only call
svr4_so_ops.handle_event if so. However, it doesn't feel right to
include some svr4 implementation detail in the ROCm event handler.
Instead, this patch changes svr4_handle_solib_event to not assume it is
an error if called while not at an svr4 probe location, and therefore
not disable the probes interface. That just means moving the
make_scope_exit call below where we lookup the probe by pc.
Change-Id: Ie8ddf5beffa2e92b8ebfdd016454546252519244
Co-Authored-By: Lancelot SIX <lancelot.six@amd.com>
|
|
Add a gdbarch_up unique pointer type, that calls gdbarch_free on
deletion. This is used in the ROCm support patch at the end of this
series.
Change-Id: I4b808892d35d69a590ce83180f41afd91705b2c8
Approved-By: Andrew Burgess <aburgess@redhat.com>
|
|
Add an observable notified in target_detach just before calling the
detach method on the inferior's target stack. This allows observer to
do some work on the inferior while it's still ptrace-attached, in the
case of a native Linux inferior. Specifically, the amd-dbgapi target
will need it in order to call amd_dbgapi_process_detach before the
process gets ptrace-detached.
Change-Id: I28b6065e251012a4c2db8a600fe13ba31671e3c9
Approved-By: Andrew Burgess <aburgess@redhat.com>
|
|
A following patch will want to declare variables of the same type as
some ptid_t components. To make that easy (and avoid harcoding those
types everywhere), define some type definitions in the ptid_t struct for
each of them. Use them throughout ptid.h.
I initially used pid_t, lwp_t and tid_t, but there is the risk of some
system defining the pid_t type using a macro instead of a typedef, which
would break things. So, use the _type suffix instead.
Change-Id: I820b0bea9dafcb4914f1c9ba4bb96b5c666c8dec
Approved-By: Andrew Burgess <aburgess@redhat.com>
|
|
A following patch will want to install a breakpoint and then keep a
non-owning reference to it. Make install_breakpoint return a non-owning
reference, to make that easy.
Co-Authored-By: Simon Marchi <simon.marchi@efficios.com>
Change-Id: I2e8106a784021ff276ce251e24708cbdccc2d479
Approved-By: Andrew Burgess <aburgess@redhat.com>
|
|
In the ROCm GDB port, there are some amdgcn architectures known by BFD
that we don't actually support in GDB. We don't want
gdbarch_printable_names to return these architectures.
gdbarch_printable_names is used for a few things:
- completion of the "set architecture" command
- the gdb.architecture_names function in Python
- foreach-arch selftests
Add an optional callback to gdbarch_register that is a predicate
indicating whether the gdbarch supports the given bfd_arch_info. by
default, it is nullptr, meaning that the gdbarch accepts all "mach"s for
that architecture known by BFD.
Change-Id: I712f94351b0b34ed1f42e5cf7fc7ba051315d860
Co-Authored-By: Simon Marchi <simon.marchi@efficios.com>
Approved-By: Andrew Burgess <aburgess@redhat.com>
|