summaryrefslogblamecommitdiffstats
path: root/misplays.c
blob: a1f11a4048745df168e35f00d853f5665ca74078 (plain) (tree)
1
2
3
4
5
6
7
8
9
                  
                   
                   

                       
                     
                         

                   

                              
                    
                     
                    
 
                           
                           

                    


                  





































































                                                                                                       
  
 

                                                              









                                                                                
                                                             






                                                                         
                                                            











                                                      
                                                        






                                                                                    










                                                                         










                                                                 
                                         


                                                                         








                                                                     
                                                                                               








                                                                     






                          
                                                         
                





                                                            






                                   
       

 
                                                             
                   
























                                                                                

 
                                 

                                                      
                 
     
 

                
               

                               
                        
                       
 

                        
 


                                                     
     
 

                           

                   
                                
                                     

                              
                     
 



                         
                                
                                      
                          



                             
                             
                                                
                          
                         




                                                             
                                
                                              

                         
                      
                          















                                                               




                                            














                                                        
                         
                                              

                          
                                 
                          
































                                                                                     










                                              
                                

                                  
                               
                                      
                                

                            

                                                             




                                
                                      


                             
                                                



                          
                                             




                          
                      


             
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <linux/ptrace.h>
#include <unistd.h>

#include <capstone/capstone.h>

#include "console.h"
#include "debugger.h"
#include "helpers.h"

static PANEL *left, *right;
static struct console cons;
static int mode = 0;

PANEL *consolepan;

/*
static void describe_status(struct tracee *_dbg, PANEL *pan) {
    struct tracee dbg = *_dbg;
    int status = dbg.status;
    struct ptrace_syscall_info info;

    if (WIFEXITED(status)) {
        pprintw(pan, "exited with code: %u\n", WEXITSTATUS(status));
    } else if (WIFSIGNALED(status)) {
        pprintw(pan, "terminated by signal: %s\n", strsignal(WTERMSIG(status)));
    } else {
        unsigned long msg;
        if (ptrace(PTRACE_GETEVENTMSG, dbg.id, NULL, &msg) < 0) {
            perror("PTRACE_GETEVENTMSG");
        }

        if (WIFSTOPPED(status)) {
            switch (status >> 8) {
                case ((PTRACE_EVENT_VFORK << 8) | SIGTRAP):
                    pprintw(pan, "child vfork()'d to: %lu\n", msg);
                    break;
                case ((PTRACE_EVENT_FORK << 8) | SIGTRAP):
                    pprintw(pan, "child fork()'d to: %lu\n", msg);
                    break;
                case ((PTRACE_EVENT_CLONE << 8) | SIGTRAP):
                    pprintw(pan, "child clone()'d to: %lu\n", msg);
                    break;
                case ((PTRACE_EVENT_VFORK_DONE << 8) | SIGTRAP):
                    pprintw(pan, "finished vfork\n");
                    break;
                case ((PTRACE_EVENT_EXEC << 8) | SIGTRAP):
                    pprintw(pan, "child exec()'d from: %lu\n", msg);
                    break;
                case ((PTRACE_EVENT_EXIT << 8) | SIGTRAP):
                    pprintw(pan, "exiting with code: %lu\n", msg);
                    break;
                case ((PTRACE_EVENT_STOP << 8) | SIGTRAP):
                    pprintw(pan, "child stopped\n");
                    break;
                case ((PTRACE_EVENT_SECCOMP << 8) | SIGTRAP):
                    pprintw(pan, "child seccomp event\n");
                    break;

                case (SIGTRAP | 0x80):
                    ptrace(PTRACE_GET_SYSCALL_INFO, dbg.id, sizeof(info), &info);
                    pprintw(pan, "child entering syscall: %llu (%llx, %llx, %llx, %llx, %llx, %llx)\n",
                            info.entry.nr,
                            info.entry.args[0],
                            info.entry.args[1],
                            info.entry.args[2],
                            info.entry.args[3],
                            info.entry.args[4],
                            info.entry.args[5]);
                    break;

                case SIGSTOP:
                case SIGTSTP:
                case SIGTTIN:
                case SIGTTOU:
                    pprintw(pan, "child group-stopped\n");
                    break;

                default:
                    pprintw(pan, "received signal: %s\n", strsignal(WSTOPSIG(status)));
                    break;
            }
        } else {
            pprintw(pan, "child stop event unrecognized\n");
        }
    }
}
*/

static void list_breakpoints(struct thread *dbg, PANEL *pan) {
    struct list *breaks = &dbg->proc->breakpoints;
    if (breaks->head != breaks->end) {
        pprintw(pan, "---\n");

        for (struct breakpoint *bp=breaks->head; bp!=breaks->end; bp=bp->next) {
            pprintw(pan, "0x%lx  ", bp->address);
        }
        pprintw(pan, "\n");
    }
}

