Valgrind 在他們的檔案頁面上說以下內容
然后,您的程式將在 Valgrind 核心提供的合成 CPU 上運行
然而 GDB 似乎并沒有這樣做。它似乎啟動了一個獨立執行的單獨行程。據我所知,也沒有 c 庫。這是我所做的
- 使用 clang 或 gcc 編譯
gcc -g tiny.s -nostdlib(-g似乎是必需的) gdb ./a.out- 寫
starti - 多按
s幾下
你會看到它會列印出“Test1\n”而不列印 test2。您也可以在不終止 gdb 的情況下終止該行程。GDB 會說“程式收到信號 SIGTERM,已終止。” 并且永遠不會寫Test2
gdb 如何啟動行程并讓它一次只執行一行?
.text
.intel_syntax noprefix
.globl _start
.p2align 4, 0x90
.type _start,@function
_start:
lea rsi, [rip .s1]
mov edi, 1
mov edx, 6
mov eax, 1
syscall
lea rsi, [rip .s2]
mov edi, 1
mov edx, 6
mov eax, 1
syscall
mov eax, 60
xor edi, edi
syscall
.s1:
.ascii "Test1\n"
.s2:
.ascii "Test2\n"
uj5u.com熱心網友回復:
starti 執行
對于想要啟動另一個行程的行程,它會像 shell 一樣執行 fork/exec。但是在新的行程中,GDB并不僅僅立即進行 execve 系統呼叫。
相反,它呼叫ptrace(PTRACE_TRACEME)等待父行程附加到它,因此 GDB(父行程)在子行程進行execve()系統呼叫之前已經附加,以使該行程開始執行指定的可執行檔案。
還要注意execve(2)手冊頁:
如果正在跟蹤當前程式,則在成功執行 execve() 后會向它發送一個 SIGTRAP 信號。
這就是內核除錯 API 支持在新執行的行程中執行第一條用戶空間指令之前停止的方式。 即正是starti想要什么。這不依賴于設定斷點;無論如何,這在 execve 之后不會發生,并且在 execve 選擇基地址之后,ASLR 甚至都不知道正確的地址。(默認情況下,GDB 禁用 ASLR,但如果您告訴它不要禁用 ASLR,它仍然可以作業。)
如果您strace -f -o gdb.trace gdb ./foo或其他人,您會看到 GDB 的一些功能。(嵌套跟蹤顯然不起作用,因此在 strace 下運行 GDB 意味著 GDB 的 ptrace 系統呼叫失敗,但我們可以看到它導致的結果。)
...
231566 execve("/usr/bin/gdb", ["gdb", "./foo"], 0x7ffca2416e18 /* 57 vars */) = 0
# the initial GDB process is PID 231566.
... whole bunch of stuff
231566 write(1, "Starting program: /tmp/foo \n", 28) = 28
231566 personality(0xffffffff) = 0 (PER_LINUX)
231566 personality(PER_LINUX|ADDR_NO_RANDOMIZE) = 0 (PER_LINUX)
231566 personality(0xffffffff) = 0x40000 (PER_LINUX|ADDR_NO_RANDOMIZE)
231566 vfork( <unfinished ...>
# 231584 is the new PID created by vfork that would go on to execve the new PID
231584 openat(AT_FDCWD, "/proc/self/fd", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 13
231584 newfstatat(13, "", {st_mode=S_IFDIR|0500, st_size=0, ...}, AT_EMPTY_PATH) = 0
231584 getdents64(13, 0x558403e20360 /* 16 entries */, 32768) = 384
231584 close(3) = 0
... all these FDs
231584 close(12) = 0
231584 getdents64(13, 0x558403e20360 /* 0 entries */, 32768) = 0
231584 close(13) = 0
231584 getpid() = 231584
231584 getpid() = 231584
231584 setpgid(231584, 231584) = 0
231584 ptrace(PTRACE_TRACEME) = -1 EPERM (Operation not permitted)
231584 write(2, "warning: ", 9) = 9
231584 write(2, "Could not trace the inferior pro"..., 37) = 37
231584 write(2, "\n", 1) = 1
231584 write(2, "warning: ", 9) = 9
231584 write(2, "ptrace", 6) = 6
231584 write(2, ": ", 2) = 2
231584 write(2, "Operation not permitted", 23) = 23
231584 write(2, "\n", 1) = 1
# gotta love unbuffered stderr
231584 exit_group(127) = ?
231566 <... vfork resumed>) = 231584 # in the parent
231584 exited with 127
# then the parent is running again
231566 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=231584, si_uid=1000, si_status=127, si_utime=0, si_stime=0} ---
231566 rt_sigreturn({mask=[]}) = 231584
... then I typed "quit" and hit return
有一些較早的clone系統呼叫在主 GDB 行程中創建更多執行緒,但這些呼叫直到 vforked PID 嘗試之后才退出ptrace(PTRACE_TRACEME)。它們都只是執行緒,因為它們clone與CLONE_VM. 有一個較早vfork/execve的/usr/bin/iconv。
令人惱火的是,現代 Linux 已經轉移到 16 位以上的 PID,因此對于人類思維來說,數字變得不方便。
step 執行:
與在支持它的 ISA 上stepi使用的不同PTRACE_SINGLESTEP(例如 x86,其中內核可以使用 TF 陷阱標志,但有趣的是不是 ARM),step它基于源級行號 <-> 地址除錯資訊。這對于 asm 來說通常毫無意義,除非你想跳過宏擴展或其他東西。
But for step, GDB will use ptrace(PTRACE_POKETEXT) to write an int3 debug-break opcode over the first byte of an instruction, then ptrace(PTRACE_CONT) to let execution run in the child process until it hits a breakpoint or other signal. (Then put back the original opcode byte when this instruction needs to execute). The place at which it puts that breakpoint is something it finds by looking for the next address of a line-number in the DWARF or STABS debug info (metadata) in the executable. That's why only stepi (aka si) works when you don't have debug info.
Or possibly it would use PTRACE_SINGLESTEP one or two times as an optimization if it saw it was close.
(我通常只使用si或ni用于除錯 asm,而不是s或n. layout reg也很好,當 GDB 不會崩潰時。有關更多 GDB 除錯技巧,請參閱x86 標記 wiki的底部。)
如果您想詢問 x86 ISA 如何支持除錯,而不是通過與目標無關的 API 公開這些功能的 Linux 內核 API,請參閱相關問答:
- PTRACE_SINGLESTEP 是如何實作的?
- 為什么在 X86 上使用單步指令?
- 如何使用 CPU 本身判斷 x86-64 指令操作碼的長度?
另外除錯器是如何作業的?有一些 Windowsy 答案。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/341857.html
上一篇:Python復制檔案到遠程
