16

gdb provides functionality to read or write to a specific linear address, for example:

(gdb) x/1wx 0x080483e4
0x80483e4 <main>:       0x83e58955
(gdb) 

but how do you specify a logical address ? I came accross the following instruction:

   0x0804841a <+6>:     mov    %gs:0x14,%eax

how can i read the memory at "%gs:0x14" in gdb, or translate this logical address to a linear address that i could use in x command ?

note: i know that i could simply read %eax after this instruction, but that is not my concern

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
user368507
  • 1,388
  • 1
  • 13
  • 25
  • possible duplicate of [how to resolve segment:offset adres in GDB](http://stackoverflow.com/questions/4006686/how-to-resolve-segmentoffset-adres-in-gdb). That doesn't have a good answer though. – mtvec Apr 28 '12 at 08:56
  • Arguably a better answer is https://stackoverflow.com/a/6617004/148439 that covers obtaining the base address of the TLS segment behind `%gs:` or `%fs:` (depending on arch) but seemingly not possible in GDB directly. – shuckc Jul 02 '18 at 09:10

3 Answers3

5

how can i read the memory at "%gs:0x14" in gdb

You can't: there is no way for GDB to know how the segment to which %gs refers to has been set up.

or translate this logical address to a linear address that i could use in x command

Again, you can't do this in general. However, you appear to be on 32-bit x86 Linux, and there you can do that -- the %gs is set up to point to the thread descriptor via set_thread_area system call.

You can do catch syscall set_thread_area in GDB, and examine the parameters (each thread will have one such call). The code to actually do that is here. Once you know how %gs has been set up, just add 0x14 to the base_addr, and you are done.

Employed Russian
  • 199,314
  • 34
  • 295
  • 362
  • Nice answer. Unfortunately, my program seems to not call set_thread_area(2). You can see the source code here: http://pastebin.com/us5sbzVg (compilation options provided in source code). – user368507 Apr 29 '12 at 15:06
  • 1
    @user368507 Your program only has one thread. The program *does* call `set_thread_area` (you should be able to see that under `strace`). I was able to catch that call with GDB; not sure why you claim that `set_thread_area` is not called. – Employed Russian Apr 29 '12 at 15:16
  • my mistake. I used another computer after the OP. It was an x86-64... You're anwser works perfectly well on 32bit x86. I guess things are different on x86-64. – user368507 Apr 29 '12 at 15:28
  • 1
    @user368507 "I guess things are different on x86-64" -- indeed they are. There is no `set_thread_area` system call on `x86_64`, and it doesn't use `%gs` to access thread locals. – Employed Russian Apr 29 '12 at 16:38
  • 5
    I don't buy "there is no way for GDB to know how the segment to which `%gs` refers to has been set up". GDB is running in user mode and can't read the GDT/LDT, but it could write machine code for something like `mov %gs:0x14,%eax` into some memory it controls and then jump to it. In that way, it could "read" `%gs:0x14`. – Alex D Mar 25 '15 at 17:29
  • 1
    @AlexD: Or under Linux, could just ask the kernel what the GS base is with `arch_prctl(ARCH_GET_GS)` in the context of the target process. (BTW, modern OSes don't use the GDT/LDT to set FS/GS base, they use the MSRs or even new instructions like `wrfsbase` on CPUs where available). IDK if ptrace has a way for the debugger to just directly query the FS/GS bases; I thought I remembered something about GDB being able to query it somehow but it's not part of `info reg all`. – Peter Cordes Jan 31 '21 at 22:05
  • 2
    @PeterCordes Apparently, `info reg all` doesn't list all registers. The command `maintenance print register-groups` shows which register groups each register belongs to. For me, `fs_base` and `gs_base` belong to the `system` group (as well as `save` and `restore`, but not `all`), so `info reg system` (or `i r sy`) prints them. – user_ Sep 29 '22 at 17:26
4

As answered in Using GDB to read MSRs, this is possible with gdb 8, using the registers $fs_base and $gs_base.

ObsequiousNewt
  • 260
  • 2
  • 5
1

I think the easiest way to do this is to read the content of EAX register as you can see the value of %gs:0x14 is moved to EAX.

In GDB, set a breakpoint at the address right after 0x0804841a with break. For example

break *0x0804841e

Then run the program and you can print the contents of EAX register with

info registers eax
Thien Phan
  • 358
  • 4
  • 8
  • 1
    Yes, but the question already mentions this method: *note: i know that i could simply read %eax after this instruction, but that is not my concern*. Some code does things like `sub %gs:0x14, %eax` / jnz, not loading it into a separate register first. (e.g. GCC's `-fstack-protector-strong` will do that to check the stack cookie.) – Peter Cordes Jan 31 '21 at 22:02