📄 yamd.c
字号:
{ log_detail(level, "Seems not to be associated with any block.\n"); }}void__yamd_describe_address(void *a){ /* HACK HACK HACK */ /* This is intended for debuggers, so make it show up. */ int ofd; int oll; log_flush(); ofd = log_fd; log_fd = 2; /* stderr */ oll = min_log_level; min_log_level = 0; describe_address(LOG_INFO, (addr)a); log_flush(); log_fd = ofd; min_log_level = oll;}/* Hmm. This is probably not overly safe; we call printf and such from within a signal handler. If the crash was inside a stdio function, its state might be funny and things could get very screwed up. */static void disclaimer(void){ static char message[] = "This appears to be a non-malloc bug, dumping core\n"; write(2, message, sizeof(message)); signal(SIGSEGV, SIG_DFL); return;}#ifdef __linux__#ifdef __i386__static void sigsegv_handler(int signum, struct sigcontext ctx){ (void)signum; /* shut the compiler up */ /* Find out if this is a fault we're trying to catch */ if (ctx.trapno != 14 /* Not a page fault */ || !(ctx.err & 4)) /* Not a user access */ { disclaimer(); return; } /* Note that using cr2 here assumes that the base of DS is 0. Thank God for systems with real memory mapping... */ handle_page_fault(ctx.cr2, ctx.err & 2, ctx.eip, ctx.ebp); return; /* Resume the faulting instruction; it may or may not have been fixed up */}#endif#endif#ifdef DJGPP_SIGNAL/* Curses. None of this clever hackish stuff works, since CWSDPMI zeroes out cr2 for its own purposes. Getting the faulting cr2 is probably going to require hacking of CWSDPMI itself, or writing a newer-style exception handler (only for DPMI 1.0 and not supported by CWSDPMI). So at present, let's just leave this stuff out and let the debuggers handle it. */static intget_ring(void){ unsigned long desc[2]; if (__dpmi_get_descriptor(_my_cs(), desc) < 0) return -1; /* DPL is bits 13 and 14 of upper word */ return (desc[1] >> 13) & 0x2;}static voidsigsegv_handler(int sig){ unsigned long cr2; unsigned long err_code; (void)sig; /* shut the compiler up */#ifdef DEBUG printf("In signal handler\n");#endif /* Misnamed; member `signum' is really the exception number. 14 == page fault. */ if (__djgpp_exception_state->__signum != 14) {#ifdef DEBUG printf("Bad exception number %ld\n", __djgpp_exception_state->__signum);#endif disclaimer(); return; } if (get_ring() != 0) return; /* without cr2 we can't do much */ asm("movl %%cr2, %0" : "=r" (cr2)); /* Undocumented feature. From dpmiexcp.c-- MAY CHANGE! */ err_code = __djgpp_exception_state->__sigmask & 0xffff; /* cr2 is linear address, so we must adjust. */#ifdef DEBUG printf("cr2 = %#08lx\n", cr2); printf("base = %#08lx\n", (unsigned long)__djgpp_base_address); printf("eip = %#08lx\n", __djgpp_exception_state->__eip); printf("ebp = %#08lx\n", __djgpp_exception_state->__ebp); printf("err = %lx\n", err_code);#endif handle_page_fault(cr2 - __djgpp_base_address, err_code & 2, __djgpp_exception_state->__eip, __djgpp_exception_state->__ebp); return; /* and die! */}#endifstatic voidhandle_page_fault(addr address, int write, addr eip, addr ebp){ block *b; if (SHOULD_NOT_CATCH) { /* If YAMD shouldn't run, we're probably inside it and so the crash was caused by us. */ signal(SIGSEGV, SIG_DFL); return; } NO_CATCH(); /* is this really correct? */ if (!(b = find_block_by_any_addr(address))) { disclaimer(); return; } signal(SIGSEGV, SIG_DFL); log_event(LOG_ERR, "Crash"); do_any_traceback(LOG_ERR, eip, ebp, 0); log_detail(LOG_ERR, "Tried to %s address " POINTER_FORMAT "\n", (write) ? "write" : "read", address); describe_address(LOG_ERR, address); log_detail(LOG_ERR, "Will dump core after checking heap.\n"); check_heap();#if 0 /* Tread lightly on the core dump */ print_footer();#endif log_flush(); return; /* Resume the faulting instruction */}#define ENVIRON_INT 1#define ENVIRON_STRING 2struct environment_entry { char *name; int type; void *valuep;};static struct environment_entry environment_entries[] = { { "DEFAULT_ALIGNMENT", ENVIRON_INT, &default_alignment }, { "LOGFILE_NAME", ENVIRON_STRING, &logfile_name }, { "LOGFILE", ENVIRON_STRING, &logfile_name }, /* nicer for users */ { "LOGLEVEL", ENVIRON_INT, &min_log_level }, { "REPAIR_CORRUPTED", ENVIRON_INT, &repair_corrupted }, { "DIE_ON_CORRUPTED", ENVIRON_INT, &die_on_corrupted }, { "CHECK_FRONT", ENVIRON_INT, &check_front },#ifdef COMPLETE_MAGIC { "COMPLETE_MAGIC", ENVIRON_INT, &complete_magic },#endif { NULL, 0, NULL }};static voidparse_environment(void){ char buf[200]; struct environment_entry *env; for (env = environment_entries; env->name != NULL; env++) { char *p; strcpy(buf, ENVIRONMENT_PREFIX); strcat(buf, env->name); p = getenv(buf); if (p) { switch(env->type) { case ENVIRON_INT: { int t; char *tp; t = strtol(p, &tp, 0); if (tp) *(int *)env->valuep = t; break; } case ENVIRON_STRING: *(const char **)env->valuep = p; break; } } }}/* Set LD_PRELOAD for exec'd programs, possibly to prevent children from having YAMD loaded. */static void set_child_preload(void){ /* YAMD_CHILD_LD_PRELOAD is set for us by the shell script. */ char *s; s = getenv("YAMD_CHILD_LD_PRELOAD"); if (s) { if (strlen(s) != 0) { char *newbuf; newbuf = alloca(strlen(LD_PRELOAD_ENV) + 1 + strlen(s) + 1); /* '=' '\0' */ strcpy(newbuf, LD_PRELOAD_ENV); strcat(newbuf, "="); strcat(newbuf, s); putenv(newbuf); } else { putenv(LD_PRELOAD_ENV); /* unset it */ } }}/* Return process size in K. */#ifdef __linux__static unsigned long process_size(void){ FILE *f; unsigned long s; char buf[100]; f = fopen("/proc/self/status", "r"); if (!f) return 0; while (fgets(buf, 100, f) != NULL) { if (sscanf(buf, "VmSize: %lu", &s) == 1) return s; } return 0;}#endif#ifdef __DJGPP__static unsigned long process_size(void){ /* Probably not accurate. mprotect(PROT_NONE) will uncommit pages, meaning they will not be swapped out and are effectively freed (since when physical memory becomes full they will be discarded and reused). This has the effect of creating holes in the memory map, so we're not actually using all the memory in this range. */ return (((unsigned long)sbrk(0)) - 0x1000) / 1024;}#endifstatic void print_footer(void){ time_t t; time(&t); /* ctime's string ends in \n */ log_printf("\n*** Finished at %s", ctime(&t)); log_printf("Allocated a grand total of %lu bytes\n", (unsigned long)user_allocated); log_printf("%lu allocations\n", n_allocations); log_printf("Average of %lu bytes per allocation\n", user_allocated / (n_allocations ? n_allocations : 1)); log_printf("Max bytes allocated at one time: %lu\n", (unsigned long)max_user_allocated); log_printf("%lu K alloced internally / %lu K mapped now / %lu K max\n", (unsigned long)internal_allocated / 1024, (unsigned long)internal_mapped / 1024, (unsigned long)max_internal_mapped / 1024);#ifdef HASH_PROFILE hash_profile();#endif log_printf("Virtual program size is %lu K\n", process_size()); log_printf("End.\n");}static void check_memory_leaks(void){ block *p; int nleaks = 0; unsigned long nbytes = 0; for_each_block(p) { /* Don't complain that libc is leaking memory. */ if (p->who_alloced != BY_ALLOCA && p->who_alloced != BY_LITE && p->who_freed == BY_NONE) { nleaks++; nbytes += p->user_size; log_event(LOG_WARN, "Memory leak"); describe_block(LOG_WARN, p); } } if (nleaks) { log_event(LOG_WARN, "Total memory leaks:"); log_detail(LOG_WARN, "%d unfreed allocations totaling %lu bytes\n", nleaks, nbytes); }}static void print_header(void){ time_t t; log_printf("YAMD version %s\n", YAMD_VERSION); log_printf("Starting run: ");#ifdef __linux__ { FILE *cmdline; char buf[PATH_MAX]; int len; cmdline = fopen("/proc/self/cmdline", "r"); if (cmdline) { int c; while ((c = getc(cmdline)) != EOF) { if (c == 0) c = ' '; /* null separation in use */ /* Well, this oughta be plenty slow. Would log_putc be a good idea, or should I use a real buffer here? */ log_printf("%c", c); } fclose(cmdline); } else log_printf("<unknown>"); log_printf("\n"); /* This will only be useful if they have the new dcache in the kernel (since mid 2.1 but not in 2.0). */ len = readlink("/proc/self/exe", buf, PATH_MAX); if (len < 0) strcpy(buf, "<unknown>"); else buf[len] = '\0'; /* readlink does not null-terminate. */ log_printf("Executable: %s\n", buf); }#endif#ifdef __DJGPP__ { int i; for (i = 0; i < __crt0_argc; i++) log_printf("%s ", __crt0_argv[i]); log_printf("\nExecutable: %s\n", __crt0_argv[0]); }#endif log_printf("Virtual program size is %lu K\n", process_size()); time(&t); log_printf("Time is %s\n", ctime(&t));#define PRINT_VAR(v) log_printf("%s = %d\n", #v, v) PRINT_VAR(default_alignment); PRINT_VAR(min_log_level); PRINT_VAR(repair_corrupted); PRINT_VAR(die_on_corrupted); PRINT_VAR(check_front);#ifdef COMPLETE_MAGIC PRINT_VAR(complete_magic);#endif#undef PRINT_VAR}#ifdef USE_LIBC_HOOKSstatic void start_catching(void){ OK_CATCH();}void (*__malloc_initialize_hook)(void) = start_catching;#endif/* HACK HACK HACK HACK HACK HACK HACK *//* We want `startup' to be run before any constructors, and `finish' after all destructors and `atexit' functions. The order depends in part on link order. Therefore we call these from all possible places, and get the first or last as appropriate. */void __yamd_maybe_startup(void){ static int have_run = 0; if (!have_run) { have_run = 1; atexit(__yamd_maybe_finish); startup(); } else return;}void __yamd_maybe_finish(void){ static int tries = 0; if (++tries == TRIES_FOR_FINISH) /* This is the last try */ finish(); else return;}/* This file will be linked either first or last, so let's have a shot at constructing. */static void construct(void) __attribute__((constructor));static void construct(void) { __yamd_maybe_startup(); }static void destruct(void) __attribute__((destructor));static void destruct(void) { __yamd_maybe_finish(); }static void startup(void) { static int initted = 0; if (initted) { fprintf(stderr, "Initted multiple times! Can't happen\n"); return; } initted = 1; /* We are in lite mode. */ parse_environment(); set_child_preload(); if (strcmp(logfile_name, "-") == 0) { log_fd = 2; } else { /* Would other perms. be a good idea? */ log_fd = open(logfile_name, O_WRONLY | O_CREAT | O_TRUNC, 0600); if (log_fd < 0) { perror(logfile_name); return; } } print_header();#ifdef __DJGPP__#ifdef DJGPP_SIGNAL#ifdef DEBUG printf("Running in ring %d\n", get_ring());#endif /* DEBUG */ if (get_ring() == 0) signal(SIGSEGV, sigsegv_handler);#endif /* DJGPP_SIGNAL */#else signal(SIGSEGV, (void (*)(int))sigsegv_handler); #endif /* __DJGPP__ */ mode = FULL_MODE; /* go go go! */}static void finish(void){ mode = LITE_MODE; signal(SIGSEGV, SIG_DFL); check_heap(); /* One last time... */ check_memory_leaks(); print_footer(); log_flush(); close(log_fd);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -