Re: [RFA 3/5] Prec: x86 segment register support: target

Hui Zhu
2010-03-22T14:03:25Z

[-- Attachment #1: Type: text/plain, Size: 2409 bytes --]

Thanks Michael and Daniel.

I make a patch to add base of segments registers to x86-32:
(gdb) info reg
eax 0xffffd514 -10988
ecx 0x1eda96c5 517641925
edx 0x1 1
ebx 0xf7fb1ff4 -134537228
esp 0xffffd488 0xffffd488
ebp 0xffffd488 0xffffd488
esi 0x8048510 134513936
edi 0x80483d0 134513616
eip 0x8048487 0x8048487 <main+3>
eflags 0x246 [ PF ZF IF ]
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x0 0
gs 0x63 99
cs_base 0x0 0
ss_base 0x0 0
ds_base 0x0 0
es_base 0x0 0
fs_base 0x0 0
gs_base 0xf7e528d0 -135976752

I try it in x86-32 pc and 32bit code in x86-64. It works OK.

Please help me review it.

Best regards,
Hui

2010-03-22 Hui Zhu <teawater@gmail.com>

* features/i386/32bit-linux.xml (org.gnu.gdb.i386.linux): Add
cs_base, ss_base, ds_base, es_base, fs_base and gs_base.
* i386-tdep.h (i386_segment_base_regnum): New enum.
* amd64-linux-nat.c (GDT_ENTRY_TLS_MIN,
GDT_ENTRY_TLS_MAX): New marco.
(ps_get_thread_area): New extern.
(amd64_linux_fetch_inferior_registers): Add
code to get 32 bits segment registers base.
* i386-linux-nat.c (GDT_ENTRY_TLS_ENTRIES,
GDT_ENTRY_TLS_MIN,
GDT_ENTRY_TLS_MAX): New marco.
(ps_get_thread_area): New extern.
(i386_linux_fetch_inferior_registers): Add
code to get segment registers base.

On Wed, Mar 17, 2010 at 04:04, Daniel Jacobowitz <dan@codesourcery.com> wrote:
> On Tue, Mar 16, 2010 at 11:12:49AM -0700, Michael Snyder wrote:
>> However, isn't target.c the wrong place for this function?
>> Wouldn't it belong better in the gdbarch?  It is architecture-
>> specific, if I understand correctly.
>>
>> That is, this will be the same between i386-ptrace and i386-remote,
>> but different between i386-remote and (say) mips-remote.
>
> IMO, these should simply be added as new registers.  Since the name
> $gs is already taken, why not add a $gs_base register?
>
> H.J. Lu has recently converted the i386 target to use target
> descriptions; it should be easy to add new registers now.
> They could go in 32bit-linux.xml or in some other file that could be
> shared among OS's.  H.J. may have some more ideas.
>
> --
> Daniel Jacobowitz
> CodeSourcery
>

[-- Attachment #2: add-segment-base.txt --]
[-- Type: text/plain, Size: 5295 bytes --]

---
amd64-linux-nat.c | 33 +++++++++++++++++++++++++++++++++
features/i386/32bit-linux.xml | 6 ++++++
features/i386/i386-linux.c | 6 ++++++
i386-linux-nat.c | 34 ++++++++++++++++++++++++++++++++++
i386-tdep.h | 10 ++++++++++
5 files changed, 89 insertions(+)

--- a/amd64-linux-nat.c
+++ b/amd64-linux-nat.c
@@ -155,6 +155,12 @@ fill_fpregset (const struct regcache *re
this for all registers (including the floating point and SSE
registers). */

+#define GDT_ENTRY_TLS_MIN 12
+#define GDT_ENTRY_TLS_MAX 14
+
+extern ps_err_e ps_get_thread_area (const struct ps_prochandle *ph,
+ lwpid_t lwpid, int idx, void **base);
+
static void
amd64_linux_fetch_inferior_registers (struct target_ops *ops,
struct regcache *regcache, int regnum)
@@ -188,6 +194,33 @@ amd64_linux_fetch_inferior_registers (st

amd64_supply_fxsave (regcache, -1, &fpregs);
}
+
+ if (gdbarch_ptr_bit (gdbarch) == 32
+ && regnum >= I386_CS_BASE_REGNUM && regnum <= I386_GS_BASE_REGNUM)
+ {
+ ULONGEST idx;
+ int base;
+
+ /* Get the idx. */
+ regcache_raw_read_unsigned (regcache,
+ regnum - I386_CS_BASE_REGNUM + I386_CS_REGNUM,
+ &idx);
+ idx >>= 3;
+
+ /* The base will be 0 if the idx is not TLS. */
+ if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
+ {
+ regcache_raw_supply (regcache, regnum, NULL);
+ return;
+ }
+
+ /* Get the base. */
+ if (ps_get_thread_area (NULL, tid, idx, (void *)&base) == PS_ERR)
+ perror_with_name (_("Couldn't get registers"));
+
+ regcache_raw_supply (regcache, regnum, &base);
+ return;
+ }
}

/* Store register REGNUM back into the child process. If REGNUM is
--- a/features/i386/32bit-linux.xml
+++ b/features/i386/32bit-linux.xml
@@ -8,4 +8,10 @@

<feature name="org.gnu.gdb.i386.linux">
<reg name="orig_eax" bitsize="32" type="int" regnum="41"/>
+ <reg name="cs_base" bitsize="32" type="int" regnum="42"/>
+ <reg name="ss_base" bitsize="32" type="int" regnum="43"/>
+ <reg name="ds_base" bitsize="32" type="int" regnum="44"/>
+ <reg name="es_base" bitsize="32" type="int" regnum="45"/>
+ <reg name="fs_base" bitsize="32" type="int" regnum="46"/>
+ <reg name="gs_base" bitsize="32" type="int" regnum="47"/>
</feature>
--- a/features/i386/i386-linux.c
+++ b/features/i386/i386-linux.c
@@ -71,6 +71,12 @@ initialize_tdesc_i386_linux (void)

feature = tdesc_create_feature (result, "org.gnu.gdb.i386.linux");
tdesc_create_reg (feature, "orig_eax", 41, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "cs_base", 42, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "ss_base", 43, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "ds_base", 44, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "es_base", 45, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "fs_base", 46, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "gs_base", 47, 1, NULL, 32, "int");

feature = tdesc_create_feature (result, "org.gnu.gdb.i386.sse");
field_type = tdesc_named_type (feature, "ieee_single");
--- a/i386-linux-nat.c
+++ b/i386-linux-nat.c
@@ -450,6 +450,13 @@ static int store_fpxregs (const struct r
this for all registers (including the floating point and SSE
registers). */

+#define GDT_ENTRY_TLS_ENTRIES 3
+#define GDT_ENTRY_TLS_MIN 6
+#define GDT_ENTRY_TLS_MAX (GDT_ENTRY_TLS_MIN + GDT_ENTRY_TLS_ENTRIES - 1)
+
+extern ps_err_e ps_get_thread_area (const struct ps_prochandle *ph,
+ lwpid_t lwpid, int idx, void **base);
+
static void
i386_linux_fetch_inferior_registers (struct target_ops *ops,
struct regcache *regcache, int regno)
@@ -516,6 +523,33 @@ i386_linux_fetch_inferior_registers (str
return;
}

+ /* Get the base of segment registers. */
+ if (regno >= I386_CS_BASE_REGNUM && regno <= I386_GS_BASE_REGNUM)
+ {
+ ULONGEST idx;
+ int base;
+
+ /* Get the idx. */
+ regcache_raw_read_unsigned (regcache,
+ regno - I386_CS_BASE_REGNUM + I386_CS_REGNUM,
+ &idx);
+ idx >>= 3;
+
+ /* The base will be 0 if the idx is not TLS. */
+ if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
+ {
+ regcache_raw_supply (regcache, regno, NULL);
+ return;
+ }
+
+ /* Get the base. */
+ if (ps_get_thread_area (NULL, tid, idx, (void *)&base) == PS_ERR)
+ perror_with_name (_("Couldn't get registers"));
+
+ regcache_raw_supply (regcache, regno, &base);
+ return;
+ }
+
internal_error (__FILE__, __LINE__,
_("Got request for bad register number %d."), regno);
}
--- a/i386-tdep.h
+++ b/i386-tdep.h
@@ -231,6 +231,16 @@ enum i386_regnum
I386_MXCSR_REGNUM = 40 /* %mxcsr */
};

+enum i386_segment_base_regnum
+{
+ I386_CS_BASE_REGNUM = 42, /* %cs_base */
+ I386_SS_BASE_REGNUM, /* %ss_base */
+ I386_DS_BASE_REGNUM, /* %ds_base */
+ I386_ES_BASE_REGNUM, /* %es_base */
+ I386_FS_BASE_REGNUM, /* %fs_base */
+ I386_GS_BASE_REGNUM, /* %gs_base */
+};
+
/* Register numbers of RECORD_REGMAP. */

enum record_i386_regnum