Ваша программа работает, вам просто нужно посмотреть в нужном месте в правильном порядке в вашем результате.
Имея это определение теста:
#include <stdio.h>
int main()
{
puts("hello");
puts("world");
return 0;
}
objdump -d test
производит среди других вещи:
0000000000400526 <main>:
400526: 55 push %rbp
400527: 48 89 e5 mov %rsp,%rbp
40052a: bf d4 05 40 00 mov $0x4005d4,%edi
40052f: e8 cc fe ff ff callq 400400 <puts@plt>
400534: bf da 05 40 00 mov $0x4005da,%edi
400539: e8 c2 fe ff ff callq 400400 <puts@plt>
40053e: b8 00 00 00 00 mov $0x0,%eax
400543: 5d pop %rbp
400544: c3 retq
400545: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
40054c: 00 00 00
40054f: 90 nop
если я запустил вашу программу среди результатов, я нашел код с теми же адресами objdump и теми же кодами инструкций, поэтому init section et c затем main (из строки 81208!):
400526 4005d4bfe5894855
400527 4005d4bfe58948
40052a fecce8004005d4bf
40052f 5dabffffffecce8
400400 6800200c1225ff
400406 ffe0e90000000068
40040b a25ffffffffe0e9
4003f0 25ff00200c1235ff
4003f6 1f0f00200c1425ff
...
Я запускаю на Intel i7, байты инструкции должны читаться в обратном порядке, чем показано objdump , например, первая инструкция 55 , затем 48 89 e5 , затем bf d4 05 40 00 , затем e8 cc fe ff ff et c.
Конечно, в вашем случае это похоже на «шаг», а не «следующий» в отладчике, поэтому на callq * От 1032 * до ставит , введенные вами в ставит , а objdump разбирает. До адреса 4005234 имеется 60084 строки после адреса 400534, поэтому для выполнения команды puts("hello");
необходимо 60084 инструкции!
Конечно, можно печатать только с начала main , например, с ленивым способом, используя objdump :
void debugger(pid_t pid)
{
FILE * fp = popen("objdump -d ./test | grep \"<main>:\"", "r");
if (fp == NULL) {
puts("cannot get main address");
}
else {
char line[256];
if (fgets(line, sizeof(line), fp) == NULL) {
puts("no address !");
pclose(fp);
}
else {
unsigned long long main_addr;
pclose(fp);
errno = 0;
main_addr = strtoull(line, NULL, 16);
if (errno != 0)
puts("invalid address");
else {
int found = 0;
int status;
while(wait(&status), WIFSTOPPED(status))
{
struct user_regs_struct regs;
ptrace(PTRACE_GETREGS, pid, 0, ®s);
if (found |= (regs.rip == main_addr)) {
long instruction = ptrace(PTRACE_PEEKTEXT, pid, regs.rip, 0);
printf("%llx %16lx\n", regs.rip, instruction);
}
ptrace(PTRACE_SINGLESTEP, pid, 0, 0);
}
}
}
}
}
[редактировать из вашего замечания]
ptrace не знает, хотите ли вы прочитать данные или инструкции, если вы хотите отделить каждую инструкцию как objdump вы должны знать код каждой и соответствующей длины, иначе вы можете использовать разницу адресов от одного к другому, даже если это не работает в случае вызова / jmp / условного jmp / return:
void debugger(pid_t pid)
{
FILE * fp = popen("objdump -d ./test | grep \"<main>:\"", "r");
if (fp == NULL) {
puts("cannot get main address");
}
else {
char line[256];
if (fgets(line, sizeof(line), fp) == NULL) {
puts("no address !");
pclose(fp);
}
else {
unsigned long long main_addr;
pclose(fp);
errno = 0;
main_addr = strtoull(line, NULL, 16);
if (errno != 0)
puts("invalid address");
else {
int found = 0;
int status;
unsigned long prev_instr;
long long prev_addr = -1;
while(wait(&status), WIFSTOPPED(status))
{
struct user_regs_struct regs;
ptrace(PTRACE_GETREGS, pid, 0, ®s);
if (found |= (regs.rip == main_addr)) {
unsigned long instruction =
(unsigned long) ptrace(PTRACE_PEEKTEXT, pid, regs.rip, 0);
if (prev_addr != -1) {
/* longest instruction has 15 bytes on x86 */
int len = ((regs.rip > prev_addr) && ((regs.rip - prev_addr) <= 15))
? regs.rip - prev_addr : 100;
printf("%llx ", prev_addr);
while (prev_instr && len--) {
printf("%02x ", (unsigned) (prev_instr & 0xff));
prev_instr /= 256;
}
if (len > 15)
puts(" (?)");
else
putchar('\n');
}
prev_instr = instruction;
prev_addr = regs.rip;
}
ptrace(PTRACE_SINGLESTEP, pid, 0, 0);
}
}
}
}
}
теперь вывод:
400526 55
400527 48 89 e5
40052a bf d4 05 40 00
40052f e8 cc fe ff ff bf da 05 (?)
400400 ff 25 12 0c 20 00
400406 68 00 00 00 00
40040b e9 e0 ff ff ff ff 25 0a (?)
4003f0 ff 35 12 0c 20 00
4003f6 ff 25 14 0c 20 00 0f 1f (?)
7fe20cc1fe10 53
7fe20cc1fe11 48 89 e3
7fe20cc1fe14 48 83 e4 c0
7fe20cc1fe18 48 2b 25 31 df 20 00
7fe20cc1fe1f 48 89 04 24
7fe20cc1fe23 48 89 4c 24 08
...
, чтобы сделать больше, вы должны знать код и длину каждого вызова инструкции / jmp / условное jmp / return. Заметьте, что код операции может быть на 1 или 2 байта.