Browse Source

Step over calls!!!!

master
A.Olokhtonov 3 years ago
parent
commit
be8fac97cc
  1. 42
      command.c
  2. 3
      traceme.c
  3. 142
      util.c

42
command.c

@ -30,25 +30,8 @@ static void @@ -30,25 +30,8 @@ static void
command_start(struct mi_process proc)
{
u64 main_address = proc.base_address + proc.main_address;
long saved_instruction = ptrace(PTRACE_PEEKDATA, proc.pid, main_address, NULL);
long int3_byte = 0x000000000000cc;
long int3_word = (saved_instruction & 0xFFFFFFFFFFFFFF00) | int3_byte;
/* write 0xcc */
ptrace(PTRACE_POKEDATA, proc.pid, main_address, int3_word);
/* wait till child hits the interrupt */
ptrace(PTRACE_CONT, proc.pid, 0, 0);
waitpid(proc.pid, 0, 0);
/* restore original instrucion */
ptrace(PTRACE_POKEDATA, proc.pid, main_address, saved_instruction);
/* step back to original instruction */
struct mi_registers regs = get_process_registers(proc);
regs.rip -= 1;
set_process_registers(proc, regs);
long saved_instruction = place_breakpoint_at(proc, main_address);
run_until_breakpoint_and_restore(proc, main_address, saved_instruction);
}
static void
@ -63,9 +46,28 @@ command_next(struct mi_process proc) @@ -63,9 +46,28 @@ command_next(struct mi_process proc)
ptrace(PTRACE_SINGLESTEP, proc.pid, 0, 0);
waitpid(proc.pid, 0, 0);
regs = get_process_registers(proc);
long instruction = ptrace(PTRACE_PEEKDATA, proc.pid, regs.rip, NULL);
if (is_call_instruction(instruction)) {
u64 call_at = regs.rip;
// Do single step, get return address from stack, place breakpoint there, continue
ptrace(PTRACE_SINGLESTEP, proc.pid, 0, 0);
waitpid(proc.pid, 0, 0);
regs = get_process_registers(proc);
long return_address = ptrace(PTRACE_PEEKDATA, proc.pid, regs.rsp, NULL);
long saved_instruction = place_breakpoint_at(proc, return_address);
run_until_breakpoint_and_restore(proc, return_address, saved_instruction);
// TODO: disambiguate recursive calls
regs = get_process_registers(proc);
}
// TODO: skip call, repXXX
//printf("%#lx\n", regs.rip - proc.base_address);
next_sp = pc_to_sourcepoint(proc, regs.rip - proc.base_address);
// TODO: skip call, repXXX, etc
if (!next_sp) break;
} while (next_sp->line == sp->line);

3
traceme.c

@ -19,5 +19,8 @@ int main() @@ -19,5 +19,8 @@ int main()
foo(3);
pipa += 4;
boba = foo(2) - foo(1);
return 0;
}

142
util.c

