📄 trace-x86.c
字号:
* All went well */ return (1);} /* x86stepIntoDebug() *//*x86stepOverDebug() Single step our program, stepping past any subroutinesInputs: ws - debug workspace num - number of instructions to step over data - modified to contain info depending on the return result, see belowReturn: 0 if unsuccessful 1 if successful 2 if program stops due to a signal 3 if breakpoint encountered 4 if program terminatesSide effects: If the process stops due to a signal, data is modified to contain the signal number. If the process stops due to a breakpoint, data is modified to contain the breakpoint number. If the process terminates normally, data is modified to contain the exit status.*/intx86stepOverDebug(struct debugWorkspace *ws, int num, int *data){ int ii, dret, /* return value from dump memory routine */ pret; /* return value from a ptrace function */ unsigned long slen; /* length of subroutine call opcode */ unsigned char *opbuf; /* contains potential call opcode */ assert(num > 0); if (ws->pid == NOPID) { int ret; ret = x86execDebug(ws); if (ret == 2) return (6); /* not an executable file */ else if (ret == 0) return (0); /* something went wrong */ } dbSetRunning(ws); for (ii = 0; ii < num; ++ii) { slen = 0; opbuf = 0; /* * Dump 20 bytes of memory so we can tell if we are about * to enter a subroutine */ dret = x86dumpMemoryDebug(ws, &opbuf, ws->instructionPointer, 20); if (opbuf) { if (dret > 0) slen = IsSubroutine(opbuf); free(opbuf); } if (slen) { int bret; unsigned long baddr; /* * We are about to enter a subroutine - set a breakpoint * at location ws->instructionPointer + slen. */ baddr = (unsigned long) (ws->instructionPointer + slen); bret = setAndSaveBreakpoint(ws, baddr, BK_TEMPORARY | BK_STEPOVER); /* * Now continue until we hit the breakpoint */ pret = x86DoContinue(ws, data); if (pret == 3) { if (*data == 0) { /* * A value of 0 means we hit the temporary breakpoint * at the address after the call instruction - so we * do not need to inform the user about it. Continue * stepping. */ continue; } /* * It is most likely a breakpoint which was set inside * of the subroutine we were trying to step over. It * could also be a breakpoint at the exact address we set * our temporary breakpoint. */ return (3); } else { /* * 'data' will have been set appropriately by * x86GetDebugProcessStatus() */ return (pret); } } /* if (slen) */ /* * We are not about to enter a subroutine - just step * one instruction */ pret = x86DoSingleStep(ws, data); if (pret != 1) { /* * Something happened (signal, breakpoint, exit, etc) */ return (pret); } } /* for (ii = 0; ii < num; ++ii) */ /* * All went well */ return (1);} /* x86stepOverDebug() *//*x86continueDebug() Continue the debugged process where it left offInputs: ws - debug workspace data - modified to contain info depending on return valueReturn: 0 if unsuccessful 1 if successful 2 if program stops due to a signal (signal put into data) 3 if breakpoint encountered (brk pt number put into data) 4 if program terminates (exit status put into data) 6 if program is not executable 7 if program terminates due to a signal (signal num put into data)*/intx86continueDebug(struct debugWorkspace *ws, int *data){ if (ws->pid == NOPID) { int ret; ret = x86execDebug(ws); if (ret == 2) return (6); /* not an executable file */ else if (ret == 0) return (0); /* something went wrong */ } dbSetRunning(ws); return (x86DoContinue(ws, data));} /* x86continueDebug() *//*x86attachDebug() Attach to a currently running processInputs: ws - debug workspace pid - process idReturn: 1 if successful, 0 if not*/intx86attachDebug(struct debugWorkspace *ws, int pid){ int err; int waitval; if (ptrace(PT_ATTACH, pid, 0, 0) != 0) return (0); /* something went wrong */ wait(&waitval); ws->pid = (pid_t) pid; /* * Set the instruction pointer to the program's current position */ err = 0; ws->instructionPointer = x86getCurrentInstruction(ws, &err); if (err) { /* * The most likely cause of this is that the file is not * executable */ ws->pid = NOPID; return (0); } dbSetAttached(ws); dbSetRunning(ws); return (1);} /* x86attachDebug() *//*x86detachDebug() Detach from current processInputs: ws - debug workspaceReturn: -1 if not currently attached 0 if ptrace fails pid of detached process if successful*/intx86detachDebug(struct debugWorkspace *ws){ int waitval; int pid; if (!dbIsAttached(ws)) return (-1); if (ptrace(PT_DETACH, ws->pid, 0, 0) != 0) return (0); /* something went wrong */ wait(&waitval); pid = ws->pid; ws->pid = NOPID; dbClearAttached(ws); dbClearRunning(ws); return (pid);} /* x86detachDebug() *//*x86killDebug() Kill current debugged processReturn: 1 if successful 0 if not*/intx86killDebug(struct debugWorkspace *ws){ int ret; int waitval; if (ws->pid != NOPID) { ret = ptrace(PT_KILL, ws->pid, 0, 0); if (ret == 0) wait(&waitval); } return (1);} /* x86killDebug() *//*x86saveBreakpoint() Save the contents of a breakpoint's memory location, so we can restore it laterInputs: ws - debug workspace bptr - breakpoint structure containing infoReturn: 1 if successful 0 if not*/intx86saveBreakpoint(struct debugWorkspace *ws, struct Breakpoint *bptr){ int saved; /* saved instruction */ assert(bptr != 0); assert(ws->pid != NOPID);#if 0 if (ws->pid == NOPID) { if (x86execDebug(ws) == 0) return (0); /* something went wrong */ }#endif /* * Save lowest byte of the dword at the break address */ saved = PtraceRead(ws->pid, bptr->address, 0); if (saved == (-1)) return (0); /* error - most likely EIO */ bptr->svdinsn = saved; return (1);} /* x86saveBreakpoint() *//*x86enableBreakpoint() Enable breakpoint by setting the first byte of it'smemory address to the breakpoint instructionReturn: 1 if successful 0 if not*/intx86enableBreakpoint(struct debugWorkspace *ws, struct Breakpoint *bptr){ int insn; int data; assert(ws->pid != NOPID); assert(bptr != 0); /* * We must read the contents of bptr->address again, even though we have * previously saved the contents of that location. The reason for this is * the following scenario: If we set 2 breakpoints, within 4 bytes of each other, * when we enable the first, we stick a 0xCC in the first byte of it's location. * If the second breakpoint occurs before the first in memory, we will overwrite * the original 0xCC when writing the modified word for the second breakpoint. * Unfortunately, ptrace cannot be used to write a single byte without disturbing * adjacent bytes. */ data = PtraceRead(ws->pid, bptr->address, 0); if (data == (-1)) return (0); /* error - most likely EIO */ /* * This is little-endian specific */ insn = (data & ~0x000000FF) | BRKPT_INSN;#if 0 insn = (bptr->svdinsn & ~0xFF) | BRKPT_INSN;#endif /* * Replace the instruction with our breakpoint instruction */ if (PtraceWrite(ws->pid, bptr->address, insn) != 0) return (0); return (1);} /* x86enableBreakpoint() *//*x86disableBreakpoint() Restore breakpoint address with it's original instructionReturn: 1 if successful 0 if not*/intx86disableBreakpoint(struct debugWorkspace *ws, struct Breakpoint *bptr){ assert(ws->pid != NOPID); assert(bptr != 0); /* * Replace the instruction with our saved instruction */ if (PtraceWrite(ws->pid, bptr->address, bptr->svdinsn) != 0) return (0); return (1);} /* x86disableBreakpoint() *//*x86dumpMemoryDebug() Dump memory contents of debugged processInputs: ws - debug workspace buf - buffer to store memory bytes in start - address to start dump bytes - number of bytes to dumpReturn: number of bytes dumped - if this is less than 'bytes', an error occurred, and errno should be set appropriately.Side effects: space is allocated for 'buf', so it must be freed by the calling function*/longx86dumpMemoryDebug(struct debugWorkspace *ws, unsigned char **buf, unsigned long start, unsigned long bytes){ int wordval; unsigned long addr, /* current address we are examining */ end; /* last address to examine */ unsigned char *bufptr; long ret; /* return value */ if (ws->pid == NOPID) { if (x86execDebug(ws) == 0) return (0); /* something went wrong */ } addr = start; end = start + bytes; if (end < start) return (0); /* integer overflow */ if ((bytes + 1) == 0) return (0); /* integer overflow */ *buf = (char *) malloc(bytes + 1); if (*buf == NULL) return (0); bufptr = (unsigned char *) *buf; ret = 0; while (addr < end) { wordval = PtraceRead(ws->pid, addr, 0); if ((wordval == (-1)) && (errno == EIO)) { /* * Input/output error */ return (ret); } /* * The ptrace() call will return a 2 byte (word) value on * intel systems, and little-endian will put the byte at * the address 'addr' last, so anding with 0xff will separate * that byte. */ *bufptr++ = (unsigned char) (wordval & 0xff); ++addr; ++ret; } /* while (addr <= end) */ *bufptr = '\0'; return (ret);} /* x86dumpMemoryDebug() *//*x86setMemoryDebug() Set the contents of memory location 'address' to 'value'Inputs: ws - debug workspace address - memory address value - value to setReturn: 0 if unsuccessful (ptrace error) number of bytes written if successful*/intx86setMemoryDebug(struct debugWorkspace *ws, unsigned long address, unsigned long value){ int wordval; int ret; unsigned int mask; if (ws->pid == NOPID) { if (x86execDebug(ws) == 0) return (0); /* something went wrong */ } /* * An interesting note about ptrace() - although it is documented * to return a "word", it actually returns the size of an int, * in this case 32 bits, when it should actually return 16 bits, * the size of an intel word. * This works for PtraceWrite() too - it writes a 32 bit quantity * to the address you specify. */ wordval = PtraceRead(ws->pid, address, 0); if (wordval == (-1)) return (0); ret = 0; /* * Determine how many bytes the calling program wants to write * to memory - if we simply try to write the 32 bit quantity * 'value', and it is a 1 byte number, we will overwrite 3 bytes * of memory with zeros */ if ((value & 0xff) == value) { ret = 1; /* we are setting 1 byte */ mask = 0xffffff00; } else if ((value & 0xffff) == value) { ret = 2; /* we are setting 2 bytes */ mask = 0xffff0000; } else if ((value & 0xffffff) == value) { ret = 3; /* we are setting 3 bytes */ mask = 0xff000000; } else { ret = 4; /* we are setting 4 bytes */ mask = 0x00000000; } /* * Clear the byte(s) we are about to change */ wordval &= mask; /* * Set the new byte(s) */ wordval |= value; if (PtraceWrite(ws->pid, address, wordval) != 0) return (0); return (ret);} /* x86setMemoryDebug() */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -