diff options
author | Maciej W. Rozycki <macro@mips.com> | 2018-05-16 20:43:30 +0100 |
---|---|---|
committer | Maciej W. Rozycki <macro@mips.com> | 2018-05-16 20:43:30 +0100 |
commit | 1d7611244c140a1a08f3365cd5881120eba7749d (patch) | |
tree | a732ed2ed889e38324c0d9825cbc5c9a8e96b3e8 /gdb/linux-nat-trad.c | |
parent | 49d519ec2fe80b48f404c0209b41bf8fee47cf39 (diff) | |
download | binutils-gdb-1d7611244c140a1a08f3365cd5881120eba7749d.tar.gz |
PR gdb/22286: linux-nat-trad: Support arbitrary register widths
Update `fetch_register' and `store_register' code to support arbitrary
register widths rather than only ones that are a multiply of the size of
the `ptrace' data type used with PTRACE_PEEKUSR and PTRACE_POKEUSR
requests to access registers. Remove associated assertions, correcting
an issue with accessing the DSPControl (`$dspctl') register on n64 MIPS
native targets:
(gdb) print /x $dspctl
.../gdb/linux-nat-trad.c:50: internal-error: void linux_nat_trad_target::fetch_register(regcache*, int): Assertion `(size % sizeof (PTRACE_TYPE_RET)) == 0' failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.
Quit this debugging session? (y or n) n
This is a bug, please report it. For instructions, see:
<http://www.gnu.org/software/gdb/bugs/>.
.../gdb/linux-nat-trad.c:50: internal-error: void linux_nat_trad_target::fetch_register(regcache*, int): Assertion `(size % sizeof (PTRACE_TYPE_RET)) == 0' failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.
Create a core file of GDB? (y or n) n
Command aborted.
(gdb)
All registers are now reported correctly and their architectural
hardware widths respected:
(gdb) print /x $dspctl
$1 = 0x55aa33cc
(gdb) info registers
zero at v0 v1
R0 0000000000000000 0000000000000001 000000fff7ffeb20 0000000000000000
a0 a1 a2 a3
R4 0000000000000001 000000ffffffeaf8 000000ffffffeb08 0000000000000000
a4 a5 a6 a7
R8 000000fff7ee3800 000000fff7ede8f0 000000ffffffeaf0 2f2f2f2f2f2f2f2f
t0 t1 t2 t3
R12 0000000000000437 0000000000000002 000000fff7ffd000 0000000120000ad0
s0 s1 s2 s3
R16 000000fff7ee2068 0000000120000e60 0000000000000000 0000000000000000
s4 s5 s6 s7
R20 0000000000521ec8 0000000000522608 0000000000000000 0000000000000000
t8 t9 k0 k1
R24 0000000000000000 0000000120000d9c 0000000000000000 0000000000000000
gp sp s8 ra
R28 0000000120019030 000000ffffffe990 000000ffffffe990 000000fff7d5b88c
status lo hi badvaddr
0000000000109cf3 0000000000005ea5 0000000000000211 000000fff7fc6fe0
cause pc
0000000000800024 0000000120000dbc
fcsr fir hi1 lo1
00000000 00f30000 0000000000000000 0101010101010101
hi2 lo2 hi3 lo3
0202020202020202 0303030303030303 0404040404040404 0505050505050505
dspctl restart
55aa33cc 0000000000000000
(gdb)
NB due to the lack of access to 64-bit DSP hardware all DSP register
values in the dumps are artificial and have been created with a debug
change applied to the kernel handler of the `ptrace' syscall.
The use of `store_unsigned_integer' and `extract_unsigned_integer'
unconditionally in all cases rather than when actual data occupies a
part of the data quantity exchanged with `ptrace' makes code perhaps
marginally slower, however I think avoiding it is not worth code
obfuscation it would cause. If this turns out unfounded, then there
should be no problem with optimizing this code later.
gdb/
PR gdb/22286
* linux-nat-trad.c (linux_nat_trad_target::fetch_register):
Also handle registers whose width is not a multiple of
PTRACE_TYPE_RET.
(linux_nat_trad_target::store_register): Likewise.
Diffstat (limited to 'gdb/linux-nat-trad.c')
-rw-r--r-- | gdb/linux-nat-trad.c | 28 |
1 files changed, 18 insertions, 10 deletions
diff --git a/gdb/linux-nat-trad.c b/gdb/linux-nat-trad.c index 066d15a352b..ce6788c0bc1 100644 --- a/gdb/linux-nat-trad.c +++ b/gdb/linux-nat-trad.c @@ -29,9 +29,10 @@ void linux_nat_trad_target::fetch_register (struct regcache *regcache, int regnum) { struct gdbarch *gdbarch = regcache->arch (); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); CORE_ADDR addr; + gdb_byte *buf; size_t size; - PTRACE_TYPE_RET *buf; pid_t pid; int i; @@ -47,18 +48,21 @@ linux_nat_trad_target::fetch_register (struct regcache *regcache, int regnum) pid = get_ptrace_pid (regcache_get_ptid (regcache)); size = register_size (gdbarch, regnum); - gdb_assert ((size % sizeof (PTRACE_TYPE_RET)) == 0); - buf = (PTRACE_TYPE_RET *) alloca (size); + buf = (gdb_byte *) alloca (size); /* Read the register contents from the inferior a chunk at a time. */ - for (i = 0; i < size / sizeof (PTRACE_TYPE_RET); i++) + for (i = 0; i < size; i += sizeof (PTRACE_TYPE_RET)) { + size_t chunk = std::min (sizeof (PTRACE_TYPE_RET), size - i); + PTRACE_TYPE_RET val; + errno = 0; - buf[i] = ptrace (PT_READ_U, pid, (PTRACE_TYPE_ARG3)(uintptr_t)addr, 0); + val = ptrace (PT_READ_U, pid, (PTRACE_TYPE_ARG3) (uintptr_t) addr, 0); if (errno != 0) error (_("Couldn't read register %s (#%d): %s."), gdbarch_register_name (gdbarch, regnum), regnum, safe_strerror (errno)); + store_unsigned_integer (buf + i, chunk, byte_order, val); addr += sizeof (PTRACE_TYPE_RET); } @@ -87,9 +91,10 @@ linux_nat_trad_target::store_register (const struct regcache *regcache, int regnum) { struct gdbarch *gdbarch = regcache->arch (); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); CORE_ADDR addr; size_t size; - PTRACE_TYPE_RET *buf; + gdb_byte *buf; pid_t pid; int i; @@ -102,15 +107,18 @@ linux_nat_trad_target::store_register (const struct regcache *regcache, pid = get_ptrace_pid (regcache_get_ptid (regcache)); size = register_size (gdbarch, regnum); - gdb_assert ((size % sizeof (PTRACE_TYPE_RET)) == 0); - buf = (PTRACE_TYPE_RET *) alloca (size); + buf = (gdb_byte *) alloca (size); /* Write the register contents into the inferior a chunk at a time. */ regcache_raw_collect (regcache, regnum, buf); - for (i = 0; i < size / sizeof (PTRACE_TYPE_RET); i++) + for (i = 0; i < size; i += sizeof (PTRACE_TYPE_RET)) { + size_t chunk = std::min (sizeof (PTRACE_TYPE_RET), size - i); + PTRACE_TYPE_RET val; + + val = extract_unsigned_integer (buf + i, chunk, byte_order); errno = 0; - ptrace (PT_WRITE_U, pid, (PTRACE_TYPE_ARG3)(uintptr_t)addr, buf[i]); + ptrace (PT_WRITE_U, pid, (PTRACE_TYPE_ARG3) (uintptr_t) addr, val); if (errno != 0) error (_("Couldn't write register %s (#%d): %s."), gdbarch_register_name (gdbarch, regnum), |