diff options
Diffstat (limited to 'src/libmach/linux.c')
-rw-r--r-- | src/libmach/linux.c | 1008 |
1 files changed, 0 insertions, 1008 deletions
diff --git a/src/libmach/linux.c b/src/libmach/linux.c deleted file mode 100644 index 89f3b2070..000000000 --- a/src/libmach/linux.c +++ /dev/null @@ -1,1008 +0,0 @@ -// Derived from Plan 9 from User Space src/libmach/Linux.c -// http://code.swtch.com/plan9port/src/tip/src/libmach/Linux.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. -// Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net). -// Portions Copyright © 1997-1999 Vita Nuova Limited. -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). -// Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others. -// Portions Copyright © 2001-2007 Russ Cox. -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include <u.h> -#include <sys/syscall.h> /* for tkill */ -#include <unistd.h> -#include <dirent.h> -#include <sys/ptrace.h> -#include <sys/signal.h> -#include <sys/wait.h> -#include <errno.h> -#include <libc.h> -#include <bio.h> -#include <mach.h> -#include <ureg_x86.h> -#include <ureg_amd64.h> -#undef waitpid - -// The old glibc used with crosstool compilers on thresher -// doesn't know these numbers, but the Linux kernel -// had them as far back as 2.6.0. -#ifndef WSTOPPED -#define WSTOPPED 2 -#define WCONTINUED 8 -#define WIFCONTINUED(x) ((x) == 0xffff) -#endif -#ifndef PTRACE_SETOPTIONS -#define PTRACE_SETOPTIONS 0x4200 -#define PTRACE_GETEVENTMSG 0x4201 -#define PTRACE_O_TRACEFORK 0x2 -#define PTRACE_O_TRACEVFORK 0x4 -#define PTRACE_O_TRACECLONE 0x8 -#define PTRACE_O_TRACEEXEC 0x10 -#define PTRACE_O_TRACEVFORKDONE 0x20 -#define PTRACE_O_TRACEEXIT 0x40 -#define PTRACE_EVENT_FORK 0x1 -#define PTRACE_EVENT_VFORK 0x2 -#define PTRACE_EVENT_CLONE 0x3 -#define PTRACE_EVENT_EXEC 0x4 -#define PTRACE_EVENT_VFORK_DONE 0x5 -#define PTRACE_EVENT_EXIT 0x6 -#endif - -static Maprw ptracesegrw; -static Maprw ptraceregrw; - -// /usr/include/asm-x86_64/user.h -struct user_regs_struct { - unsigned long r15,r14,r13,r12,rbp,rbx,r11,r10; - unsigned long r9,r8,rax,rcx,rdx,rsi,rdi,orig_rax; - unsigned long rip,cs,eflags; - unsigned long rsp,ss; - unsigned long fs_base, gs_base; - unsigned long ds,es,fs,gs; -}; - -// Linux gets very upset if a debugger forgets the reported state -// of a debugged process, so we keep everything we know about -// a debugged process in the LinuxThread structure. -// -// We can poll for state changes by calling waitpid and interpreting -// the integer status code that comes back. Wait1 does this. -// -// If the process is already running, it is an error to PTRACE_CONT it. -// -// If the process is already stopped, it is an error to stop it again. -// -// If the process is stopped because of a signal, the debugger must -// relay the signal to the PTRACE_CONT call, or else the signal is -// dropped. -// -// If the process exits, the debugger should detach so that the real -// parent can reap the zombie. -// -// On first attach, the debugger should set a handful of flags in order -// to catch future events like fork, clone, exec, etc. - -// One for every attached thread. -typedef struct LinuxThread LinuxThread; -struct LinuxThread -{ - int pid; - int tid; - int state; - int signal; - int child; - int exitcode; -}; - -static int trace = 0; - -static LinuxThread **thr; -static int nthr; -static int mthr; - -static int realpid(int pid); - -enum -{ - Unknown, - Detached, - Attached, - AttachStop, - Stopped, - Running, - Forking, - Vforking, - VforkDone, - Cloning, - Execing, - Exiting, - Exited, - Killed, - - NSTATE, -}; - -static char* statestr[NSTATE] = { - "Unknown", - "Detached", - "Attached", - "AttachStop", - "Stopped", - "Running", - "Forking", - "Vforking", - "VforkDone", - "Cloning", - "Execing", - "Exiting", - "Exited", - "Killed" -}; - -static LinuxThread* -attachthread(int pid, int tid, int *new, int newstate) -{ - int i, n, status; - LinuxThread **p, *t; - uintptr flags; - - if(new) - *new = 0; - - for(i=0; i<nthr; i++) - if((pid == 0 || thr[i]->pid == pid) && thr[i]->tid == tid) { - t = thr[i]; - goto fixup; - } - - if(!new) - return nil; - - if(nthr >= mthr) { - n = mthr; - if(n == 0) - n = 64; - else - n *= 2; - p = realloc(thr, n*sizeof thr[0]); - if(p == nil) - return nil; - thr = p; - mthr = n; - } - - t = malloc(sizeof *t); - if(t == nil) - return nil; - memset(t, 0, sizeof *t); - - thr[nthr++] = t; - if(pid == 0 && nthr > 0) - pid = thr[0]->pid; - t->pid = pid; - t->tid = tid; - t->state = newstate; - if(trace) - fprint(2, "new thread %d %d\n", t->pid, t->tid); - if(new) - *new = 1; - -fixup: - if(t->state == Detached) { - if(ptrace(PTRACE_ATTACH, tid, 0, 0) < 0) { - fprint(2, "ptrace ATTACH %d: %r\n", tid); - return nil; - } - t->state = Attached; - } - - if(t->state == Attached) { - // wait for stop, so we can set options - if(waitpid(tid, &status, __WALL|WUNTRACED|WSTOPPED) < 0) - return nil; - if(!WIFSTOPPED(status)) { - fprint(2, "waitpid %d: status=%#x not stopped\n", tid); - return nil; - } - t->state = AttachStop; - } - - if(t->state == AttachStop) { - // set options so we'll find out about new threads - flags = PTRACE_O_TRACEFORK | - PTRACE_O_TRACEVFORK | - PTRACE_O_TRACECLONE | - PTRACE_O_TRACEEXEC | - PTRACE_O_TRACEVFORKDONE; - if(ptrace(PTRACE_SETOPTIONS, tid, 0, (void*)flags) < 0) { - fprint(2, "ptrace PTRACE_SETOPTIONS %d: %r\n", tid); - return nil; - } - t->state = Stopped; - } - - return t; -} - -static LinuxThread* -findthread(int tid) -{ - return attachthread(0, tid, nil, 0); -} - -int -procthreadpids(int pid, int *p, int np) -{ - int i, n; - LinuxThread *t; - - n = 0; - for(i=0; i<nthr; i++) { - t = thr[i]; - if(t->pid == pid) { - switch(t->state) { - case Exited: - case Detached: - case Killed: - break; - - default: - if(n < np) - p[n] = t->tid; - n++; - break; - } - } - } - return n; -} - -// Execute a single wait and update the corresponding thread. -static int -wait1(int nohang) -{ - int tid, new, status, event; - ulong data; - LinuxThread *t; - enum - { - NormalStop = 0x137f - }; - - if(nohang != 0) - nohang = WNOHANG; - - status = 0; - tid = waitpid(-1, &status, __WALL|WUNTRACED|WSTOPPED|WCONTINUED|nohang); - - if(tid < 0) - return -1; - if(tid == 0) - return 0; - - if(trace > 0 && status != NormalStop) - fprint(2, "TID %d: %#x\n", tid, status); - - t = findthread(tid); - if(t == nil) { - // Sometimes the kernel tells us about new threads - // before we see the parent clone. - t = attachthread(0, tid, &new, Stopped); - if(t == nil) { - fprint(2, "failed to attach to new thread %d\n", tid); - return -1; - } - } - - if(WIFSTOPPED(status)) { - t->state = Stopped; - t->signal = WSTOPSIG(status); - if(trace) - fprint(2, "tid %d: stopped %#x%s\n", tid, status, - status != NormalStop ? " ***" : ""); - if(t->signal == SIGTRAP && (event = status>>16) != 0) { // ptrace event - switch(event) { - case PTRACE_EVENT_FORK: - t->state = Forking; - goto child; - - case PTRACE_EVENT_VFORK: - t->state = Vforking; - goto child; - - case PTRACE_EVENT_CLONE: - t->state = Cloning; - goto child; - - child: - if(ptrace(PTRACE_GETEVENTMSG, t->tid, 0, &data) < 0) { - fprint(2, "ptrace GETEVENTMSG tid %d: %r\n", tid); - break; - } - t->child = data; - attachthread(t->pid, t->child, &new, Running); - break; - - case PTRACE_EVENT_EXEC: - t->state = Execing; - break; - - case PTRACE_EVENT_VFORK_DONE: - t->state = VforkDone; - break; - - case PTRACE_EVENT_EXIT: - // We won't see this unless we set PTRACE_O_TRACEEXIT. - // The debuggers assume that a read or write on a Map - // will fail for a thread that has exited. This event - // breaks that assumption. It's not a big deal: we - // only lose the ability to see the register state at - // the time of exit. - if(trace) - fprint(2, "tid %d: exiting %#x\n", tid, status); - t->state = Exiting; - if(ptrace(PTRACE_GETEVENTMSG, t->tid, 0, &data) < 0) { - fprint(2, "ptrace GETEVENTMSG tid %d: %r\n", tid); - break; - } - t->exitcode = data; - break; - } - } - } - if(WIFCONTINUED(status)) { - if(trace) - fprint(2, "tid %d: continued %#x\n", tid, status); - t->state = Running; - } - if(WIFEXITED(status)) { - if(trace) - fprint(2, "tid %d: exited %#x\n", tid, status); - t->state = Exited; - t->exitcode = WEXITSTATUS(status); - t->signal = -1; - ptrace(PTRACE_DETACH, t->tid, 0, 0); - if(trace) - fprint(2, "tid %d: detach exited\n", tid); - } - if(WIFSIGNALED(status)) { - if(trace) - fprint(2, "tid %d: signaled %#x\n", tid, status); - t->state = Exited; - t->signal = WTERMSIG(status); - t->exitcode = -1; - ptrace(PTRACE_DETACH, t->tid, 0, 0); - if(trace) - fprint(2, "tid %d: detach signaled\n", tid); - } - return 1; -} - -static int -waitstop(LinuxThread *t) -{ - while(t->state == Running) - if(wait1(0) < 0) - return -1; - return 0; -} - -// Attach to and stop all threads in process pid. -// Must stop everyone in order to make sure we set -// the "tell me about new threads" option in every -// task. -int -attachallthreads(int pid) -{ - int tid, foundnew, new; - char buf[100]; - DIR *d; - struct dirent *de; - LinuxThread *t; - - if(pid == 0) { - fprint(2, "attachallthreads(0)\n"); - return -1; - } - - pid = realpid(pid); - - snprint(buf, sizeof buf, "/proc/%d/task", pid); - if((d = opendir(buf)) == nil) { - fprint(2, "opendir %s: %r\n", buf); - return -1; - } - - // Loop in case new threads are being created right now. - // We stop every thread as we find it, so eventually - // this has to stop (or the system runs out of procs). - do { - foundnew = 0; - while((de = readdir(d)) != nil) { - tid = atoi(de->d_name); - if(tid == 0) - continue; - t = attachthread(pid, tid, &new, Detached); - foundnew |= new; - if(t) - waitstop(t); - } - rewinddir(d); - } while(foundnew); - closedir(d); - - return 0; -} - -Map* -attachproc(int pid, Fhdr *fp) -{ - Map *map; - - if(pid == 0) { - fprint(2, "attachproc(0)\n"); - return nil; - } - - if(findthread(pid) == nil && attachallthreads(pid) < 0) - return nil; - - map = newmap(0, 4); - if (!map) - return 0; - map->pid = pid; - if(mach->regsize) - setmap(map, -1, 0, mach->regsize, 0, "regs", ptraceregrw); -// if(mach->fpregsize) -// setmap(map, -1, mach->regsize, mach->regsize+mach->fpregsize, 0, "fpregs", ptraceregrw); - setmap(map, -1, fp->txtaddr, fp->txtaddr+fp->txtsz, fp->txtaddr, "*text", ptracesegrw); - setmap(map, -1, fp->dataddr, mach->utop, fp->dataddr, "*data", ptracesegrw); - return map; -} - -void -detachproc(Map *m) -{ - LinuxThread *t; - - t = findthread(m->pid); - if(t != nil) { - ptrace(PTRACE_DETACH, t->tid, 0, 0); - t->state = Detached; - if(trace) - fprint(2, "tid %d: detachproc\n", t->tid); - // TODO(rsc): Reclaim thread structs somehow? - } - free(m); -} - -/* /proc/pid/stat contains - pid - command in parens - 0. state - 1. ppid - 2. pgrp - 3. session - 4. tty_nr - 5. tpgid - 6. flags (math=4, traced=10) - 7. minflt - 8. cminflt - 9. majflt - 10. cmajflt - 11. utime - 12. stime - 13. cutime - 14. cstime - 15. priority - 16. nice - 17. 0 - 18. itrealvalue - 19. starttime - 20. vsize - 21. rss - 22. rlim - 23. startcode - 24. endcode - 25. startstack - 26. kstkesp - 27. kstkeip - 28. pending signal bitmap - 29. blocked signal bitmap - 30. ignored signal bitmap - 31. caught signal bitmap - 32. wchan - 33. nswap - 34. cnswap - 35. exit_signal - 36. processor -*/ - -static int -readstat(int pid, char *buf, int nbuf, char **f, int nf) -{ - int fd, n; - char *p; - - snprint(buf, nbuf, "/proc/%d/stat", pid); - if((fd = open(buf, OREAD)) < 0){ - fprint(2, "open %s: %r\n", buf); - return -1; - } - n = read(fd, buf, nbuf-1); - close(fd); - if(n <= 0){ - fprint(2, "read %s: %r\n", buf); - return -1; - } - buf[n] = 0; - - /* command name is in parens, no parens afterward */ - p = strrchr(buf, ')'); - if(p == nil || *++p != ' '){ - fprint(2, "bad format in /proc/%d/stat\n", pid); - return -1; - } - ++p; - - nf = tokenize(p, f, nf); - if(0) print("code 0x%lux-0x%lux stack 0x%lux kstk 0x%lux keip 0x%lux pending 0x%lux\n", - strtoul(f[23], 0, 0), strtoul(f[24], 0, 0), strtoul(f[25], 0, 0), - strtoul(f[26], 0, 0), strtoul(f[27], 0, 0), strtoul(f[28], 0, 0)); - - return nf; -} - -static char* -readstatus(int pid, char *buf, int nbuf, char *key) -{ - int fd, n; - char *p; - - snprint(buf, nbuf, "/proc/%d/status", pid); - if((fd = open(buf, OREAD)) < 0){ - fprint(2, "open %s: %r\n", buf); - return nil; - } - n = read(fd, buf, nbuf-1); - close(fd); - if(n <= 0){ - fprint(2, "read %s: %r\n", buf); - return nil; - } - buf[n] = 0; - p = strstr(buf, key); - if(p) - return p+strlen(key); - return nil; -} - -int -procnotes(int pid, char ***pnotes) -{ - char buf[1024], *f[40]; - int i, n, nf; - char *s, **notes; - ulong sigs; - extern char *_p9sigstr(int, char*); - - *pnotes = nil; - nf = readstat(pid, buf, sizeof buf, f, nelem(f)); - if(nf <= 28) - return -1; - - sigs = strtoul(f[28], 0, 0) & ~(1<<SIGCONT); - if(sigs == 0){ - *pnotes = nil; - return 0; - } - - notes = malloc(32*sizeof(char*)); - if(notes == nil) - return -1; - memset(notes, 0, 32*sizeof(char*)); - n = 0; - for(i=0; i<32; i++){ - if((sigs&(1<<i)) == 0) - continue; - if((s = _p9sigstr(i, nil)) == nil) - continue; - notes[n++] = s; - } - *pnotes = notes; - return n; -} - -static int -realpid(int pid) -{ - char buf[1024], *p; - - p = readstatus(pid, buf, sizeof buf, "\nTgid:"); - if(p == nil) - return pid; - return atoi(p); -} - -int -ctlproc(int pid, char *msg) -{ - int new; - LinuxThread *t; - uintptr data; - - while(wait1(1) > 0) - ; - - if(strcmp(msg, "attached") == 0){ - t = attachthread(pid, pid, &new, Attached); - if(t == nil) - return -1; - return 0; - } - - if(strcmp(msg, "hang") == 0){ - if(pid == getpid()) - return ptrace(PTRACE_TRACEME, 0, 0, 0); - werrstr("can only hang self"); - return -1; - } - - t = findthread(pid); - if(t == nil) { - werrstr("not attached to pid %d", pid); - return -1; - } - if(t->state == Exited) { - werrstr("pid %d has exited", pid); - return -1; - } - if(t->state == Killed) { - werrstr("pid %d has been killed", pid); - return -1; - } - - if(strcmp(msg, "kill") == 0) { - if(ptrace(PTRACE_KILL, pid, 0, 0) < 0) - return -1; - t->state = Killed; - return 0; - } - if(strcmp(msg, "startstop") == 0){ - if(ctlproc(pid, "start") < 0) - return -1; - return waitstop(t); - } - if(strcmp(msg, "sysstop") == 0){ - if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) - return -1; - t->state = Running; - return waitstop(t); - } - if(strcmp(msg, "stop") == 0){ - if(trace > 1) - fprint(2, "tid %d: tkill stop\n", pid); - if(t->state == Stopped) - return 0; - if(syscall(__NR_tkill, pid, SIGSTOP) < 0) - return -1; - return waitstop(t); - } - if(strcmp(msg, "step") == 0){ - if(t->state == Running) { - werrstr("cannot single-step unstopped %d", pid); - return -1; - } - if(ptrace(PTRACE_SINGLESTEP, pid, 0, 0) < 0) - return -1; - return waitstop(t); - } - if(strcmp(msg, "start") == 0) { - if(t->state == Running) - return 0; - data = 0; - if(t->state == Stopped && t->signal != SIGSTOP && t->signal != SIGTRAP) - data = t->signal; - if(trace && data) - fprint(2, "tid %d: continue %lud\n", pid, (ulong)data); - if(ptrace(PTRACE_CONT, pid, 0, (void*)data) < 0) - return -1; - t->state = Running; - return 0; - } - if(strcmp(msg, "waitstop") == 0) { - return waitstop(t); - } - werrstr("unknown control message '%s'", msg); - return -1; -} - -char* -proctextfile(int pid) -{ - static char buf[1024], pbuf[128]; - - snprint(pbuf, sizeof pbuf, "/proc/%d/exe", pid); - if(readlink(pbuf, buf, sizeof buf) >= 0) - return strdup(buf); - if(access(pbuf, AEXIST) >= 0) - return strdup(pbuf); - return nil; -} - - -static int -ptracerw(int type, int xtype, int isr, int pid, uvlong addr, void *v, uint n) -{ - int i; - uintptr u, a; - uchar buf[sizeof(uintptr)]; - - for(i=0; i<n; i+=sizeof(uintptr)){ - // Tread carefully here. On recent versions of glibc, - // ptrace is a variadic function which means the third - // argument will be pushed onto the stack as a uvlong. - // This is fine on amd64 but will not work for 386. - // We must convert addr to a uintptr. - a = addr+i; - if(isr){ - errno = 0; - u = ptrace(type, pid, a, 0); - if(errno) - goto ptraceerr; - if(n-i >= sizeof(uintptr)) - memmove((char*)v+i, &u, sizeof(uintptr)); - else{ - memmove(buf, &u, sizeof u); - memmove((char*)v+i, buf, n-i); - } - }else{ - if(n-i >= sizeof(uintptr)) - u = *(uintptr*)((char*)v+i); - else{ - errno = 0; - u = ptrace(xtype, pid, a, 0); - if(errno) - return -1; - memmove(buf, &u, sizeof u); - memmove(buf, (char*)v+i, n-i); - memmove(&u, buf, sizeof u); - } - if(ptrace(type, pid, a, u) < 0) - goto ptraceerr; - } - } - return 0; - -ptraceerr: - werrstr("ptrace %s addr=%#llux pid=%d: %r", isr ? "read" : "write", addr, pid); - return -1; -} - -static int -ptracesegrw(Map *map, Seg *seg, uvlong addr, void *v, uint n, int isr) -{ - USED(seg); - - return ptracerw(isr ? PTRACE_PEEKDATA : PTRACE_POKEDATA, PTRACE_PEEKDATA, - isr, map->pid, addr, v, n); -} - -// If the debugger is compiled as an x86-64 program, -// then all the ptrace register read/writes are done on -// a 64-bit register set. If the target program -// is a 32-bit program, the debugger is expected to -// read the bottom half of the relevant registers -// out of the 64-bit set. - -// Linux 32-bit is -// BX CX DX SI DI BP AX DS ES FS GS OrigAX IP CS EFLAGS SP SS - -// Linux 64-bit is -// R15 R14 R13 R12 BP BX R11 R10 R9 R8 AX CX DX SI DI OrigAX IP CS EFLAGS SP SS FSBase GSBase DS ES FS GS - -// Go 32-bit is -// DI SI BP NSP BX DX CX AX GS FS ES DS TRAP ECODE PC CS EFLAGS SP SS - -uint go32tolinux32tab[] = { - 4, 3, 5, 15, 0, 2, 1, 6, 10, 9, 8, 7, -1, -1, 12, 13, 14, 15, 16 -}; -static int -go32tolinux32(uvlong addr) -{ - int r; - - if(addr%4 || addr/4 >= nelem(go32tolinux32tab)) - return -1; - r = go32tolinux32tab[addr/4]; - if(r < 0) - return -1; - return r*4; -} - -uint go32tolinux64tab[] = { - 14, 13, 4, 19, 5, 12, 11, 10, 26, 25, 24, 23, -1, -1, 16, 17, 18, 19, 20 -}; -static int -go32tolinux64(uvlong addr) -{ - int r; - - if(addr%4 || addr/4 >= nelem(go32tolinux64tab)) - return -1; - r = go32tolinux64tab[addr/4]; - if(r < 0) - return -1; - return r*8; -} - -extern Mach mi386; -extern Mach mamd64; - -static int -go2linux(uvlong addr) -{ - if(sizeof(void*) == 4) { - if(mach == &mi386) - return go32tolinux32(addr); - werrstr("unsupported architecture"); - return -1; - } - - if(mach == &mi386) - return go32tolinux64(addr); - if(mach != &mamd64) { - werrstr("unsupported architecture"); - return -1; - } - - switch(addr){ - case offsetof(UregAmd64, ax): - return offsetof(struct user_regs_struct, rax); - case offsetof(UregAmd64, bx): - return offsetof(struct user_regs_struct, rbx); - case offsetof(UregAmd64, cx): - return offsetof(struct user_regs_struct, rcx); - case offsetof(UregAmd64, dx): - return offsetof(struct user_regs_struct, rdx); - case offsetof(UregAmd64, si): - return offsetof(struct user_regs_struct, rsi); - case offsetof(UregAmd64, di): - return offsetof(struct user_regs_struct, rdi); - case offsetof(UregAmd64, bp): - return offsetof(struct user_regs_struct, rbp); - case offsetof(UregAmd64, r8): - return offsetof(struct user_regs_struct, r8); - case offsetof(UregAmd64, r9): - return offsetof(struct user_regs_struct, r9); - case offsetof(UregAmd64, r10): - return offsetof(struct user_regs_struct, r10); - case offsetof(UregAmd64, r11): - return offsetof(struct user_regs_struct, r11); - case offsetof(UregAmd64, r12): - return offsetof(struct user_regs_struct, r12); - case offsetof(UregAmd64, r13): - return offsetof(struct user_regs_struct, r13); - case offsetof(UregAmd64, r14): - return offsetof(struct user_regs_struct, r14); - case offsetof(UregAmd64, r15): - return offsetof(struct user_regs_struct, r15); - case offsetof(UregAmd64, ds): - return offsetof(struct user_regs_struct, ds); - case offsetof(UregAmd64, es): - return offsetof(struct user_regs_struct, es); - case offsetof(UregAmd64, fs): - return offsetof(struct user_regs_struct, fs); - case offsetof(UregAmd64, gs): - return offsetof(struct user_regs_struct, gs); - case offsetof(UregAmd64, ip): - return offsetof(struct user_regs_struct, rip); - case offsetof(UregAmd64, cs): - return offsetof(struct user_regs_struct, cs); - case offsetof(UregAmd64, flags): - return offsetof(struct user_regs_struct, eflags); - case offsetof(UregAmd64, sp): - return offsetof(struct user_regs_struct, rsp); - case offsetof(UregAmd64, ss): - return offsetof(struct user_regs_struct, ss); - } - return -1; -} - -static int -ptraceregrw(Map *map, Seg *seg, uvlong addr, void *v, uint n, int isr) -{ - int laddr; - uvlong u; - - USED(seg); - - if((laddr = go2linux(addr)) < 0){ - if(isr){ - memset(v, 0, n); - return 0; - } - werrstr("register %llud not available", addr); - return -1; - } - - if(isr){ - errno = 0; - u = ptrace(PTRACE_PEEKUSER, map->pid, laddr, 0); - if(errno) - goto ptraceerr; - switch(n){ - case 1: - *(uint8*)v = u; - break; - case 2: - *(uint16*)v = u; - break; - case 4: - *(uint32*)v = u; - break; - case 8: - *(uint64*)v = u; - break; - default: - werrstr("bad register size"); - return -1; - } - }else{ - switch(n){ - case 1: - u = *(uint8*)v; - break; - case 2: - u = *(uint16*)v; - break; - case 4: - u = *(uint32*)v; - break; - case 8: - u = *(uint64*)v; - break; - default: - werrstr("bad register size"); - return -1; - } - if(ptrace(PTRACE_POKEUSER, map->pid, laddr, (void*)(uintptr)u) < 0) - goto ptraceerr; - } - return 0; - -ptraceerr: - werrstr("ptrace %s register laddr=%d pid=%d n=%d: %r", isr ? "read" : "write", laddr, map->pid, n); - return -1; -} - -char* -procstatus(int pid) -{ - LinuxThread *t; - - t = findthread(pid); - if(t == nil) - return "???"; - - return statestr[t->state]; -} |