--- 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 @@ + + + + + + --- 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