@ -1,3 +1,97 @@ @@ -1,3 +1,97 @@
static struct mi_registers
get_process_registers(struct mi_process proc)
{
struct user_regs_struct regs = { 0 };
struct iovec iov = { &regs, sizeof(regs) };
struct mi_registers result = { 0 };
ptrace(PTRACE_GETREGSET, proc.pid, NT_PRSTATUS, &iov);
result.rax = regs.rax;
result.rip = regs.rip;
result.rbp = regs.rbp;
result.rbx = regs.rbx;
result.rcx = regs.rcx;
result.rdx = regs.rdx;
result.rsi = regs.rsi;
result.rdi = regs.rdi;
result.rsp = regs.rsp;
result._sys = regs;
return(result);
}
static void
set_process_registers(struct mi_process proc, struct mi_registers regs)
{
regs._sys.rax = regs.rax;
regs._sys.rip = regs.rip;
regs._sys.rbp = regs.rbp;
regs._sys.rbx = regs.rbx;
regs._sys.rcx = regs.rcx;
regs._sys.rdx = regs.rdx;
regs._sys.rsi = regs.rsi;
regs._sys.rdi = regs.rdi;
regs._sys.rsp = regs.rsp;
struct iovec iov = { &regs._sys, sizeof(regs._sys) };
ptrace(PTRACE_SETREGSET, proc.pid, NT_PRSTATUS, &iov);
}
static int
is_call_instruction(long word)
{
// It's a call if:
// first byte == 0xe8
// first byte == 0xff AND "reg field" (bit 3-5 in next byte) == 2 or 3
// REX.W + 0xff/3 ????? TODO TODO TODO
u8 first_byte = word & 0xFF;
if (first_byte == 0xE8) {
return 1;
} else if (first_byte == 0xFF) {
u8 second_byte = word & 0xFF00UL;
u8 reg = second_byte & 0x38; // 111000 (to extract bits 3-5)
if (reg == 2 || reg == 3) {
return 1;
}
}
return 0;
}
static long
place_breakpoint_at(struct mi_process proc, u64 address)
{
long saved_instruction = ptrace(PTRACE_PEEKDATA, proc.pid, address, NULL);
long int3_byte = 0x000000000000CC;
long int3_word = (saved_instruction & 0xFFFFFFFFFFFFFF00) | int3_byte;
/* write 0xcc */
ptrace(PTRACE_POKEDATA, proc.pid, address, int3_word);
return(saved_instruction);
}
static void
run_until_breakpoint_and_restore(struct mi_process proc, u64 address, long saved_instruction)
{
/* wait till child hits the interrupt */
ptrace(PTRACE_CONT, proc.pid, 0, 0);
waitpid(proc.pid, 0, 0);
/* restore original instrucion */
ptrace(PTRACE_POKEDATA, proc.pid, address, saved_instruction);
/* step back to original instruction */
struct mi_registers regs = get_process_registers(proc);
regs.rip -= 1;
set_process_registers(proc, regs);
}
static u64
get_address_of_subroutine(struct mi_process proc, char *sr)
{
@ -42,7 +136,12 @@ read_file_mmap(char *path) @@ -42,7 +136,12 @@ read_file_mmap(char *path)
struct stat s;
int fd = open(path, O_RDONLY);
assert(fd != -1);
if (fd == -1) {
printf("File not found: %s\n", path);
DIE("open() failed\n");
}
fstat(fd, &s);
result.data = mmap(0, s.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
@ -146,47 +245,6 @@ process_create(char *path) @@ -146,47 +245,6 @@ process_create(char *path)
return(result);
}
static struct mi_registers
get_process_registers(struct mi_process proc)
{
struct user_regs_struct regs = { 0 };
struct iovec iov = { &regs, sizeof(regs) };
struct mi_registers result = { 0 };
ptrace(PTRACE_GETREGSET, proc.pid, NT_PRSTATUS, &iov);
result.rax = regs.rax;
result.rip = regs.rip;
result.rbp = regs.rbp;
result.rbx = regs.rbx;
result.rcx = regs.rcx;
result.rdx = regs.rdx;
result.rsi = regs.rsi;
result.rdi = regs.rdi;
result.rsp = regs.rsp;
result._sys = regs;
return(result);
}
static void
set_process_registers(struct mi_process proc, struct mi_registers regs)
{
regs._sys.rax = regs.rax;
regs._sys.rip = regs.rip;
regs._sys.rbp = regs.rbp;
regs._sys.rbx = regs.rbx;
regs._sys.rcx = regs.rcx;
regs._sys.rdx = regs.rdx;
regs._sys.rsi = regs.rsi;
regs._sys.rdi = regs.rdi;
regs._sys.rsp = regs.rsp;
struct iovec iov = { &regs._sys, sizeof(regs._sys) };
ptrace(PTRACE_SETREGSET, proc.pid, NT_PRSTATUS, &iov);
}
static void
print_current_instruction(struct mi_process proc)
{

Loading…
Cancel
Save