debug.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. /*
  2. * debug.c -- handles:
  3. * signal handling
  4. * Context handling
  5. * debug funtions
  6. *
  7. */
  8. #include "common.h"
  9. #include "debug.h"
  10. #include "chanprog.h"
  11. #include "net.h"
  12. #include "shell.h"
  13. #include "color.h"
  14. #include "userrec.h"
  15. #include "main.h"
  16. #include "dccutil.h"
  17. #include <setjmp.h>
  18. #include <signal.h>
  19. #include <sys/types.h>
  20. #include <sys/stat.h>
  21. #include <fcntl.h>
  22. #include <sys/time.h>
  23. #include <sys/resource.h>
  24. #include <unistd.h>
  25. #include <stdarg.h>
  26. #include <errno.h>
  27. #include <sys/mman.h>
  28. #define PAGESIZE 4096
  29. int sdebug = 0; /* enable debug output? */
  30. #ifdef DEBUG_CONTEXT
  31. /* Context storage for fatal crashes */
  32. char cx_file[16][15];
  33. char cx_note[16][21];
  34. int cx_line[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  35. int cx_ptr = 0;
  36. #endif /* DEBUG_CONTEXT */
  37. void setlimits()
  38. {
  39. #ifndef CYGWIN_HACKS
  40. struct rlimit plim, fdlim, corelim;
  41. #ifndef DEBUG_MEM
  42. /* struct rsslim, stacklim;
  43. rsslim.rlim_cur = 30720;
  44. rsslim.rlim_max = 30720;
  45. setrlimit(RLIMIT_RSS, &rsslim);
  46. stacklim.rlim_cur = 30720;
  47. stacklim.rlim_max = 30720;
  48. setrlimit(RLIMIT_STACK, &stacklim);
  49. */
  50. /* do NOT dump a core. */
  51. plim.rlim_cur = 40;
  52. plim.rlim_max = 40;
  53. corelim.rlim_cur = 0;
  54. corelim.rlim_max = 0;
  55. #else /* DEBUG_MEM */
  56. plim.rlim_cur = 80;
  57. plim.rlim_max = 80;
  58. corelim.rlim_cur = RLIM_INFINITY;
  59. corelim.rlim_max = RLIM_INFINITY;
  60. #endif /* !DEBUG_MEM */
  61. setrlimit(RLIMIT_CORE, &corelim);
  62. setrlimit(RLIMIT_NPROC, &plim);
  63. fdlim.rlim_cur = 200;
  64. fdlim.rlim_max = 200;
  65. setrlimit(RLIMIT_NOFILE, &fdlim);
  66. #endif /* !CYGWIN_HACKS */
  67. }
  68. void init_debug()
  69. {
  70. int i = 0;
  71. for (i = 0; i < 16; i ++)
  72. Context;
  73. #ifdef DEBUG_CONTEXT
  74. egg_bzero(&cx_file, sizeof cx_file);
  75. egg_bzero(&cx_note, sizeof cx_note);
  76. #endif /* DEBUG_CONTEXT */
  77. }
  78. void sdprintf (char *format, ...)
  79. {
  80. if (sdebug) {
  81. char s[2001] = "";
  82. va_list va;
  83. va_start(va, format);
  84. egg_vsnprintf(s, 2000, format, va);
  85. va_end(va);
  86. if (!backgrd)
  87. dprintf(DP_STDOUT, "[D:%d] %s%s%s\n", getpid(), BOLD(-1), s, BOLD_END(-1));
  88. else
  89. printf("[D:%d] %s%s%s\n", getpid(), BOLD(-1), s, BOLD_END(-1));
  90. }
  91. }
  92. #ifdef DEBUG_CONTEXT
  93. static int nested_debug = 0;
  94. void write_debug()
  95. {
  96. int x;
  97. char s[25] = "", tmpout[150] = "", buf[DIRMAX] = "";
  98. int y;
  99. if (nested_debug) {
  100. /* Yoicks, if we have this there's serious trouble!
  101. * All of these are pretty reliable, so we'll try these.
  102. *
  103. * NOTE: dont try and display context-notes in here, it's
  104. * _not_ safe <cybah>
  105. */
  106. sprintf(buf, "%sDEBUG.DEBUG", tempdir);
  107. x = creat(buf, 0600);
  108. setsock(x, SOCK_NONSOCK);
  109. if (x >= 0) {
  110. strncpyz(s, ctime(&now), sizeof s);
  111. dprintf(-x, "Debug (%s) written %s\n", ver, s);
  112. dprintf(-x, "Context: ");
  113. cx_ptr = cx_ptr & 15;
  114. for (y = ((cx_ptr + 1) & 15); y != cx_ptr; y = ((y + 1) & 15))
  115. dprintf(-x, "%s/%d,\n ", cx_file[y], cx_line[y]);
  116. dprintf(-x, "%s/%d\n\n", cx_file[y], cx_line[y]);
  117. killsock(x);
  118. close(x);
  119. }
  120. #ifndef CYGWIN_HACKS
  121. {
  122. /* Use this lame method because shell_exec() or mail() may have caused another segfault :o */
  123. char buff[255] = "";
  124. egg_snprintf(buff, sizeof(buff), "cat << EOFF >> %sbleh\nNDEBUG from: %s\n`date`\n`w`\n---\n`who`\n---\n`ls -al`\n---\n`ps ux`\n---\n`uname -a`\n---\n`id`\n---\n`cat %s`\nEOFF", tempdir, origbotname, buf);
  125. system(buff);
  126. egg_snprintf(buff, sizeof(buff), "cat %sbleh |mail wraith@shatow.net", tempdir);
  127. system(buff);
  128. unlink("bleh");
  129. }
  130. #endif /* !CYGWIN_HACKS */
  131. unlink(buf);
  132. exit(1); /* Dont even try & tell people about, that may
  133. have caused the fault last time. */
  134. } else {
  135. nested_debug = 1;
  136. }
  137. egg_snprintf(tmpout, sizeof tmpout, "* Last 3 contexts: %s/%d [%s], %s/%d [%s], %s/%d [%s]",
  138. cx_file[cx_ptr-2], cx_line[cx_ptr-2], cx_note[cx_ptr-2][0] ? cx_note[cx_ptr-2] : "",
  139. cx_file[cx_ptr-1], cx_line[cx_ptr-1], cx_note[cx_ptr-1][0] ? cx_note[cx_ptr-1] : "",
  140. cx_file[cx_ptr], cx_line[cx_ptr], cx_note[cx_ptr][0] ? cx_note[cx_ptr] : "");
  141. putlog(LOG_MISC, "*", "%s", tmpout);
  142. printf("%s\n", tmpout);
  143. sprintf(buf, "%sDEBUG", tempdir);
  144. x = creat(buf, 0600);
  145. setsock(x, SOCK_NONSOCK);
  146. if (x < 0) {
  147. putlog(LOG_MISC, "*", "* Failed to write DEBUG");
  148. } else {
  149. char date[80] = "";
  150. strncpyz(s, ctime(&now), sizeof s);
  151. dprintf(-x, "Debug (%s) written %s\n", ver, s);
  152. egg_strftime(date, sizeof date, "%c %Z", gmtime(&buildts));
  153. dprintf(-x, "Build: %s (%lu)\n", date, buildts);
  154. stackdump(-x);
  155. dprintf(-x, "Context: ");
  156. cx_ptr = cx_ptr & 15;
  157. for (y = ((cx_ptr + 1) & 15); y != cx_ptr; y = ((y + 1) & 15))
  158. dprintf(-x, "%s/%d, [%s]\n ", cx_file[y], cx_line[y],
  159. (cx_note[y][0]) ? cx_note[y] : "");
  160. dprintf(-x, "%s/%d [%s]\n\n", cx_file[cx_ptr], cx_line[cx_ptr],
  161. (cx_note[cx_ptr][0]) ? cx_note[cx_ptr] : "");
  162. tell_dcc(-x);
  163. dprintf(-x, "\n");
  164. tell_netdebug(-x);
  165. killsock(x);
  166. close(x);
  167. #ifndef CYGWIN_HACKS
  168. {
  169. char *w = NULL, *who = NULL, *ps = NULL, *uname = NULL,
  170. *id = NULL, *ls = NULL, *debug = NULL, *msg = NULL, buf2[DIRMAX] = "";
  171. egg_strftime(date, sizeof date, "%c %Z", gmtime(&now));
  172. shell_exec("w", NULL, &w, NULL);
  173. shell_exec("who", NULL, &who, NULL);
  174. shell_exec("ps cux", NULL, &ps, NULL);
  175. shell_exec("uname -a", NULL, &uname, NULL);
  176. shell_exec("id", NULL, &id, NULL);
  177. shell_exec("ls -al", NULL, &ls, NULL);
  178. buf2[0] = 0;
  179. sprintf(buf2, "cat %s", buf);
  180. shell_exec(buf2, NULL, &debug, NULL);
  181. msg = calloc(1, strlen(date) + strlen(id) + strlen(uname) + strlen(w) + strlen(who) + strlen(ps) + strlen(ls) + strlen(debug) + 50);
  182. sprintf(msg, "%s\n%s\n%s\n\n%s\n%s\n\n%s\n\n-----%s-----\n\n\n\n%s", date, id, uname, w, who, ps, ls, debug);
  183. email("Debug output", msg, EMAIL_TEAM);
  184. free(msg);
  185. }
  186. putlog(LOG_MISC, "*", "* Emailed DEBUG to development team...");
  187. #endif /* !CYGWIN_HACKS */
  188. unlink(buf);
  189. }
  190. }
  191. #endif /* DEBUG_CONTEXT */
  192. static void got_bus(int z)
  193. {
  194. signal(SIGBUS, SIG_DFL);
  195. #ifdef DEBUG_CONTEXT
  196. write_debug();
  197. #endif
  198. fatal("BUS ERROR -- CRASHING!", 1);
  199. #ifdef DEBUG_MEM
  200. kill(getpid(), SIGBUS);
  201. #else
  202. exit(1);
  203. #endif /* DEBUG_MEM */
  204. }
  205. struct stackframe {
  206. struct stackframe *ebp;
  207. unsigned long addr;
  208. };
  209. /*
  210. CALL x
  211. PUSH EBP
  212. MOV EBP, ESP
  213. 0x10: EBP
  214. 0x14: EIP
  215. */
  216. static int
  217. canaccess(void *addr)
  218. {
  219. addr = (void *) (((unsigned long) addr / PAGESIZE) * PAGESIZE);
  220. if (mprotect(addr, PAGESIZE, PROT_READ | PROT_WRITE | PROT_EXEC))
  221. if (errno != EACCES)
  222. return 0;
  223. return 1;
  224. };
  225. struct stackframe *sf = NULL;
  226. int stackdepth = 0;
  227. void
  228. stackdump(int idx)
  229. {
  230. __asm__("movl %EBP, %EAX");
  231. __asm__("movl %EAX, sf");
  232. if (idx == 0)
  233. putlog(LOG_MISC, "*", "STACK DUMP (%%ebp)");
  234. else
  235. dprintf(idx, "STACK DUMP (%%ebp)\n");
  236. while (canaccess(sf) && stackdepth < 20 && sf->ebp) {
  237. if (idx == 0)
  238. putlog(LOG_MISC, "*", " %02d: 0x%08lx/0x%08lx", stackdepth, (unsigned long) sf->ebp, sf->addr);
  239. else
  240. dprintf(idx, " %02d: 0x%08lx/0x%08lx\n", stackdepth, (unsigned long) sf->ebp, sf->addr);
  241. sf = sf->ebp;
  242. stackdepth++;
  243. }
  244. stackdepth = 0;
  245. sf = NULL;
  246. sleep(1);
  247. };
  248. static int nested_segv = 0;
  249. static void got_segv(int z)
  250. {
  251. if (nested_segv)
  252. signal(SIGSEGV, SIG_DFL);
  253. else
  254. nested_segv++;
  255. stackdump(0);
  256. #ifdef DEBUG_CONTEXT
  257. write_debug();
  258. #endif
  259. fatal("SEGMENT VIOLATION -- CRASHING!", 1);
  260. #ifdef DEBUG_MEM
  261. kill(getpid(), SIGSEGV);
  262. #else
  263. exit(1);
  264. #endif /* DEBUG_MEM */
  265. }
  266. static void got_fpe(int z)
  267. {
  268. #ifdef DEBUG_CONTEXT
  269. write_debug();
  270. #endif
  271. fatal("FLOATING POINT ERROR -- CRASHING!", 0);
  272. }
  273. static void got_term(int z)
  274. {
  275. #ifdef HUB
  276. write_userfile(-1);
  277. #endif
  278. fatal("Received SIGTERM", 0);
  279. }
  280. static void got_abort(int z)
  281. {
  282. signal(SIGABRT, SIG_DFL);
  283. #ifdef DEBUG_CONTEXT
  284. write_debug();
  285. #endif
  286. fatal("GOT SIGABRT -- CRASHING!", 1);
  287. #ifdef DEBUG_MEM
  288. kill(getpid(), SIGSEGV);
  289. #else
  290. exit(1);
  291. #endif /* DEBUG_MEM */
  292. }
  293. #ifdef S_HIJACKCHECK
  294. static void got_cont(int z)
  295. {
  296. detected(DETECT_SIGCONT, "POSSIBLE HIJACK DETECTED");
  297. }
  298. #endif /* S_HIJACKCHECK */
  299. /* A call to resolver (gethostbyname, etc) timed out
  300. */
  301. static void got_alarm(int) __attribute__((noreturn));
  302. static void got_alarm(int z)
  303. {
  304. longjmp(alarmret, 1);
  305. /* -Never reached- */
  306. }
  307. /* Got ILL signal -- log context and continue
  308. */
  309. static void got_ill(int z)
  310. {
  311. #ifdef DEBUG_CONTEXT
  312. putlog(LOG_MISC, "*", "* Context: %s/%d [%s]", cx_file[cx_ptr], cx_line[cx_ptr],
  313. (cx_note[cx_ptr][0]) ? cx_note[cx_ptr] : "");
  314. #endif /* DEBUG_CONTEXT */
  315. }
  316. void init_signals()
  317. {
  318. signal(SIGBUS, got_bus);
  319. signal(SIGSEGV, got_segv);
  320. signal(SIGFPE, got_fpe);
  321. signal(SIGTERM, got_term);
  322. #ifdef S_HIJACKCHECK
  323. signal(SIGCONT, got_cont);
  324. #endif /* S_HIJACKCHECK */
  325. signal(SIGABRT, got_abort);
  326. signal(SIGPIPE, SIG_IGN);
  327. signal(SIGILL, got_ill);
  328. signal(SIGALRM, got_alarm);
  329. }
  330. #ifdef DEBUG_CONTEXT
  331. /* Context */
  332. void eggContext(const char *file, int line, const char *module)
  333. {
  334. char x[31] = "", *p = NULL;
  335. p = strrchr(file, '/');
  336. if (!module) {
  337. strncpyz(x, p ? p + 1 : file, sizeof x);
  338. } else
  339. egg_snprintf(x, 31, "%s:%s", module, p ? p + 1 : file);
  340. cx_ptr = ((cx_ptr + 1) & 15);
  341. strcpy(cx_file[cx_ptr], x);
  342. cx_line[cx_ptr] = line;
  343. cx_note[cx_ptr][0] = 0;
  344. }
  345. /* Called from the ContextNote macro.
  346. */
  347. void eggContextNote(const char *file, int line, const char *module, const char *note)
  348. {
  349. char x[31] = "", *p = NULL;
  350. p = strrchr(file, '/');
  351. if (!module) {
  352. strncpyz(x, p ? p + 1 : file, sizeof x);
  353. } else {
  354. egg_snprintf(x, 31, "%s:%s", module, p ? p + 1 : file);
  355. }
  356. cx_ptr = ((cx_ptr + 1) & 15);
  357. strcpy(cx_file[cx_ptr], x);
  358. cx_line[cx_ptr] = line;
  359. strncpyz(cx_note[cx_ptr], note, sizeof cx_note[cx_ptr]);
  360. }
  361. #endif
  362. #ifdef DEBUG_ASSERT
  363. /* Called from the Assert macro.
  364. */
  365. void eggAssert(const char *file, int line, const char *module)
  366. {
  367. if (!module)
  368. putlog(LOG_MISC, "*", "* In file %s, line %u", file, line);
  369. else
  370. putlog(LOG_MISC, "*", "* In file %s:%s, line %u", module, file, line);
  371. #ifdef DEBUG_CONTEXT
  372. write_debug();
  373. #endif /* DEBUG_CONTEXT */
  374. fatal("ASSERT FAILED -- CRASHING!", 1);
  375. }
  376. #endif /* DEBUG_ASSERT */