[RFA] i386 segment base support

Hui Zhu
2010-05-20T07:34:53Z

Hi guys,

I update the old patch that I post to support segment base value.

Now, it will not show when info reg.
For example:
(gdb) info reg
eax 0x1 1
ecx 0xbffff510 -1073744624
edx 0xbffff530 -1073744592
ebx 0xb7fb5ff4 -1208262668
esp 0xbffff4a0 0xbffff4a0
ebp 0xbffff4f8 0xbffff4f8
esi 0xb7ffece0 -1207964448
edi 0x0 0
eip 0x8048388 0x8048388 <main+20>
eflags 0x286 [ PF SF IF ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb) info reg cs_base
cs_base 0x0 0
(gdb) info reg gs_base
gs_base 0xb7e6a6b0 -1209620816

Please help me review it.

Thanks,
Hui

2010-05-20 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.

* amd64-linux-nat.c (user-regs.h): New include.
(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 (user-regs.h): New include.
(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.

* i386-linux-tdep.c (user-regs.h): New include.
(i386_linux_register_reggroup_p): Add check for segment base
registers.

---
amd64-linux-nat.c | 40 ++++++++++++++++++++++++++++++++++++++++
features/i386/32bit-linux.xml | 6 ++++++
features/i386/i386-linux.c | 6 ++++++
i386-linux-nat.c | 40 ++++++++++++++++++++++++++++++++++++++++
i386-linux-tdep.c | 8 ++++++++
5 files changed, 100 insertions(+)

--- a/amd64-linux-nat.c
+++ b/amd64-linux-nat.c
@@ -26,6 +26,7 @@
#include "regset.h"
#include "linux-nat.h"
#include "amd64-linux-tdep.h"
+#include "user-regs.h"

#include "gdb_assert.h"
#include "gdb_string.h"
@@ -146,12 +147,19 @@ 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)
{
struct gdbarch *gdbarch = get_regcache_arch (regcache);
int tid;
+ int cs_base;

/* GNU/Linux LWP ID's are process ID's. */
tid = TIDGET (inferior_ptid);
@@ -195,6 +203,38 @@ amd64_linux_fetch_inferior_registers (st
amd64_supply_fxsave (regcache, -1, &fpregs);
}
}
+
+ /* Get the base of segment registers. */
+ cs_base = user_reg_map_name_to_regnum (get_regcache_arch (regcache),
+ "cs_base", 7);
+ if (gdbarch_ptr_bit (gdbarch) == 32
+ && regnum >= cs_base && regnum <= cs_base + 5)
+ {
+ ULONGEST idx;
+ int base;
+
+ /* Get the idx. */
+ base = user_reg_map_name_to_regnum (get_regcache_arch (regcache),
+ "cs", 2);
+ regcache_raw_read_unsigned (regcache,
+ regnum - cs_base + base,
+ &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"/>
+ <reg name="ss_base" bitsize="32" type="int"/>
+ <reg name="ds_base" bitsize="32" type="int"/>
+ <reg name="es_base" bitsize="32" type="int"/>
+ <reg name="fs_base" bitsize="32" type="int"/>
+ <reg name="gs_base" bitsize="32" type="int"/>
</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
@@ -26,6 +26,7 @@
#include "regset.h"
#include "target.h"
#include "linux-nat.h"
+#include "user-regs.h"

#include "gdb_assert.h"
#include "gdb_string.h"
@@ -506,11 +507,19 @@ 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)
{
int tid;
+ int cs_base;

/* Use the old method of peeking around in `struct user' if the
GETREGS request isn't available. */
@@ -580,6 +589,37 @@ i386_linux_fetch_inferior_registers (str
return;
}

+ /* Get the base of segment registers. */
+ cs_base = user_reg_map_name_to_regnum (get_regcache_arch (regcache),
+ "cs_base", 7);
+ if (regno >= cs_base && regno <= cs_base + 5)
+ {
+ ULONGEST idx;
+ int base;
+
+ /* Get the idx. */
+ base = user_reg_map_name_to_regnum (get_regcache_arch (regcache),
+ "cs", 2);
+ regcache_raw_read_unsigned (regcache,
+ regno - cs_base + base,
+ &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-linux-tdep.c
+++ b/i386-linux-tdep.c
@@ -42,6 +42,8 @@
#include "i387-tdep.h"
#include "i386-xstate.h"

+#include "user-regs.h"
+
/* The syscall's XML filename for i386. */
#define XML_SYSCALL_FILENAME_I386 "syscalls/i386-linux.xml"

@@ -81,6 +83,12 @@ static int
i386_linux_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
struct reggroup *group)
{
+ int cs_base = user_reg_map_name_to_regnum (gdbarch,
+ "cs_base", 7);
+
+ if (regnum >= cs_base && regnum <= cs_base + 5)
+ return (group == all_reggroup);
+
if (regnum == I386_LINUX_ORIG_EAX_REGNUM)
return (group == system_reggroup
|| group == save_reggroup