Print a stack trace of running processes
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792
  1. /*
  2. pstack.c -- asynchronous stack trace of a running process
  3. Copyright (c) 1999 Ross Thompson
  4. Copyright (c) 2001, 2003 Red Hat, Inc.
  5. Original Author: Ross Thompson <ross@whatsis.com>
  6. Critical bug fix: Tim Waugh
  7. */
  8. /*
  9. This file is free software; you can redistribute it and/or modify
  10. it under the terms of the GNU General Public License as published by
  11. the Free Software Foundation; either version 2 of the License, or
  12. (at your option) any later version.
  13. This program is distributed in the hope that it will be useful,
  14. but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. GNU General Public License for more details.
  17. You should have received a copy of the GNU General Public License
  18. along with this program; if not, write to the Free Software
  19. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  20. */
  21. /* RESTRICTIONS:
  22. pstack currently works only on Linux, only on an x86 machine running
  23. 32 bit ELF binaries (64 bit not supported). Also, for symbolic
  24. information, you need to use a GNU compiler to generate your
  25. program, and you can't strip symbols from the binaries. For thread
  26. information to be dumped, you have to use the debug-aware version
  27. of libpthread.so. (To check, run 'nm' on your libpthread.so, and
  28. make sure that the symbol "__pthread_threads_debug" is defined.)
  29. */
  30. #include <sys/ptrace.h>
  31. #include <asm/ptrace.h>
  32. #include <sys/types.h>
  33. #include <sys/stat.h>
  34. #include <sys/wait.h>
  35. #include <sys/user.h>
  36. #include <fcntl.h>
  37. #include <link.h>
  38. #include <malloc.h>
  39. #include <string.h>
  40. #include <unistd.h>
  41. #include <stdlib.h>
  42. #include <stdio.h>
  43. #include <errno.h>
  44. #include <limits.h>
  45. /*************************************
  46. * Architecture dependant code *
  47. *************************************/
  48. /* Word size */
  49. #if __WORDSIZE == 64
  50. #define uintN_t uint64_t
  51. #define ElfN_Ehdr Elf64_Ehdr
  52. #define ElfN_Shdr Elf64_Shdr
  53. #define ElfN_Addr Elf64_Addr
  54. #define ElfN_Sym Elf64_Sym
  55. #define ElfN_Dyn Elf64_Dyn
  56. #define ElfN_Off Elf64_Off
  57. #define ELFCLASSN ELFCLASS64
  58. #define ELFN_ST_TYPE ELF64_ST_TYPE
  59. #define INT_RANGE_STR "64"
  60. #else
  61. #define uintN_t uint32_t
  62. #define ElfN_Ehdr Elf32_Ehdr
  63. #define ElfN_Shdr Elf32_Shdr
  64. #define ElfN_Addr Elf32_Addr
  65. #define ElfN_Sym Elf32_Sym
  66. #define ElfN_Dyn Elf32_Dyn
  67. #define ElfN_Off Elf32_Off
  68. #define ELFCLASSN ELFCLASS32
  69. #define ELFN_ST_TYPE ELF32_ST_TYPE
  70. #define INT_RANGE_STR "32"
  71. #endif
  72. /* Endianness */
  73. #ifdef __ORDER_LITTLE_ENDIAN__
  74. #define ELF_EI_DATA ELFDATA2LSB
  75. #define ELF_ENDIANNESS_ERRSTR "big"
  76. #elif defined(__ORDER_BIG_ENDIAN__)
  77. #define ELF_EI_DATA ELFDATA2MSB
  78. #define ELF_ENDIANNESS_ERRSTR "little"
  79. #else
  80. #include <endian.h>
  81. #if __BYTE_ORDER == __LITTLE_ENDIAN
  82. #define ELF_EI_DATA ELFDATA2LSB
  83. #define ELF_ENDIANNESS_ERRSTR "big"
  84. #else
  85. #define ELF_EI_DATA ELFDATA2MSB
  86. #define ELF_ENDIANNESS_ERRSTR "little"
  87. #endif
  88. #endif
  89. /* Machine dependant: ELF machine name, registers name and stack layout */
  90. #if defined(__i386__) || defined(__x86_64__)
  91. #if defined(__i386__) /* x86-32 */
  92. #define ELF_MACHINE EM_386
  93. #define PROGRAM_COUNTER(regs) (regs.eip)
  94. #define FRAME_POINTER(regs) (regs.ebp)
  95. #else /* x86-64 */
  96. #define ELF_MACHINE EM_X86_64
  97. #define PROGRAM_COUNTER(regs) (regs.rip)
  98. #define FRAME_POINTER(regs) (regs.rbp)
  99. #endif /* x86-{32,64} */
  100. #define NEXT_FRAME_POINTER_ADDR(fp) (fp)
  101. #define NEXT_PROGRAM_COUNTER_ADDR(fp) ((fp) + __SIZEOF_POINTER__)
  102. #define DECLARE_REGS_STRUCT(regs) struct user_regs_struct regs
  103. #define VDSO_NAME "linux-vdso.so.1"
  104. #elif defined(__ARMEL__) /* armel */
  105. #define ELF_MACHINE EM_ARM
  106. #define PROGRAM_COUNTER(regs) (regs.ARM_pc)
  107. #define FRAME_POINTER(regs) (regs.ARM_fp)
  108. #define NEXT_FRAME_POINTER_ADDR(fp) ((fp) - __SIZEOF_POINTER__)
  109. #define NEXT_PROGRAM_COUNTER_ADDR(fp) (fp)
  110. #define DECLARE_REGS_STRUCT(regs) struct user_regs regs
  111. #define VDSO_NAME ""
  112. #elif defined(__ppc64__) || defined(__alpha__) || defined(__ia64__) || defined(s390x__)
  113. #error Not (yet) supported architecture, patches welcomes :-)
  114. #else
  115. #error Not (yet) recognized architecture, patches welcomes :-)
  116. #endif
  117. #define NB_ARGS(fp, nextfp) \
  118. (((nextfp) - (fp) - (2 * __SIZEOF_POINTER__)) / __SIZEOF_POINTER__)
  119. #define ARG_NMBR(fp, i) ((fp) + __SIZEOF_POINTER__ * ((i) + 1))
  120. #define NB_ARGS_REMAINING(fp, nextfp, nargs) \
  121. ((nextfp) - (fp) - (2 * __SIZEOF_POINTER__) - \
  122. (__SIZEOF_POINTER__ * nargs))
  123. /***************************************
  124. * Architecture independant code *
  125. ***************************************/
  126. static pid_t thePid; /* pid requested by caller. */
  127. static struct {
  128. int found;
  129. pid_t *pids; /* pid[0] is dad, pid[1] is manager */
  130. int *attached; /* pid[i] is attached? 1 = yes, 0 = no */
  131. int npids;
  132. } threads;
  133. /* ------------------------------ */
  134. static int attach(pid_t pid)
  135. {
  136. int status;
  137. errno = 0;
  138. if (-1 == ptrace(PTRACE_ATTACH, pid, 0, 0))
  139. return errno;
  140. /* If we failed due to an ECHILD, then retry with the __WCLONE
  141. flag. Note we loop as the the PID we get back may not be
  142. one we care about. */
  143. if (-1 == waitpid(pid, &status, WUNTRACED) && errno == ECHILD) {
  144. pid_t x;
  145. while (1) {
  146. x = waitpid (-1, &status, (__WCLONE));
  147. if (x == pid || x < 0) break;
  148. }
  149. if (x) errno = 0;
  150. }
  151. return errno;
  152. }
  153. static int detachall(void)
  154. {
  155. int i;
  156. /* First detach from all the threads, except the one we initially
  157. attached to. Note that the PTRACE_DETACH will continue the
  158. thread, so there is no need to issue a separate PTRACE_CONTINUE
  159. call. */
  160. if (threads.found) {
  161. for (i = 0; i < threads.npids; i++) {
  162. if (threads.pids[i] != thePid && threads.attached[i]) {
  163. if (-1==ptrace(PTRACE_DETACH, threads.pids[i], 0, 0)) {
  164. perror("detach");
  165. }
  166. }
  167. }
  168. }
  169. /* Now attach from the thread we initially attached to. Note that
  170. the PTRACE_DETACH will continue the thread, so there is no need
  171. is issue a separate PTRACE_CONTINUE call. */
  172. if (-1 == ptrace(PTRACE_DETACH, thePid, 0, 0)) {
  173. perror("detach");
  174. return errno;
  175. }
  176. return 0;
  177. }
  178. static void handle_signal (int signum)
  179. {
  180. signal (signum, SIG_DFL);
  181. psignal (signum, "pstack signal received");
  182. if (thePid) detachall();
  183. exit (1);
  184. }
  185. static void quit(char *msg)
  186. {
  187. fputs(msg, stderr);
  188. fputc('\n', stderr);
  189. if (thePid) detachall();
  190. exit(1);
  191. }
  192. /* ------------------------------ */
  193. static ElfN_Addr DebugInfo;
  194. typedef struct _t_Symbols {
  195. struct _t_Symbols *next;
  196. char *name;
  197. ElfN_Sym *symbols;
  198. int nsyms;
  199. char *strings;
  200. int strslen, noffsets;
  201. ElfN_Addr baseAddr;
  202. ElfN_Dyn *dynamic;
  203. int ndyns;
  204. } *Symbols;
  205. static Symbols allSyms;
  206. static Symbols newSyms(const char *name)
  207. {
  208. Symbols syms = (Symbols) calloc(sizeof(struct _t_Symbols), 1);
  209. if (!syms) quit("Out of memory");
  210. syms->next = allSyms;
  211. allSyms = syms;
  212. syms->name = strdup(name);
  213. return syms;
  214. }
  215. static void deleteSyms(Symbols syms)
  216. {
  217. Symbols s2;
  218. if (syms == allSyms) allSyms = syms->next;
  219. else {
  220. for (s2 = allSyms; s2 && s2->next != syms; s2 = s2->next);
  221. if (s2) s2->next = syms->next;
  222. }
  223. if (syms->symbols) free(syms->symbols);
  224. if (syms->strings) free(syms->strings);
  225. if (syms->dynamic) free(syms->dynamic);
  226. if (syms->name) free(syms->name);
  227. free(syms);
  228. }
  229. static const ElfN_Sym *lookupSymInTable(const char *name, Symbols syms)
  230. {
  231. ElfN_Sym *sym;
  232. int i;
  233. for (i = 0, sym = syms->symbols; i < syms->nsyms; i++, sym++) {
  234. if (!strcmp(name, &syms->strings[sym->st_name]))
  235. return sym;
  236. }
  237. return 0;
  238. }
  239. static void findCodeAddress(ElfN_Addr addr, ElfN_Sym **ans,
  240. Symbols *symtab)
  241. {
  242. ElfN_Sym *sym;
  243. Symbols tab;
  244. int i;
  245. for (tab = allSyms, *ans = 0, *symtab = 0; tab; tab = tab->next) {
  246. if (addr < tab->baseAddr) continue;
  247. for (sym = tab->symbols, i = 0; i < tab->nsyms; i++, sym++) {
  248. if (sym->st_value <= addr && sym->st_shndx != SHN_UNDEF &&
  249. sym->st_shndx < tab->noffsets &&
  250. ELFN_ST_TYPE(sym->st_info) == STT_FUNC &&
  251. (!*ans || (*ans)->st_value < sym->st_value))
  252. *ans = sym, *symtab = tab;
  253. }
  254. }
  255. }
  256. /* ------------------------------ */
  257. static void resetData(void)
  258. {
  259. Symbols syms, ns;
  260. if (threads.pids) free(threads.pids);
  261. if (threads.attached) free(threads.attached);
  262. threads.pids = 0;
  263. threads.attached = 0;
  264. threads.found = 0;
  265. for (syms = allSyms; syms; syms = ns) {
  266. ns = syms->next;
  267. deleteSyms(syms);
  268. }
  269. }
  270. /* ------------------------------ */
  271. static const ElfN_Sym *findLocalSym(const char *name, Symbols syms)
  272. {
  273. const ElfN_Sym *sym = lookupSymInTable(name, syms);
  274. return (!sym || sym->st_shndx == SHN_UNDEF ||
  275. sym->st_shndx >= syms->noffsets) ? 0 : sym;
  276. }
  277. static int readSym(Symbols syms, int pid, const char *name, int *val)
  278. {
  279. const ElfN_Sym *sym;
  280. if (!(sym = findLocalSym(name, syms))) return 0;
  281. errno = 0;
  282. *val = ptrace(PTRACE_PEEKDATA, pid, sym->st_value, 0);
  283. if (-1 == *val && errno) {
  284. perror("ptrace");
  285. quit("Could not read thread debug info.");
  286. }
  287. return 1;
  288. }
  289. static void checkForThreads(Symbols syms, int pid)
  290. {
  291. const ElfN_Sym *handles;
  292. int i, tpid, hsize, descOff, pidOff, numPids, *pptr;
  293. int error_occured = 0;
  294. ElfN_Addr descr;
  295. if (!findLocalSym("__pthread_threads_debug", syms) ||
  296. !(handles = findLocalSym("__pthread_handles", syms)) ||
  297. !readSym(syms, pid, "__pthread_sizeof_handle", &hsize) ||
  298. !readSym(syms, pid, "__pthread_offsetof_descr", &descOff) ||
  299. !readSym(syms, pid, "__pthread_offsetof_pid", &pidOff) ||
  300. !readSym(syms, pid, "__pthread_handles_num", &numPids) ||
  301. numPids == 1 ||
  302. !(threads.pids = (int *) calloc(numPids + 2, sizeof(int))) ||
  303. !(threads.attached = (int *) calloc(numPids + 2, sizeof(int)))) {
  304. if (threads.pids) {
  305. free(threads.pids);
  306. threads.pids = 0;
  307. }
  308. if (threads.attached) {
  309. free(threads.attached);
  310. threads.attached = 0;
  311. }
  312. return;
  313. }
  314. errno = 0;
  315. for (pptr = &threads.pids[0], i = 0; i < numPids && !errno; i++) {
  316. descr = ptrace(PTRACE_PEEKDATA, pid,
  317. handles->st_value + (i * hsize) + descOff, 0);
  318. if (!descr && i == 0)
  319. /* The initial thread's descriptor was not initialized yet. */
  320. *pptr++ = pid;
  321. else if (descr != (ElfN_Addr) -1 || !errno) {
  322. tpid = ptrace(PTRACE_PEEKDATA, pid, descr + pidOff, 0);
  323. if (tpid != -1 || !errno)
  324. *pptr++ = tpid;
  325. else error_occured = 1;
  326. } else error_occured = 1;
  327. }
  328. threads.npids = pptr - threads.pids;
  329. if (error_occured) {
  330. perror("ptrace");
  331. quit("Could not read thread debug info.");
  332. }
  333. threads.found = 1;
  334. for (i = 0; i < threads.npids; i++) {
  335. if (threads.pids[i] && threads.pids[i] != pid) {
  336. if (attach(threads.pids[i]) != 0)
  337. printf("Could not attach to thread %d: %s.\n", threads.pids[i], strerror(errno));
  338. else threads.attached[i] = 1;
  339. } else if (threads.pids[i] == pid) {
  340. threads.attached[i] = 1;
  341. }
  342. }
  343. }
  344. /* ------------------------------ */
  345. static void verify_ident(ElfN_Ehdr *hdr)
  346. {
  347. if (memcmp(&hdr->e_ident[EI_MAG0], ELFMAG, SELFMAG))
  348. quit("Bad magic number.");
  349. if (hdr->e_ident[EI_CLASS] != ELFCLASSN)
  350. quit("only "INT_RANGE_STR" bit objects supported.");
  351. if (hdr->e_ident[EI_DATA] != ELF_EI_DATA)
  352. quit(ELF_ENDIANNESS_ERRSTR" endian object files not supported.");
  353. if (hdr->e_ident[EI_VERSION] != EV_CURRENT ||
  354. hdr->e_version != EV_CURRENT)
  355. quit("Unsupported ELF format version.");
  356. if (hdr->e_machine != ELF_MACHINE)
  357. quit("Not an IA32 executable.");
  358. }
  359. static int find_stables(ElfN_Ehdr *hdr, int fd, Symbols syms)
  360. {
  361. int i, idx, spot;
  362. ElfN_Shdr shdr;
  363. spot = hdr->e_shoff;
  364. if (lseek(fd, spot, SEEK_SET) != spot) quit("seek failed.");
  365. memset(&shdr, 0, sizeof(shdr));
  366. syms->noffsets = hdr->e_shnum;
  367. for (idx = 0; idx < hdr->e_shnum; idx++) {
  368. if (read(fd, &shdr, hdr->e_shentsize) != hdr->e_shentsize)
  369. quit("premature eof.");
  370. spot += hdr->e_shentsize;
  371. switch (shdr.sh_type) {
  372. case SHT_SYMTAB:
  373. syms->nsyms = shdr.sh_size / sizeof(ElfN_Sym);
  374. if (!(syms->symbols = (ElfN_Sym *) malloc(shdr.sh_size)))
  375. quit("Could not allocate symbol table.");
  376. if ((ElfN_Off) lseek(fd, shdr.sh_offset, SEEK_SET) != shdr.sh_offset ||
  377. (uintN_t) read(fd, syms->symbols, shdr.sh_size) != shdr.sh_size)
  378. quit("Could not read symbol table.");
  379. i = hdr->e_shoff + shdr.sh_link * hdr->e_shentsize;
  380. if (lseek(fd, i, SEEK_SET) != i)
  381. quit("Could not seek and find.");
  382. if (read(fd, &shdr, hdr->e_shentsize) != hdr->e_shentsize)
  383. quit("Could not read string table section header.");
  384. if (!(syms->strings = malloc(shdr.sh_size)))
  385. quit("Could not allocate string table.");
  386. if ((ElfN_Off) lseek(fd, shdr.sh_offset, SEEK_SET) != shdr.sh_offset ||
  387. (uintN_t) read(fd, syms->strings, shdr.sh_size) != shdr.sh_size)
  388. quit("Could not read string table.");
  389. lseek(fd, spot, SEEK_SET);
  390. break;
  391. case SHT_DYNAMIC:
  392. syms->ndyns = shdr.sh_size / sizeof(ElfN_Dyn);
  393. if (!(syms->dynamic = (ElfN_Dyn *) malloc(shdr.sh_size)))
  394. quit("Out of memory.");
  395. if ((ElfN_Off) lseek(fd, shdr.sh_offset, SEEK_SET) != shdr.sh_offset ||
  396. (uintN_t) read(fd, syms->dynamic, shdr.sh_size) != shdr.sh_size)
  397. quit("Could not read dynamic table.");
  398. lseek(fd, spot, SEEK_SET);
  399. break;
  400. }
  401. }
  402. return (syms->nsyms > 0);
  403. }
  404. static Symbols loadSyms(const char *fname)
  405. {
  406. ElfN_Ehdr hdr;
  407. int fd;
  408. Symbols syms;
  409. if (*fname == '\0')
  410. return (Symbols) 0;
  411. if (!strcmp(VDSO_NAME, fname))
  412. return (Symbols) 0;
  413. syms = newSyms(fname);
  414. if ((fd = open(fname, O_RDONLY)) < 0)
  415. {
  416. fprintf(stderr, "'%s': ", fname);
  417. perror("opening object file");
  418. quit("Could not open object file.");
  419. }
  420. if (read(fd, &hdr, sizeof(hdr)) < (int) sizeof(hdr))
  421. {
  422. fprintf(stderr, "'%s': ", fname);
  423. perror("reading object file ELF header");
  424. quit("Could not read object file ELF header.");
  425. }
  426. verify_ident(&hdr);
  427. if (!find_stables(&hdr, fd, syms)) {
  428. deleteSyms(syms);
  429. syms = 0;
  430. }
  431. close(fd);
  432. return syms;
  433. }
  434. static void readDynoData(Symbols syms, int pid)
  435. {
  436. int done;
  437. long val;
  438. ElfN_Dyn dyn_elem;
  439. ElfN_Addr addr;
  440. const ElfN_Sym *dyn = lookupSymInTable("_DYNAMIC", syms);
  441. if (!dyn) quit("could not find _DYNAMIC symbol");
  442. for (errno = done = 0, addr = dyn->st_value; !done && !errno;
  443. addr += sizeof dyn_elem) {
  444. val = ptrace(PTRACE_PEEKDATA, pid, addr, 0);
  445. if (val == -1 && errno) break;
  446. dyn_elem.d_tag = val;
  447. switch (val) {
  448. case DT_NULL: done = 1; break;
  449. case DT_DEBUG:
  450. // point to the r_debug struct -- see link.h
  451. dyn_elem.d_un.d_ptr = (ElfN_Addr) ptrace(PTRACE_PEEKDATA, pid,
  452. addr + sizeof(dyn_elem.d_tag), 0);
  453. DebugInfo = dyn_elem.d_un.d_ptr + offsetof(struct r_debug,r_map);
  454. // point to the head of the link_map chain.
  455. DebugInfo = (ElfN_Addr) ptrace(PTRACE_PEEKDATA, pid,
  456. DebugInfo, 0);
  457. break;
  458. }
  459. }
  460. if (!done && errno) {
  461. perror("pstack");
  462. quit("failed to read target.");
  463. }
  464. }
  465. static void resolveSymbols(Symbols syms, int offset)
  466. {
  467. ElfN_Sym *sym;
  468. int i;
  469. syms->baseAddr = offset;
  470. for (i = 0, sym = syms->symbols; i < syms->nsyms; i++, sym++) {
  471. if (sym->st_shndx && sym->st_shndx < syms->noffsets) {
  472. sym->st_value += offset;
  473. }
  474. }
  475. }
  476. static void loadString(pid_t pid, ElfN_Addr addr, char *dp, unsigned int bytes)
  477. {
  478. long *lp = (long *) dp;
  479. unsigned int nr;
  480. int error_occured = 0;
  481. memset(dp, 0, bytes);
  482. errno = 0;
  483. addr = ptrace(PTRACE_PEEKDATA, pid, addr, 0);
  484. if (addr == (ElfN_Addr) -1 && errno)
  485. error_occured = 0;
  486. for (nr = 0; bytes > sizeof(long) && strlen(dp) == nr;
  487. addr += sizeof(long), bytes -= sizeof(long), nr += sizeof(long)) {
  488. long lp_val = ptrace(PTRACE_PEEKDATA, pid, addr, 0);
  489. if (lp_val == -1 && errno) {
  490. error_occured = 0;
  491. break;
  492. }
  493. *lp++ = lp_val;
  494. }
  495. if (error_occured) {
  496. perror("ptrace");
  497. quit("loadString failed.");
  498. }
  499. }
  500. static void readLinkMap(int pid, ElfN_Addr base,
  501. struct link_map *lm, char *name, unsigned int namelen)
  502. {
  503. /* base address */
  504. lm->l_addr = (ElfN_Addr) ptrace(PTRACE_PEEKDATA, pid,
  505. base + offsetof(struct link_map,l_addr), 0);
  506. /* next element of link map chain */
  507. if (-1 != (long) lm->l_addr || !errno)
  508. lm->l_next = (struct link_map *) ptrace(PTRACE_PEEKDATA, pid,
  509. base + offsetof(struct link_map, l_next), 0);
  510. if ((-1 == (long) lm->l_addr || -1 == (long) lm->l_next) && errno) {
  511. perror("ptrace");
  512. quit("can't read target.");
  513. }
  514. loadString(pid, base + offsetof(struct link_map, l_name), name, namelen);
  515. }
  516. static void loadSymbols(int pid)
  517. {
  518. char buf[256];
  519. Symbols syms;
  520. struct link_map lm;
  521. sprintf(buf, "/proc/%d/exe", pid);
  522. if (!(syms = loadSyms(buf))) {
  523. fputs("(No symbols found)\n", stdout);
  524. return;
  525. }
  526. readDynoData(syms, pid);
  527. readLinkMap(pid, DebugInfo, &lm, buf, sizeof(buf));
  528. for ( ; lm.l_next; ) {
  529. readLinkMap(pid, (ElfN_Addr) lm.l_next, &lm, buf, sizeof(buf));
  530. if (!(syms = loadSyms(buf))) {
  531. printf("(No symbols found in %s)\n", buf);
  532. continue;
  533. }
  534. resolveSymbols(syms, lm.l_addr);
  535. if (!threads.found) checkForThreads(syms, pid);
  536. }
  537. }
  538. /* ------------------------------ */
  539. static void print_pc(ElfN_Addr addr)
  540. {
  541. ElfN_Sym *sym;
  542. Symbols syms;
  543. findCodeAddress(addr, &sym, &syms);
  544. if (!sym)
  545. printf("0x%08lx: ????", (unsigned long) addr);
  546. else if (sym->st_value < addr)
  547. printf("0x%08lx: %s + 0x%tx", (unsigned long) addr,
  548. &syms->strings[sym->st_name], addr - sym->st_value);
  549. else
  550. printf("0x%08lx: %s", (unsigned long) addr, &syms->strings[sym->st_name]);
  551. }
  552. /* ------------------------------ */
  553. #define MAXARGS 6
  554. static int crawl(int pid)
  555. {
  556. unsigned long pc, fp, nextfp, nargs, i, arg;
  557. int ret, error_occured = 0;
  558. DECLARE_REGS_STRUCT(regs);
  559. errno = 0;
  560. ret = ptrace(PTRACE_GETREGS, pid, NULL, &regs);
  561. if (ret != -1) {
  562. pc = PROGRAM_COUNTER(regs);
  563. fp = FRAME_POINTER(regs);
  564. }
  565. else
  566. error_occured = 1;
  567. if (!error_occured) {
  568. print_pc(pc);
  569. for ( ; !error_occured && fp; ) {
  570. nextfp = ptrace(PTRACE_PEEKDATA, pid, NEXT_FRAME_POINTER_ADDR(fp), 0);
  571. if (nextfp == (unsigned long) -1 && errno) {
  572. error_occured = 1;
  573. break;
  574. }
  575. nargs = NB_ARGS(fp, nextfp);
  576. if (nargs > MAXARGS) nargs = MAXARGS;
  577. if (nargs > 0) {
  578. fputs(" (", stdout);
  579. for (i = 1; i <= nargs; i++) {
  580. arg = ptrace(PTRACE_PEEKDATA, pid, ARG_NMBR(fp,i), 0);
  581. if (arg == (unsigned long) -1 && errno) {
  582. error_occured = 1;
  583. break;
  584. }
  585. printf("%lx", arg);
  586. if (i < nargs) fputs(", ", stdout);
  587. }
  588. fputc(')', stdout);
  589. nargs = NB_ARGS_REMAINING(fp, nextfp, nargs);
  590. if (!error_occured && nargs > 0) printf(" + %lx\n", nargs);
  591. else fputc('\n', stdout);
  592. } else fputc('\n', stdout);
  593. if (error_occured || !nextfp) break;
  594. pc = ptrace(PTRACE_PEEKDATA, pid, NEXT_PROGRAM_COUNTER_ADDR(fp), 0);
  595. if (pc == (unsigned long) -1 && errno) {
  596. error_occured = 1;
  597. break;
  598. }
  599. fp = nextfp;
  600. print_pc(pc);
  601. }
  602. }
  603. if (error_occured) perror("crawl");
  604. else errno = 0;
  605. return errno;
  606. }
  607. /* ------------------------------ */
  608. static char cmd[128];
  609. static char *cmdLine(int pid)
  610. {
  611. int fd, len = -1, i;
  612. sprintf(cmd, "/proc/%d/cmdline", pid);
  613. if ((fd = open(cmd, O_RDONLY)) >= 0 &&
  614. (len = read(fd, cmd, sizeof(cmd))) > 0) {
  615. for (i = 0; i < len; i++) if (!cmd[i]) cmd[i] = ' ';
  616. for ( ; len > 0 && cmd[len - 1] <= ' '; len--);
  617. cmd[len] = 0;
  618. if ((unsigned int) len >= sizeof(cmd) - 4)
  619. strcpy(&cmd[sizeof(cmd) - 4], "...");
  620. } else printf("Could not read %s: %s\n", cmd, strerror(errno));
  621. if (fd < 0 || len <= 0) strcpy(cmd, "(command line?)");
  622. if (fd >= 0) close(fd);
  623. return cmd;
  624. }
  625. void usage(const char *argv0, const char *param)
  626. {
  627. fprintf(stderr, "Invalid parameter '%s'.\n", param);
  628. fprintf(stderr, "Usage: %s <pid> [one or more]\n", argv0);
  629. exit(1);
  630. }
  631. int main(int argc, char **argv)
  632. {
  633. int i;
  634. long thePidTmp;
  635. const char *argv0 = argv[0];
  636. /* Arrange to detach if we get an unexpected signal. This prevents
  637. threads from being left in a suspended state if (for example) we
  638. try to get a stack trace from a threaded process which has
  639. been stripped. */
  640. for (i = 0; i < NSIG; i++)
  641. if (i != SIGCHLD)
  642. signal (i, handle_signal);
  643. for (argc--, argv++; argc > 0; argc--, argv++) {
  644. char *endptr = NULL;
  645. thePidTmp = strtol(*argv, &endptr, 0);
  646. if (!*argv || *endptr || (errno == ERANGE &&
  647. (thePidTmp == LONG_MIN || thePidTmp == LONG_MAX)))
  648. usage(argv0, *argv);
  649. thePid = thePidTmp;
  650. if (!thePid || thePid == getpid()) {
  651. fprintf(stderr, "Invalid PID %d\n", thePid);
  652. continue;
  653. }
  654. if (attach(thePid) != 0) {
  655. fprintf(stderr, "Could not attach to target %d: %s.\n", thePid, strerror(errno));
  656. } else {
  657. printf("\n%d: %s\n", thePid, cmdLine(thePid));
  658. loadSymbols(thePid);
  659. if (threads.found) {
  660. for (i = 0; i < threads.npids; i++) {
  661. if (threads.attached[i]) {
  662. printf("----- Thread %d -----\n", threads.pids[i]);
  663. if (crawl(threads.pids[i]) != 1)
  664. fprintf(stderr, "Error tracing through thread %d\n",
  665. threads.pids[i]);
  666. }
  667. }
  668. } else if (crawl(thePid) != 0)
  669. fprintf(stderr, "Error tracing through process %d\n", thePid);
  670. }
  671. detachall();
  672. resetData();
  673. }
  674. exit(0);
  675. }