static void describe_states(struct thread *dbg, PANEL *pan) {
    struct list *states = &dbg->states;
    for (struct state *s = states->head; s != states->end; s = s->next) {
        pprintw(pan, "%c", (s == dbg->state ? '#' : '-'));
    }
    pprintw(pan, "\n");
}

static void dump_registers(struct thread *dbg, PANEL *pan) {
    struct user_regs_struct *regs = &dbg->state->regs;
    pprintw(pan, "rax = 0x%016llx\n", regs->rax);
    pprintw(pan, "rbx = 0x%016llx\n", regs->rbx);
    pprintw(pan, "rcx = 0x%016llx\n", regs->rcx);
    pprintw(pan, "rdx = 0x%016llx\n", regs->rdx);
    pprintw(pan, "rdi = 0x%016llx\n", regs->rdi);
    pprintw(pan, "rsi = 0x%016llx\n", regs->rsi);
    pprintw(pan, "rsp = 0x%016llx\n", regs->rsp);
    pprintw(pan, "rbp = 0x%016llx\n", regs->rbp);
    pprintw(pan, "rip = 0x%016llx\n", regs->rip);
}

static void dump_stack(struct thread *dbg, PANEL *pan) {
    unsigned long sp = dbg->state->regs.rsp;
    for (size_t i = 0; i < 16; i++, sp += 8) {
        unsigned long word = *(unsigned long *)deref(dbg, sp,sizeof(unsigned long));
        pprintw(pan, "0x%lx:\t0x%lx\n", sp, word);
    }
}

static int rip_visited(struct thread *th, unsigned long rip) {
    struct list *states = &th->states;
    for (struct state *s = states->head; s != states->end; s = s->next) {
        if (rip == s->regs.rip) {
            return 1;
        }
    }
    return 0;
}

static void disasm(struct thread *dbg, PANEL *pan) {
    csh handle;
    cs_insn *insn;

    if (cs_open(CS_ARCH_X86, CS_MODE_64, &handle) != CS_ERR_OK) {
        perror("capstone open");
    } else {
        uint64_t address = dbg->state->regs.rip;
        size_t codez = 128;
        const uint8_t *code = deref(dbg, address, codez);
        insn = cs_malloc(handle);

        for (size_t i = 0; i < 32; i++) {
            if (!cs_disasm_iter(handle, &code, &codez, &address, insn)) {
                break;
            }
            if (dbg->stopped) {
                if (insn->address == dbg->state->regs.rip) {
                    pattron(pan, COLOR_PAIR(1));
                } else if (is_breakpoint(dbg->proc, insn->address)) {
                    pattron(pan, COLOR_PAIR(3));
                } else if (rip_visited(dbg, insn->address)) {
                    pattron(pan, COLOR_PAIR(2));
                }
            }
            pprintw(pan, "0x%"PRIx64":\t%s %s\n", insn->address, insn->mnemonic, insn->op_str);
            if (dbg->stopped) {
                if (insn->address == dbg->state->regs.rip) {
                    pattroff(pan, COLOR_PAIR(1));
                } else if (is_breakpoint(dbg->proc, insn->address)) {
                    pattroff(pan, COLOR_PAIR(3));
                } else if (rip_visited(dbg, insn->address)) {
                    pattroff(pan, COLOR_PAIR(2));
                }
            }
        }

        cs_free(insn, 1);
        cs_close(&handle);
    }
}

static void info_update(struct thread *dbg, PANEL *pan) {
    pclear(pan);
    pprintw(pan, "TID: %li\n", (long)dbg->id);
    //if (!dbg->stopped) {
    //    pprintw(pan, "Thread is running...\n");
    //} else {
        //describe_status(dbg, pan);
        pprintw(pan, "%s (%i)\n", dbg->status, dbg->signal);
        list_breakpoints(dbg, pan);
        describe_states(dbg, pan);
        dump_registers(dbg, pan);
        pprintw(pan, "---\n");
        dump_stack(dbg, pan);
        pprintw(pan, "---\n");
        disasm(dbg, pan);
    //}
}

static void layout(struct process *proc, struct thread *th) {
    int w = COLS/2;
    reset_panel(left, LINES-2, w, 1, 0);
    reset_panel(right, LINES-2, COLS-w, 1, w);

    clear();
    attron(COLOR_PAIR(1));
    struct list *threads = &proc->threads;
    for (struct thread *t = threads->head; t != threads->end; t = t->next) {
        if (t == th) {
            printw("**");
        }
        printw("%li (%s)", (long)t->id, t->status);
        if (t == th) {
            printw("**");
        }
        printw("   ");
    }
    attroff(COLOR_PAIR(1));
    //refresh();
}

