A.Olokhtonov
3 years ago
6 changed files with 416 additions and 355 deletions
@ -0,0 +1,94 @@
@@ -0,0 +1,94 @@
|
||||
static void |
||||
command_regs(struct mi_process proc) |
||||
{ |
||||
struct mi_registers regs = get_process_registers(proc); |
||||
printf("rax = %#018lx rcx = %#018lx\n" |
||||
"rbp = %#018lx rbx = %#018lx\n" |
||||
"rdx = %#018lx rsi = %#018lx\n" |
||||
"rdi = %#018lx rip = %#018lx\n" |
||||
"rsp = %#018lx\n", |
||||
regs.rax, regs.rcx, regs.rbp, regs.rbx, |
||||
regs.rdx, regs.rsi, regs.rdi, regs.rip, |
||||
regs.rsp); |
||||
} |
||||
|
||||
static void |
||||
command_step(struct mi_process proc) |
||||
{ |
||||
ptrace(PTRACE_SINGLESTEP, proc.pid, 0, 0); |
||||
waitpid(proc.pid, 0, 0); |
||||
|
||||
#if 1 |
||||
print_current_instruction(proc); |
||||
struct mi_registers regs = get_process_registers(proc); |
||||
struct mi_sourcepoint *sp = pc_to_sourcepoint(proc, regs.rip - proc.base_address); |
||||
print_current_line(proc, sp->line); |
||||
#endif |
||||
} |
||||
|
||||
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 = 0x000000cc; |
||||
long int3_word = (saved_instruction & 0xFFFFFF00) | 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); |
||||
} |
||||
|
||||
static void |
||||
command_next(struct mi_process proc) |
||||
{ |
||||
struct mi_registers regs = get_process_registers(proc); |
||||
|
||||
struct mi_sourcepoint *sp = pc_to_sourcepoint(proc, regs.rip - proc.base_address); |
||||
struct mi_sourcepoint *next_sp; |
||||
|
||||
do { |
||||
ptrace(PTRACE_SINGLESTEP, proc.pid, 0, 0); |
||||
waitpid(proc.pid, 0, 0); |
||||
regs = get_process_registers(proc); |
||||
//printf("%#lx\n", regs.rip - proc.base_address);
|
||||
next_sp = pc_to_sourcepoint(proc, regs.rip - proc.base_address); |
||||
// TODO: skip call, repXXX, etc
|
||||
} while (next_sp->line == sp->line); |
||||
|
||||
print_current_line(proc, next_sp->line); |
||||
} |
||||
|
||||
static void |
||||
command_list(struct mi_process proc) |
||||
{ |
||||
struct mi_registers regs = get_process_registers(proc); |
||||
struct mi_sourcepoint *sp = pc_to_sourcepoint(proc, regs.rip - proc.base_address); |
||||
print_current_line(proc, sp->line); |
||||
} |
||||
|
||||
static void |
||||
command_cont(struct mi_process proc) |
||||
{ |
||||
ptrace(PTRACE_CONT, proc.pid, 0, 0); |
||||
// TODO
|
||||
} |
||||
|
||||
static void |
||||
command_stop(struct mi_process proc) |
||||
{ |
||||
kill(proc.pid, SIGINT); |
||||
// TODO
|
||||
} |
@ -0,0 +1,72 @@
@@ -0,0 +1,72 @@
|
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
#include <stdlib.h> |
||||
#include <stdint.h> |
||||
#include <signal.h> |
||||
#include <syscall.h> |
||||
|
||||
#include <unistd.h> |
||||
#include <errno.h> |
||||
#include <assert.h> |
||||
#include <fcntl.h> |
||||
|
||||
#include <sys/uio.h> |
||||
#include <sys/types.h> |
||||
#include <sys/user.h> |
||||
#include <sys/ptrace.h> |
||||
#include <sys/wait.h> |
||||
#include <sys/stat.h> |
||||
#include <sys/mman.h> |
||||
#include <sys/personality.h> |
||||
|
||||
typedef uint8_t u8; |
||||
typedef uint16_t u16; |
||||
typedef uint32_t u32; |
||||
typedef uint64_t u64; |
||||
|
||||
typedef int8_t s8; |
||||
typedef int16_t s16; |
||||
typedef int32_t s32; |
||||
typedef int64_t s64; |
||||
|
||||
#include "elf_dwarf.h" |
||||
|
||||
struct mi_sourcepoint { |
||||
u64 pc; |
||||
int line; |
||||
int column; |
||||
int file; |
||||
}; |
||||
|
||||
struct mi_process { |
||||
pid_t pid; |
||||
|
||||
char *source; |
||||
u64 source_size; |
||||
|
||||
u8 *elf; |
||||
u64 elf_size; |
||||
|
||||
u64 base_address; |
||||
u64 main_address; |
||||
|
||||
struct mi_sourcepoint *sp_table; |
||||
int sp_count; |
||||
}; |
||||
|
||||
struct mi_registers { |
||||
u64 rbp; |
||||
u64 rbx; |
||||
u64 rax; |
||||
u64 rcx; |
||||
u64 rdx; |
||||
u64 rsi; |
||||
u64 rdi; |
||||
u64 rip; |
||||
u64 rsp; |
||||
|
||||
struct user_regs_struct _sys; |
||||
}; |
||||
|
||||
#define NT_PRSTATUS 1 |
||||
#define DIE(string) do { fprintf(stderr, string); exit(1); } while (0) |
@ -0,0 +1,169 @@
@@ -0,0 +1,169 @@
|
||||
static struct mi_sourcepoint * |
||||
pc_to_sourcepoint(struct mi_process proc, u64 pc) |
||||
{ |
||||
// NOTE: find first point BIGGER that pc, return the sourcepoint just before that
|
||||
// TODO: binary search
|
||||
for (int i = 0; i < proc.sp_count; ++i) { |
||||
struct mi_sourcepoint *point = proc.sp_table + i; |
||||
if (point->pc > pc) { |
||||
return(proc.sp_table + i - 1); |
||||
} |
||||
} |
||||
|
||||
return(0); |
||||
} |
||||
|
||||
static void |
||||
print_word_at_address(int child, u64 address) |
||||
{ |
||||
long word = ptrace(PTRACE_PEEKDATA, child, address, NULL); |
||||
u8 nb[4]; |
||||
memcpy(nb, &word, 4); |
||||
printf("word at %#018lx: {%x %x %x %x}\n", address, nb[0], nb[1], nb[2], nb[3]); |
||||
} |
||||
|
||||
static void |
||||
print_current_line(struct mi_process proc, u64 line) |
||||
{ |
||||
char *source = proc.source; |
||||
u64 size = proc.source_size; |
||||
u64 current_line = 1; |
||||
|
||||
for (u32 i = 0; i < size; ++i) { |
||||
if (current_line == line) { |
||||
int len = 0; |
||||
int start = 0; |
||||
int leading = 1; |
||||
|
||||
for (u32 j = i; j < size; ++j) { |
||||
if (leading && (source[j] == '\t' || source[j] == ' ')) { |
||||
++start; |
||||
} else { |
||||
leading = 0; |
||||
} |
||||
|
||||
if (source[j] == '\n') { |
||||
break; |
||||
} |
||||
|
||||
++len; |
||||
} |
||||
|
||||
|
||||
printf("%.*s\n", len - start, source + i + start); |
||||
return; |
||||
} |
||||
|
||||
if (source[i] == '\n') { |
||||
current_line++; |
||||
} |
||||
} |
||||
} |
||||
|
||||
static struct mi_process |
||||
process_create(char *path) |
||||
{ |
||||
struct mi_process result = { 0 }; |
||||
|
||||
/* disable ASLR */ |
||||
syscall(SYS_personality, ADDR_NO_RANDOMIZE); |
||||
|
||||
pid_t pid = fork(); |
||||
|
||||
if (pid == -1) { |
||||
DIE("fork error\n"); |
||||
} |
||||
|
||||
if (pid == 0) { |
||||
int rt = ptrace(PTRACE_TRACEME, 0, 0, 0); |
||||
assert(rt == 0); |
||||
char *args[] = { path, NULL }; |
||||
rt = execvp(path, args); |
||||
if (rt == -1) { |
||||
DIE("exevp error\n"); |
||||
} |
||||
} |
||||
|
||||
u64 source_size; |
||||
u64 elf_size; |
||||
u8 *elf; |
||||
char *source; |
||||
struct stat s; |
||||
int fd; |
||||
|
||||
{ |
||||
fd = open(path, O_RDONLY); |
||||
assert(fd != -1); |
||||
fstat(fd, &s); |
||||
elf_size = s.st_size; |
||||
elf = mmap(0, s.st_size, PROT_READ, MAP_PRIVATE, fd, 0); |
||||
close(fd); |
||||
} |
||||
|
||||
{ |
||||
fd = open("/code/trace-test/traceme.c", O_RDONLY); // TODO
|
||||
assert(fd != -1); |
||||
fstat(fd, &s); |
||||
source_size = s.st_size; |
||||
source = mmap(0, source_size, PROT_READ, MAP_PRIVATE, fd, 0); |
||||
close(fd); |
||||
} |
||||
|
||||
result.elf = elf; |
||||
result.elf_size = elf_size; |
||||
result.source = source; |
||||
result.source_size = source_size; |
||||
result.pid = pid; |
||||
|
||||
return(result); |
||||
} |
||||
|
||||
static struct mi_registers |
||||
get_process_registers(struct mi_process proc) |
||||
{ |
||||
struct user_regs_struct regs = { 0 }; |
||||
struct iovec iov = { ®s, 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) |
||||
{ |
||||
struct iovec iov = { ®s._sys, sizeof(regs._sys) }; |
||||
ptrace(PTRACE_GETREGSET, proc.pid, NT_PRSTATUS, &iov); |
||||
} |
||||
|
||||
static void |
||||
print_current_instruction(struct mi_process proc) |
||||
{ |
||||
struct mi_registers regs = get_process_registers(proc); |
||||
|
||||
long wordb = ptrace(PTRACE_PEEKDATA, proc.pid, regs.rip - 4, NULL); |
||||
long word = ptrace(PTRACE_PEEKDATA, proc.pid, regs.rip, NULL); |
||||
long worda = ptrace(PTRACE_PEEKDATA, proc.pid, regs.rip + 4, NULL); |
||||
|
||||
u8 nb[12]; |
||||
memcpy(nb, &wordb, 4); |
||||
memcpy(nb + 4, &word, 4); |
||||
memcpy(nb + 8, &worda, 4); |
||||
|
||||
printf("PC = %#018lx: %x %x %x %x [%x] %x %x %x %x %x %x %x\n", regs.rip, |
||||
nb[0], nb[1], nb[2], nb[3], nb[4], nb[5], nb[6], nb[7], |
||||
nb[8], nb[9], nb[10], nb[11]); |
||||
} |
Loading…
Reference in new issue