📄 ssp.c
字号:
/* * Copyright (c) 2000, 2001, 2002 Red Hat, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * A copy of the GNU General Public License can be found at * http://www.gnu.org/ * * Written by DJ Delorie <dj@redhat.com> * */#include <stdio.h>#include <string.h>#include <stdlib.h>#include <fcntl.h>#include <time.h>#include <ctype.h>#include <windows.h>#include <getopt.h>static const char version[] = "$Revision: 1.6 $";static char *prog_name;static struct option longopts[] ={ {"console-trace", no_argument, NULL, 'c' }, {"disable", no_argument, NULL, 'd' }, {"enable", no_argument, NULL, 'e' }, {"help", no_argument, NULL, 'h' }, {"dll", no_argument, NULL, 'l' }, {"sub-threads", no_argument, NULL, 's' }, {"trace-eip", no_argument, NULL, 't' }, {"verbose", no_argument, NULL, 'v' }, {"version", no_argument, NULL, 'V' }, {NULL, 0, NULL, 0}};static char opts[] = "cdehlstvV";#define KERNEL_ADDR 0x77000000#define TRACE_SSP 0#define VERBOSE 1#define TIMES 1000/* from winsup/gmon.h */struct gmonhdr { unsigned long lpc; /* base pc address of sample buffer */ unsigned long hpc; /* max pc address of sampled buffer */ int ncnt; /* size of sample buffer (plus this header) */ int version; /* version number */ int profrate; /* profiling clock rate */ int spare[3]; /* reserved */};#define GMONVERSION 0x00051879#define HISTCOUNTER unsigned shorttypedef struct { unsigned int base_address; int pcount; int scount; char *name;} DllInfo;typedef struct { unsigned int address; unsigned char real_byte;} PendingBreakpoints;unsigned low_pc=0, high_pc=0;unsigned last_pc=0, pc, last_sp=0, sp;int total_cycles, count;HANDLE hProcess;PROCESS_INFORMATION procinfo;STARTUPINFO startup;CONTEXT context;HISTCOUNTER *hits=0;struct gmonhdr hdr;int running = 1, profiling = 1;char dll_name[1024], *dll_ptr, *cp;int eip;unsigned opcode_count = 0;int stepping_enabled = 1;int tracing_enabled = 0;int trace_console = 0;int trace_all_threads = 0;int dll_counts = 0;int verbose = 0;#define MAXTHREADS 100DWORD active_thread_ids[MAXTHREADS];HANDLE active_threads[MAXTHREADS];DWORD thread_step_flags[MAXTHREADS];DWORD thread_return_address[MAXTHREADS];int num_active_threads = 0;int suspended_count=0;#define MAXDLLS 100DllInfo dll_info[MAXDLLS];int num_dlls=0;#define MAXPENDS 100PendingBreakpoints pending_breakpoints[MAXPENDS];int num_breakpoints=0;static voidadd_breakpoint (unsigned int address){ int i; DWORD rv; static char int3[] = { 0xcc }; for (i=0; i<num_breakpoints; i++) { if (pending_breakpoints[i].address == address) return; if (pending_breakpoints[i].address == 0) break; } if (i == MAXPENDS) return; pending_breakpoints[i].address = address; ReadProcessMemory (hProcess, (void *)address, &(pending_breakpoints[i].real_byte), 1, &rv); WriteProcessMemory (hProcess, (void *)address, (LPVOID)int3, 1, &rv); if (i >= num_breakpoints) num_breakpoints = i+1;}static intremove_breakpoint (unsigned int address){ int i; DWORD rv; for (i=0; i<num_breakpoints; i++) { if (pending_breakpoints[i].address == address) { pending_breakpoints[i].address = 0; WriteProcessMemory (hProcess, (void *)address, &(pending_breakpoints[i].real_byte), 1, &rv); return 1; } } return 0;}static HANDLElookup_thread_id (DWORD threadId, int *tix){ int i; for (i=0; i<num_active_threads; i++) if (active_thread_ids[i] == threadId) { if (tix) *tix = i; return active_threads[i]; } return 0;}static voidset_step_threads (int threadId, int trace){ int rv, tix; HANDLE thread = lookup_thread_id (threadId, &tix); rv = GetThreadContext (thread, &context); if (rv != -1) { thread_step_flags[tix] = trace; if (trace) context.EFlags |= 0x100; /* TRAP (single step) flag */ else context.EFlags &= ~0x100; /* TRAP (single step) flag */ SetThreadContext (thread, &context); }}static voidset_steps (){ int i, s; for (i=0; i<num_active_threads; i++) { GetThreadContext (active_threads[i], &context); s = context.EFlags & 0x0100; if (!s && thread_step_flags[i]) { set_step_threads (active_thread_ids[i], 1); } }}static intdll_sort (const void *va, const void *vb){ DllInfo *a = (DllInfo *)va; DllInfo *b = (DllInfo *)vb; if (a->base_address < b->base_address) return -1; return 1;}static char *addr2dllname (unsigned int addr){ int i; for (i=num_dlls-1; i>=0; i--) { if (dll_info[i].base_address < addr) { return dll_info[i].name; } } return (char *)"";}static voiddump_registers (HANDLE thread){ context.ContextFlags = CONTEXT_FULL; GetThreadContext (thread, &context); printf ("eax %08lx ebx %08lx ecx %08lx edx %08lx eip\n", context.Eax, context.Ebx, context.Ecx, context.Edx); printf ("esi %08lx edi %08lx ebp %08lx esp %08lx %08lx\n", context.Esi, context.Esi, context.Ebp, context.Esp, context.Eip);}typedef struct Edge { struct Edge *next; unsigned int from_pc; unsigned int to_pc; unsigned int count;} Edge;Edge *edges[4096];voidstore_call_edge (unsigned int from_pc, unsigned int to_pc){ Edge *e; unsigned int h = ((from_pc + to_pc)>>4) & 4095; for (e=edges[h]; e; e=e->next) if (e->from_pc == from_pc && e->to_pc == to_pc) break; if (!e) { e = (Edge *)malloc (sizeof (Edge)); e->next = edges[h]; edges[h] = e; e->from_pc = from_pc; e->to_pc = to_pc; e->count = 0; } e->count++;}voidwrite_call_edges (FILE *f){ int h; Edge *e; for (h=0; h<4096; h++) for (e=edges[h]; e; e=e->next) fwrite (&(e->from_pc), 1, 3*sizeof (unsigned int), f);}char *wide_strdup (char *cp){ unsigned short *s = (unsigned short *)cp; int len; char *rv; for (len=0; s[len]; len++); rv = (char *)malloc (len+1); for (len=0; s[len]; len++) rv[len] = s[len]; rv[len] = 0; return rv;}voidrun_program (char *cmdline){ FILE *tracefile = 0; int tix, i; HANDLE hThread; char *string; memset (&startup, 0, sizeof (startup)); startup.cb = sizeof (startup); if (!CreateProcess (0, cmdline, 0, 0, 0, CREATE_NEW_PROCESS_GROUP | CREATE_SUSPENDED | DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS, 0, 0, &startup, &procinfo)) { fprintf (stderr, "Can't create process: error %ld\n", GetLastError ()); exit (1); } hProcess = procinfo.hProcess;#if 0 printf ("procinfo: %08x %08x %08x %08x\n", hProcess, procinfo.hThread, procinfo.dwProcessId, procinfo.dwThreadId);#endif active_threads[0] = procinfo.hThread; active_thread_ids[0] = procinfo.dwThreadId; thread_step_flags[0] = stepping_enabled; num_active_threads = 1; dll_info[0].base_address = 0; dll_info[0].pcount = 0; dll_info[0].scount = 0; dll_info[0].name = cmdline; num_dlls = 1; SetThreadPriority (procinfo.hThread, THREAD_PRIORITY_IDLE); context.ContextFlags = CONTEXT_FULL; ResumeThread (procinfo.hThread); total_cycles = 0; if (tracing_enabled) { tracefile = fopen ("trace.ssp", "w"); if (!tracefile) { tracing_enabled = 0; perror ("trace.ssp"); } } running = 1; while (running) { int src, dest; DWORD rv; DEBUG_EVENT event; int contv = DBG_CONTINUE; event.dwDebugEventCode = -1; if (!WaitForDebugEvent (&event, INFINITE)) { printf ("idle...\n"); } hThread = lookup_thread_id (event.dwThreadId, &tix);#if 0 printf ("DE: %x/%d %d %d ", hThread, tix, event.dwDebugEventCode, num_active_threads); for (src=0; src<num_active_threads; src++) { int sc = SuspendThread (active_threads[src]); int rv = GetThreadContext (active_threads[src], &context); ResumeThread (active_threads[src]); printf (" [%x,%x,%x]", active_threads[src], context.Eip, active_thread_ids[src]); } printf ("\n");#endif switch (event.dwDebugEventCode) { case CREATE_PROCESS_DEBUG_EVENT: break; case CREATE_THREAD_DEBUG_EVENT: if (verbose) printf ("create thread %08lx at %08x %s\n", event.dwThreadId, (int)event.u.CreateThread.lpStartAddress, addr2dllname ((unsigned int)event.u.CreateThread.lpStartAddress)); active_thread_ids[num_active_threads] = event.dwThreadId; active_threads[num_active_threads] = event.u.CreateThread.hThread; thread_return_address[num_active_threads] = 0; num_active_threads++; if (trace_all_threads && stepping_enabled) { thread_step_flags[num_active_threads-1] = stepping_enabled; add_breakpoint ((int)event.u.CreateThread.lpStartAddress); } break; case EXIT_THREAD_DEBUG_EVENT: if (verbose) printf ("exit thread %08lx, code=%ld\n", event.dwThreadId, event.u.ExitThread.dwExitCode); for (src=0, dest=0; src<num_active_threads; src++) if (active_thread_ids[src] != event.dwThreadId) { active_thread_ids[dest] = active_thread_ids[src]; active_threads[dest] = active_threads[src]; dest++; } num_active_threads = dest; break; case EXCEPTION_DEBUG_EVENT: rv = GetThreadContext (hThread, &context); switch (event.u.Exception.ExceptionRecord.ExceptionCode) { case STATUS_BREAKPOINT: if (remove_breakpoint ((int)event.u.Exception.ExceptionRecord.ExceptionAddress)) { context.Eip --; if (!rv) SetThreadContext (hThread, &context); if (ReadProcessMemory (hProcess, (void *)context.Esp, &rv, 4, &rv)) thread_return_address[tix] = rv; } set_step_threads (event.dwThreadId, stepping_enabled); case STATUS_SINGLE_STEP: opcode_count++; pc = (unsigned int)event.u.Exception.ExceptionRecord.ExceptionAddress; sp = (unsigned int)context.Esp; if (tracing_enabled) fprintf (tracefile, "%08x %08lx\n", pc, event.dwThreadId); if (trace_console) { printf ("%d %08x\n", tix, pc); fflush (stdout); } if (dll_counts) { int i; for (i=num_dlls-1; i>=0; i--) { if (dll_info[i].base_address < context.Eip) { if (hThread == procinfo.hThread) dll_info[i].pcount++; else dll_info[i].scount++; break; } } } if (pc < last_pc || pc > last_pc+10) { static int ncalls=0; static int qq=0; if (++qq % 100 == 0) fprintf (stderr, " %08x %d %d \r", pc, ncalls, opcode_count); if (sp == last_sp-4) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -