diff options
author | Tom Tromey <tromey@adacore.com> | 2024-01-18 11:08:45 -0700 |
---|---|---|
committer | Tom Tromey <tromey@adacore.com> | 2024-01-30 10:18:38 -0700 |
commit | a197d5f7eb27e99c27577558df4274692cafe37e (patch) | |
tree | bcf0a11b8ac50b0075e4b8e6eaeb0bae3e5fdf1b /gdb | |
parent | b960445a45981873c5b1718824ea9d3b5749433a (diff) | |
download | gdb-a197d5f7eb27e99c27577558df4274692cafe37e.zip gdb-a197d5f7eb27e99c27577558df4274692cafe37e.tar.gz gdb-a197d5f7eb27e99c27577558df4274692cafe37e.tar.bz2 |
Really fix Windows gdbserver segment registers
My earlier attempt to mask the segment registers in gdbserver for
Windows introduced some bugs. That patch is here:
https://sourceware.org/pipermail/gdb-patches/2023-December/205306.html
The problem turned out to be that these fields in the Windows
'CONTEXT' type are just 16 bits, so while masking the values on read
is fine, writing the truncated values back then causes zeros to be
written to some subsequent field.
This patch cleans this up by arranging never to write too much data to
a field.
I also noticed that two register numbers here were never updated for
the 64-bit port. This patch fixes this as well, and renames the "FCS"
register to follow gdb.
Finally, this patch applies the same treatment to windows-nat.c.
Reviewed-by: John Baldwin <jhb@FreeBSD.org>
Diffstat (limited to 'gdb')
-rw-r--r-- | gdb/windows-nat.c | 44 |
1 files changed, 31 insertions, 13 deletions
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c index 28f142c..6fdd1f3 100644 --- a/gdb/windows-nat.c +++ b/gdb/windows-nat.c @@ -662,23 +662,19 @@ windows_fetch_one_register (struct regcache *regcache, gdb_assert (gdbarch_pc_regnum (gdbarch) >= 0); gdb_assert (!gdbarch_write_pc_p (gdbarch)); - if (r == I387_FISEG_REGNUM (tdep)) + /* GDB treats some registers as 32-bit, where they are in fact only + 16 bits long. These cases must be handled specially to avoid + reading extraneous bits from the context. */ + if (r == I387_FISEG_REGNUM (tdep) || windows_process.segment_register_p (r)) { - long l = *((long *) context_offset) & 0xffff; - regcache->raw_supply (r, (char *) &l); + gdb_byte bytes[4] = {}; + memcpy (bytes, context_offset, 2); + regcache->raw_supply (r, bytes); } else if (r == I387_FOP_REGNUM (tdep)) { long l = (*((long *) context_offset) >> 16) & ((1 << 11) - 1); - regcache->raw_supply (r, (char *) &l); - } - else if (windows_process.segment_register_p (r)) - { - /* GDB treats segment registers as 32bit registers, but they are - in fact only 16 bits long. Make sure we do not read extra - bits from our source buffer. */ - long l = *((long *) context_offset) & 0xffff; - regcache->raw_supply (r, (char *) &l); + regcache->raw_supply (r, &l); } else { @@ -799,7 +795,29 @@ windows_store_one_register (const struct regcache *regcache, context_ptr = (char *) &th->wow64_context; #endif - regcache->raw_collect (r, context_ptr + windows_process.mappings[r]); + struct gdbarch *gdbarch = regcache->arch (); + i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch); + + /* GDB treats some registers as 32-bit, where they are in fact only + 16 bits long. These cases must be handled specially to avoid + overwriting other registers in the context. */ + if (r == I387_FISEG_REGNUM (tdep) || windows_process.segment_register_p (r)) + { + gdb_byte bytes[4]; + regcache->raw_collect (r, bytes); + memcpy (context_ptr + windows_process.mappings[r], bytes, 2); + } + else if (r == I387_FOP_REGNUM (tdep)) + { + gdb_byte bytes[4]; + regcache->raw_collect (r, bytes); + /* The value of FOP occupies the top two bytes in the context, + so write the two low-order bytes from the cache into the + appropriate spot. */ + memcpy (context_ptr + windows_process.mappings[r] + 2, bytes, 2); + } + else + regcache->raw_collect (r, context_ptr + windows_process.mappings[r]); } /* Store a new register value into the context of the thread tied to |