static void wait_all_threads(struct process *proc) {
    struct list *threads = &proc->threads;
    for (struct thread *th = threads->head; th != threads->end; th = th->next) {
        dbg_wait(th, 1);
    }
}

int main(int argc, char **argv) {
    if (argc < 2) {
        fprintf(stderr, "Usage: %s <pid>\n", argv[0]);
        return 1;
    }

    //getchar();

    cursinit();
    left = newpan(0, 0, 0, 0);
    right = newpan(0, 0, 0, 0);
    console_init(&cons);
    consolepan = right;

    struct process proc;
    struct thread *th;

    pid_t pid = strtoul(argv[1], NULL, 0);
    if (dbg_process(&proc, pid, 0)) {
        pprintw(right, "failed to attach process\n");
    }

    th = proc.threads.head;

    int quit = 0;
    while (!quit) {
        wait_all_threads(&proc);
        console_update(&cons, right);
        info_update(th, left);
        layout(&proc, th);
        cursupdate();

        int ch = getch();

        if (mode == 0) {
            switch (ch) {
                case KEY_RESIZE:
                    layout(&proc, th);
                    break;
                case 'q':
                    quit = 1;
                    break;
                case 'i':
                    mode = 1;
                    console_enter(&cons, right);
                    break;
                case 'j':
                    dbg_stepin(th);
                    /*
                    if (dbg->stopped) {
                        if (dbg->state != dbg->states.tail) {
                            dbg->state = dbg->state->next;
                        } else {
                            dbg_stepover(dbg);
                        }
                    }
                    */
                    break;
                //case 'k':
                //    if (dbg->stopped) {
                //        if (dbg->state != dbg->states.head) {
                //            dbg->state = dbg->state->prev;
                //        }
                //    }
                //    break;
                //case 'l':
                //    if (dbg->stopped) {
                //        if (dbg->state != dbg->states.tail) {
                //            //dbg.state = dbg.state->next;
                //        } else {
                //            dbg_stepin(dbg);
                //        }
                //    }
                //    break;
                //case 'h':
                //    if (dbg.stopped) {
                //        dbg_stepout(&dbg);
                //    }
                //    break;
                //case 'g':
                //    if (dbg->stopped) {
                //        dbg->state = dbg->states.head;
                //    }
                //    break;
                //case 'G':
                //    if (dbg->stopped) {
                //        dbg->state = dbg->states.tail;
                //    }
                //    break;
                //case 's':
                //    if (dbg->stopped) {
                //        dbg_cont(dbg, PTRACE_SYSCALL);
                //    }
                //    break;
                case 'c':
                    dbg_cont(th, PTRACE_CONT);
                    break;
                case 'p':
                    dbg_intr(th);
                    break;
                case 't':
                    do {
                        th = th->next;
                    } while (th == proc.threads.end);
                    break;
                case 'T':
                    do {
                        th = th->prev;
                    } while (th == proc.threads.end);
                    break;
                //case 'd':
                //    if (dbg->stopped) {
                //        while (dbg->breaks.head != dbg->breaks.end) {
                //            struct breakpoint *b = dbg->breaks.head;
                //            list_remove(b);
                //            free(b);
                //        }
                //    }
                //    break;
                //case 'D':
                //    if (dbg->stopped) {
                //        if (ptrace(PTRACE_DETACH, dbg->id, NULL, NULL) < 0) {
                //            pprintw(right, "PTRACE_DETACH: %s\n", strerror(errno));
                //        }
                //        struct tracee *rm = dbg;
                //        do {
                //            dbg = dbg->next;
                //        } while (dbg == tracees.end);
                //        list_remove(rm);
                //        dbg_free(rm);
                //        free(rm);
                //    }
                //    break;
                case ':':
                    mvprintw(LINES-1, 0, ":");
                    curs_set(TRUE);
                    echo();
                    timeout(-1);
                    char cmd[128] = {0};
                    getstr(cmd);
                    curs_set(FALSE);
                    noecho();
                    timeout(25);
                    clear();
                    //refresh();

                    char *t = cmd;
                    int en = 1;
                    if (t[0] == '!') {
                        en = -1;
                        t++;
                    }
                    unsigned long addr = strtoul(t, NULL, 0);
                    add_breakpoint(&proc, addr, 0, 0, en);
                    break;
            }
        } else {
            switch (ch) {
                case KEY_RESIZE:
                    layout(&proc, th);
                    break;
                case 0x1b:
                    mode = 0;
                    console_leave(&cons, right);
                    break;
                case ERR:
                    break;
                default:
                    console_input(&cons, ch);
                    break;
            }
        }
    }

    dbg_detach(&proc);
    endwin();
    return 0;
}