crash-stack: Get executable name from cmdline
[platform/core/system/crash-worker.git] / src / crash-stack / crash-stack.c
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  * Authors: Adrian Szyndela <adrian.s@samsung.com>
17  *          Łukasz Stelmach <l.stelmach@samsung.com>
18  *          Rafał Pietruch <r.pietruch@samsung.com>
19  */
20 #define _GNU_SOURCE 1
21
22 /**
23  * @file crash-stack.c
24  * @brief This file contains Main module of call stack unwinding program
25  *
26  * Crash-stack is a single purpose program. Its duty is to show call stack
27  * of a crashed program. Crash-stack must be called with proper arguments:
28  * PID of a crashed program.
29  */
30 #include "crash-stack.h"
31 #include <dirent.h>
32 #include <errno.h>
33 #include <fcntl.h>
34 #include <getopt.h>
35 #include <libelf.h>
36 #include <linux/prctl.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <sys/mman.h>
41 #include <sys/prctl.h>
42 #include <sys/ptrace.h>
43 #include <sys/stat.h>
44 #include <sys/syscall.h>
45 #include <sys/types.h>
46 #include <sys/uio.h>
47 #include <sys/wait.h>
48 #include <unistd.h>
49
50 #include <elfutils/version.h>
51 #include <elfutils/libdwfl.h>
52
53 #define BUF_SIZE (BUFSIZ)
54 #define HEXA 16
55 #define PERM_LEN 5
56 #define ADDR_LEN 16
57 #define STR_ANONY "[anony]"
58 #define STR_ANONY_LEN 8
59
60 static FILE *outputfile = NULL;         ///< global output stream
61 static FILE *errfile = NULL;            ///< global error stream
62 static FILE *bufferfile = NULL;         ///< buffer file for ordering
63
64 /**
65  * @brief definitions for getopt options: identifiers
66  */
67 enum {
68         OPT_PID,
69         OPT_TID,
70         OPT_SIGNUM,
71         OPT_OUTPUTFILE,
72         OPT_ERRFILE
73 };
74
75 /**
76  * @brief definitions for getopt options: full specifications
77  */
78 const struct option opts[] = {
79         { "pid", required_argument, 0, OPT_PID },
80         { "tid", required_argument, 0, OPT_TID },
81         { "sig", required_argument, 0, OPT_SIGNUM },
82         { "output", required_argument, 0, OPT_OUTPUTFILE },
83         { "erroutput", required_argument, 0, OPT_ERRFILE },
84         { 0, 0, 0, 0 }
85 };
86
87 /**
88  * @brief container for information from /proc/PID/maps
89  */
90 struct addr_node {
91         uintptr_t startaddr;
92         uintptr_t endaddr;
93         char perm[PERM_LEN];
94         char *fpath;
95         struct addr_node *next;
96 };
97
98 /* helper functions for reading /proc/PID/maps */
99 static struct addr_node *get_addr_list_from_maps(int fd);
100 static void free_all_nodes(struct addr_node *start);
101 static char *fgets_fd(char *str, int len, int fd);
102
103 /*
104  * __cxa_demangle() is taken from libstdc++, however there is no header that we
105  * can take a declaration from. Importing through 'extern' allows using it.
106  */
107 /// @cond false
108 extern char *__cxa_demangle(const char *mangled_name, char *output_buffer,
109                 size_t *length, int *status);
110 ///@endcond
111
112 /**
113  * @brief A callback for dwfl_getmodules().
114  *
115  * This callback is called once for every module discovered by dwfl_getmodules().
116  *
117  * @param module the dwfl module
118  * @param userdata unused, required by dwfl_getmodules()
119  * @param name name of the module
120  * @param address address of the module
121  * @param arg 4th argument to dwfl_getmodules is passed here
122  */
123 static int __module_callback(Dwfl_Module *module, void **userdata,
124                 const char *name, Dwarf_Addr address,
125                 void *arg)
126 {
127         return DWARF_CB_OK;
128 }
129
130 static void __find_symbol_in_elf(ProcInfo *proc_info, Dwarf_Addr mapping_start)
131 {
132         Elf *elf;
133         int fd;
134         const char *elf_name = proc_info->module_name;
135         Dwarf_Addr address = proc_info->addr;
136
137         fd = open(elf_name, O_RDONLY);
138         if (-1 == fd)
139                 return;
140
141         elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
142
143         if (NULL == elf) {
144                 close(fd);
145                 return;
146         }
147
148         Elf_Scn *scn = NULL;
149         int found = 0;
150
151         while ((scn = elf_nextscn(elf, scn)) != NULL && !found) {
152                 GElf_Shdr shdr_mem;
153                 GElf_Shdr *shdr = gelf_getshdr(scn, &shdr_mem);
154                 if (shdr != NULL && (shdr->sh_type == SHT_SYMTAB || shdr->sh_type == SHT_DYNSYM)) {
155                         Elf_Data *sdata = elf_getdata(scn, NULL);
156                         unsigned int nsyms = sdata->d_size / (gelf_getclass(elf) == ELFCLASS32 ?
157                                         sizeof(Elf32_Sym) :
158                                         sizeof(Elf64_Sym));
159                         unsigned int cnt;
160                         uintptr_t address_offset = address;
161                         if (shdr->sh_type == SHT_DYNSYM)
162                                 address_offset -= mapping_start;
163                         for (cnt = 0; cnt < nsyms; ++cnt) {
164                                 GElf_Sym sym_mem;
165                                 Elf32_Word xndx;
166                                 GElf_Sym *sym = gelf_getsymshndx(sdata, NULL, cnt, &sym_mem, &xndx);
167                                 if (sym != NULL && sym->st_shndx != SHN_UNDEF) {
168                                         if (sym->st_value <= address_offset && address_offset < sym->st_value + sym->st_size) {
169                                                 free(proc_info->name);
170                                                 proc_info->name = strdup(elf_strptr(elf, shdr->sh_link, sym->st_name));
171                                                 proc_info->offset = address_offset - sym->st_value;
172                                                 found = 1;
173                                                 break;
174                                         }
175                                 }
176                         }
177                 }
178         }
179
180         elf_end(elf);
181         close(fd);
182 }
183
184 static int __attachable(pid_t pid, pid_t tid)
185 {
186         /* read /proc/<pid>/stat */
187         char buf[40];
188         FILE *f;
189         char status;
190
191         snprintf(buf, sizeof(buf), "/proc/%d/task/%d/stat", pid, tid);
192
193         f = fopen(buf, "r");
194         if (NULL == f)
195                 return -1;
196
197         /* check if status is D */
198         if (fscanf(f, "%*d %*s %c", &status) != 1) {
199                 fclose(f);
200                 return -1;
201         }
202
203         fclose(f);
204
205         return status != 'D';
206 }
207
208 static void __print_proc_file(pid_t pid, pid_t tid, const char *name)
209 {
210         char buf[1024];
211         FILE *f;
212         int r;
213
214         snprintf(buf, sizeof(buf), "/proc/%d/task/%d/%s", pid, tid, name);
215
216         fprintf(outputfile, "%s:\n", buf);
217
218         f = fopen(buf, "r");
219         if (NULL == f)
220         {
221                 fprintf(errfile, "Failed to open %s: %m\n", buf);
222                 return;
223         }
224
225         while ((r = fread(buf, 1, sizeof(buf), f)) > 0)
226         {
227                 fwrite(buf, r, 1, outputfile);
228         }
229
230         fclose(f);
231
232         fprintf(outputfile, "\n");
233 }
234
235 static void __print_not_attachable_process_info(pid_t pid, pid_t tid)
236 {
237         fprintf(outputfile, "ERROR: can't attach to process %d, thread %d - thread is in uninterruptible sleep state\n", pid, tid);
238         fprintf(outputfile, "Giving some /proc info instead:\n\n");
239         __print_proc_file(pid, tid, "wchan");
240         fprintf(outputfile, "\n");
241         __print_proc_file(pid, tid, "syscall");
242         __print_proc_file(pid, tid, "stack");
243 }
244
245 /**
246  * @brief Opens libdwfl for using with live process
247  *
248  * @param pid pid of the process to attach to
249  * @return Dwfl handle
250  */
251 static Dwfl *__open_dwfl_with_pid(pid_t pid, pid_t tid)
252 {
253         int status;
254         pid_t stopped_pid;
255
256         status = __attachable(pid, tid);
257         if (-1 == status)
258         {
259                 fprintf(errfile, "failed to read /proc/%d/task/%d/stat: %m\n", pid, tid);
260                 return NULL;
261         }
262
263         if (!status)
264         {
265                 __print_not_attachable_process_info(pid, tid);
266                 return NULL;
267         }
268
269         if (ptrace(PTRACE_SEIZE, tid, NULL, PTRACE_O_TRACEEXIT) != 0) {
270                 fprintf(errfile, "PTRACE_SEIZE failed on TID %d: %m\n", tid);
271                 return NULL;
272         }
273
274         ptrace(PTRACE_INTERRUPT, tid, 0, 0);
275
276         stopped_pid = waitpid(tid, &status, __WALL);
277         if (stopped_pid == -1 || stopped_pid != tid || !WIFSTOPPED(status)) {
278                 fprintf(errfile, "waitpid failed: %m, stopped_pid=%d, status=%d\n", stopped_pid, status);
279                 return NULL;
280         }
281
282         static const Dwfl_Callbacks proc_callbacks = {
283                 .find_elf = dwfl_linux_proc_find_elf,
284                 .find_debuginfo = dwfl_standard_find_debuginfo,
285                 .section_address = NULL,
286                 .debuginfo_path = NULL
287         };
288
289         Dwfl *dwfl = dwfl_begin(&proc_callbacks);
290         if (dwfl == NULL) {
291                 fprintf(errfile, "process %d : Can't start dwfl (%s)\n", tid, dwfl_errmsg(-1));
292                 return NULL;
293         }
294
295         if (dwfl_linux_proc_report(dwfl, tid) < 0) {
296                 fprintf(errfile, "process %d : dwfl report failed (%s)\n", tid, dwfl_errmsg(-1));
297                 dwfl_end(dwfl);
298                 return NULL;
299         }
300
301 #if _ELFUTILS_PREREQ(0,158)
302         if (dwfl_linux_proc_attach(dwfl, tid, true) < 0) {
303                 fprintf(errfile, "process %d : dwfl attach failed (%s)\n", tid, dwfl_errmsg(-1));
304                 dwfl_end(dwfl);
305                 return NULL;
306         }
307 #endif
308         return dwfl;
309 }
310
311 /**
312  * @brief Gets registers information for live process
313  *
314  * @param pid pid of the live process
315  * @return 0 on success, -1 otherwise
316  */
317 static int __get_registers_ptrace(pid_t pid)
318 {
319         struct iovec data;
320         data.iov_base = _crash_stack_get_memory_for_ptrace_registers(&data.iov_len);
321
322         if (NULL == data.iov_base) {
323                 fprintf(errfile, "Cannot get memory for registers for ptrace (not implemented for this architecture\n");
324                 return -1;
325         }
326
327         if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &data) != 0) {
328                 fprintf(errfile, "PTRACE_GETREGSET failed on PID %d: %m\n", pid);
329                 return -1;
330         }
331
332         _crash_stack_set_ptrace_registers(data.iov_base);
333
334         return 0;
335 }
336
337 /**
338  * @brief Print signal number causing dump
339  */
340 static void __crash_stack_print_signal(int signo)
341 {
342         const char* const signal_table[] = {
343                 [SIGHUP]="SIGHUP", [SIGINT]="SIGINT", [SIGQUIT]="SIGQUIT",
344                 [SIGILL]="SIGILL", [SIGTRAP]="SIGTRAP", [SIGABRT]="SIGABRT",
345                 /* [SIGIOT]="SIGIOT", */ [SIGBUS]="SIGBUS", [SIGFPE]="SIGFPE",
346                 [SIGKILL]="SIGKILL", [SIGUSR1]="SIGUSR1", [SIGSEGV]="SIGSEGV",
347                 [SIGUSR2]="SIGUSR2", [SIGPIPE]="SIGPIPE", [SIGALRM]="SIGALRM",
348                 [SIGTERM]="SIGTERM", [SIGSTKFLT]="SIGSTKFLT", [SIGCHLD]="SIGCHLD",
349                 [SIGCONT]="SIGCONT", [SIGSTOP]="SIGSTOP", [SIGTSTP]="SIGTSTP",
350                 [SIGTTIN]="SIGTTIN", [SIGTTOU]="SIGTTOU", [SIGURG]="SIGURG",
351                 [SIGXCPU]="SIGXCPU", [SIGXFSZ]="SIGXFSZ", [SIGVTALRM]="SIGVTALRM",
352                 [SIGPROF]="SIGPROF", [SIGWINCH]="SIGWINCH", [SIGIO]="SIGIO",
353                 [SIGPWR]="SIGPWR", [SIGSYS]="SIGSYS", /* [SIGUNUSED]="SIGUNUSED", */
354         };
355
356         if (SIGHUP > signo || signo > SIGSYS) {
357                 fprintf(errfile, "Invalid signal number: %d\n", signo);
358                 return;
359         }
360
361         printf("Signal: %d\n"
362                "      (%s)\n",
363                signo,
364                signal_table[signo]);
365 }
366
367 /**
368  * @brief Resolves procedure and module names using libdwfl
369  *
370  * @param proc_info gathered call stack element
371  * @param dwfl dwfl handler
372  */
373 static void __resolve_symbols_from_dwfl(ProcInfo *proc_info, Dwfl *dwfl)
374 {
375         uintptr_t address = proc_info->addr;
376         Dwfl_Module *module = dwfl_addrmodule(dwfl, address);
377         if (module) {
378
379                 Dwarf_Addr mapping_start = 0;
380                 const char *fname = 0;
381                 const char *module_name = dwfl_module_info(module, NULL, &mapping_start, NULL, NULL, NULL, &fname, NULL);
382
383                 proc_info->module_offset = address - mapping_start;
384
385                 if (!proc_info->module_name) {
386                         if (fname)
387                                 proc_info->module_name = strdup(fname);
388                         else if (module_name)
389                                 proc_info->module_name = strdup(module_name);
390                 }
391
392                 const char *symbol = dwfl_module_addrname(module, address);
393                 if (symbol) {
394                         free(proc_info->name);
395                         proc_info->name = strdup(symbol);
396                 }
397                 else if (proc_info->module_name != NULL) {
398                         __find_symbol_in_elf(proc_info, mapping_start);
399                 }
400         }
401 }
402
403 /**
404  * @brief Checks if symbol starts with '_Z' prefix
405  *
406  * @param symbol string to compare
407  */
408 static int is_symbol_demanglable(const char *symbol)
409 {
410         return symbol != 0 && (strlen(symbol) >= 2) &&
411                 symbol[0] == '_' && symbol[1] == 'Z';
412 }
413
414 /**
415  * @brief Replaces symbols with demangled
416  *
417  * @param proc_info gathered call stack element
418  */
419 static void __demangle_symbols(ProcInfo *proc_info)
420 {
421         int status = -1;
422         char *dem_buffer = NULL;
423         char *demangled_symbol = __cxa_demangle(proc_info->name, dem_buffer, NULL, &status);
424         if (status == 0) {
425                 free(proc_info->name);
426                 proc_info->name = demangled_symbol;
427         }
428 }
429
430 /**
431  * @brief Resolves procedure and module name
432  *
433  * @param proc_info gathered call stack element
434  * @param dwfl dwfl handler
435  * @param notes notes handler, NULL if live process analyzed
436  */
437 static void __resolve_symbols(ProcInfo *proc_info, Dwfl *dwfl)
438 {
439         __resolve_symbols_from_dwfl(proc_info, dwfl);
440
441         if (is_symbol_demanglable(proc_info->name))
442                 __demangle_symbols(proc_info);
443 }
444
445 /**
446  * @brief Prints call stack element to the global outputfile.
447  *
448  * @param proc_info gathered call stack element
449  */
450 static void __print_proc_info(ProcInfo *proc_info)
451 {
452         if (proc_info->name) {
453                 fprintf(outputfile, "%s ", proc_info->name);
454                 if (proc_info->offset >= 0)
455                         fprintf(outputfile, "+ 0x%x ", proc_info->offset);
456         }
457         if (sizeof(proc_info->addr) > 4)
458                 fprintf(outputfile, "(0x%016llx)", (long long)proc_info->addr);
459         else
460                 fprintf(outputfile, "(0x%08x)", (int32_t)proc_info->addr);
461
462         if (proc_info->module_name != 0)
463                 fprintf(outputfile, " [%s] + 0x%x", proc_info->module_name, proc_info->module_offset);
464
465         fprintf(outputfile, "\n");
466 }
467
468 /**
469  * @brief Prints call stack to the global outputfile.
470  *
471  * @param callstack gathered call stack database
472  * @param pid PID of the live process
473  */
474 static void __print_callstack(Callstack *callstack, pid_t pid)
475 {
476         fprintf(outputfile, "\nCallstack Information");
477         fprintf(outputfile, " (PID:%d)", pid);
478         fprintf(outputfile, "\nCall Stack Count: %zu\n", callstack->elems);
479
480         size_t it;
481         for (it = 0; it != callstack->elems; ++it) {
482                 fprintf(outputfile, "%2zu: ", it);
483                 __print_proc_info(&callstack->proc[it]);
484         }
485         fprintf(outputfile, "End of Call Stack\n");
486 }
487
488 void callstack_constructor(Callstack *callstack)
489 {
490         size_t it;
491         callstack->elems = 0;
492         for (it = 0; it < (int)sizeof(callstack->proc)/sizeof(callstack->proc[0]); ++it) {
493                 callstack->proc[it].offset = -1;
494                 callstack->proc[it].name = 0;
495                 callstack->proc[it].module_name = 0;
496         }
497 }
498
499 void callstack_destructor(Callstack *callstack)
500 {
501         size_t it;
502         for (it = 0; it < callstack->elems; ++it) {
503                 free(callstack->proc[it].name);
504                 free(callstack->proc[it].module_name);
505         }
506 }
507
508 /**
509  * @brief Print full path of executable file
510  */
511 static void __crash_stack_print_exe(FILE* outputfile, pid_t pid)
512 {
513         int fd, ret;
514         char file_path[PATH_MAX];
515         char cmd_path[PATH_MAX];
516
517         snprintf(cmd_path, PATH_MAX, "/proc/%d/cmdline", pid);
518         if ((fd = open(cmd_path, O_RDONLY)) < 0)
519                 return;
520
521         if ((ret = read(fd, file_path, sizeof(file_path))) <= 0) {
522                 close(fd);
523                 return;
524         }
525         file_path[ret] = '\0';
526
527         fprintf(outputfile, "Executable File Path: %s\n", file_path);
528         close(fd);
529 }
530
531 /**
532  * @brief Print thread information
533  *
534  * @param outputfile File handle for printing report
535  * @param pid PID of the inspected process
536  * @param tid TID of the inspected thread
537  */
538 static void __crash_stack_print_threads(FILE* outputfile, pid_t pid, pid_t tid)
539 {
540         int threadnum=1;
541         DIR *dir;
542         struct dirent entry;
543         struct dirent *dentry=NULL;
544         char task_path[PATH_MAX];
545         struct stat sb;
546
547
548         snprintf(task_path, PATH_MAX, "/proc/%d/task", pid);
549         if (stat(task_path, &sb) == -1) {
550                 return;
551         }
552
553         threadnum = sb.st_nlink - 2;
554
555         if (threadnum > 1) {
556                 fprintf(outputfile, "\nThreads Information\n");
557                 fprintf(outputfile,
558                         "Threads: %d\nPID = %d TID = %d\n",
559                         threadnum, pid, tid);
560                 /* print thread */
561                 dir = opendir(task_path);
562                 if (!dir) {
563                         fprintf(errfile, "[crash-stack] cannot open %s\n", task_path);
564                 } else {
565                         while (readdir_r(dir, &entry, &dentry) == 0 && dentry) {
566                                 if (strcmp(dentry->d_name, ".") == 0 ||
567                                     strcmp(dentry->d_name, "..") == 0)
568                                         continue;
569                                 fprintf(outputfile, "%s ", dentry->d_name);
570                         }
571                         closedir(dir);
572                         fprintf(outputfile, "\n");
573                 }
574         }
575
576 }
577
578 /**
579  * @brief Print information about mapped memory regions
580  *
581  * @param outputfile File handle for printing report.
582  * @param pid PID of the inspected process
583  */
584 static void __crash_stack_print_maps(FILE* outputfile, pid_t pid)
585 {
586         char file_path[PATH_MAX];
587         struct addr_node *head = NULL;
588         struct addr_node *t_node;
589         int fd;
590
591         snprintf(file_path, PATH_MAX, "/proc/%d/maps", pid);
592
593         if ((fd = open(file_path, O_RDONLY)) < 0) {
594                 fprintf(errfile, "[crash-stack] cannot open %s\n", file_path);
595         } else {
596                 /* parsing the maps to get code segment address*/
597                 head = get_addr_list_from_maps(fd);
598                 close(fd);
599         }
600         if (head == NULL) {
601                 return;
602         }
603
604         t_node = head;
605         fprintf(outputfile, "\nMaps Information\n");
606         while (t_node) {
607                 if (!strncmp(STR_ANONY, t_node->fpath, STR_ANONY_LEN)) {
608                         t_node = t_node->next;
609                 } else {
610                         fprintf(outputfile, "%16lx %16lx %s %s\n",
611                                 (unsigned long)t_node->startaddr,
612                                 (unsigned long)t_node->endaddr,
613                                 t_node->perm, t_node->fpath);
614                         t_node = t_node->next;
615                 }
616         }
617         fprintf(outputfile, "End of Maps Information\n");
618         free_all_nodes(head);
619 }
620
621 static struct addr_node *get_addr_list_from_maps(int fd)
622 {
623         int fpath_len, result;
624         uintptr_t saddr;
625         uintptr_t eaddr;
626         char perm[PERM_LEN];
627         char path[PATH_MAX];
628         char addr[ADDR_LEN * 2 + 2];
629         char linebuf[BUF_SIZE];
630         struct addr_node *head = NULL;
631         struct addr_node *tail = NULL;
632         struct addr_node *t_node = NULL;
633
634         /* parsing the maps to get executable code address */
635         while (fgets_fd(linebuf, BUF_SIZE, fd) != NULL) {
636                 memset(path, 0, PATH_MAX);
637                 result = sscanf(linebuf, "%s %s %*s %*s %*s %s ", addr, perm, path);
638                 if (result < 0)
639                         continue;
640                 perm[PERM_LEN - 1] = 0;
641                 /* rwxp */
642                 if ((perm[2] == 'x' && path[0] == '/') ||
643                     (perm[1] == 'w' && path[0] != '/'))
644                 {
645                         char* addr2 = strchr(addr, '-');
646                         *(addr2++) = '\0';
647                         /* add addr node to list */
648                         saddr = strtoul(addr, NULL, HEXA);
649                         /* ffff0000-ffff1000 */
650                         eaddr = strtoul(addr2, NULL, HEXA);
651                         /* make node and attach to the list */
652                         t_node = (struct addr_node *)mmap(0, sizeof(struct addr_node),
653                                                           PROT_READ | PROT_WRITE,
654                                                           MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
655                         if (t_node == NULL) {
656                                 fprintf(errfile, "error : mmap\n");
657                                 return NULL;
658                         }
659                         memcpy(t_node->perm, perm, PERM_LEN);
660                         t_node->startaddr = saddr;
661                         t_node->endaddr = eaddr;
662                         t_node->fpath = NULL;
663                         fpath_len = strlen(path);
664                         if (fpath_len > 0) {
665                                 t_node->fpath = (char *)mmap(0, fpath_len + 1,
666                                                              PROT_READ | PROT_WRITE,
667                                                              MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
668                                 memset(t_node->fpath, 0, fpath_len + 1);
669                                 memcpy(t_node->fpath, path, fpath_len);
670                         } else {
671                                 t_node->fpath = (char *)mmap(0, STR_ANONY_LEN,
672                                                              PROT_READ | PROT_WRITE,
673                                                              MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
674                                 memset(t_node->fpath, 0, STR_ANONY_LEN);
675                                 memcpy(t_node->fpath, STR_ANONY, STR_ANONY_LEN);
676                         }
677                         t_node->next = NULL;
678                         if (head == NULL) {
679                                 head = t_node;
680                                 tail = t_node;
681                         } else {
682                                 tail->next = t_node;
683                                 tail = t_node;
684                         }
685                 }
686         }
687         return head;
688 }
689
690 static void free_all_nodes(struct addr_node *start)
691 {
692         struct addr_node *t_node, *n_node;
693         int fpath_len;
694
695         if (start == NULL)
696                 return;
697         t_node = start;
698         n_node = t_node->next;
699         while (t_node) {
700                 if (t_node->fpath != NULL) {
701                         fpath_len = strlen(t_node->fpath);
702                         munmap(t_node->fpath, fpath_len + 1);
703                 }
704                 munmap(t_node, sizeof(struct addr_node));
705                 if (n_node == NULL)
706                         break;
707                 t_node = n_node;
708                 n_node = n_node->next;
709         }
710 }
711
712 static char *fgets_fd(char *str, int len, int fd)
713 {
714         char ch;
715         register char *cs;
716         int num = 0;
717
718         cs = str;
719         while (--len > 0 && (num = read(fd, &ch, 1) > 0)) {
720                 if ((*cs++ = ch) == '\n')
721                         break;
722         }
723         *cs = '\0';
724         return (num == 0 && cs == str) ? NULL : str;
725 }
726
727 /**
728  * @brief Print process and system memory information
729  *
730  * @param outputfile File handle for printing report.
731  * @param pid PID of the inspected process
732  */
733 static void __crash_stack_print_meminfo(FILE* outputfile, pid_t pid)
734 {
735         char infoname[BUF_SIZE];
736         char memsize[BUF_SIZE];
737         char linebuf[BUF_SIZE];
738         char file_path[PATH_MAX];
739         int fd;
740
741         fprintf(outputfile, "\nMemory information\n");
742
743         if ((fd = open("/proc/meminfo", O_RDONLY)) < 0) {
744                 fprintf(errfile, "[crash-stack] cannot open /proc/meminfo\n");
745         } else {
746                 while (fgets_fd(linebuf, BUF_SIZE, fd) != NULL) {
747                         sscanf(linebuf, "%s %s %*s", infoname, memsize);
748                         if (strcmp("MemTotal:", infoname) == 0) {
749                                 fprintf(outputfile, "%s %8s KB\n", infoname, memsize);
750                         } else if (strcmp("MemFree:", infoname) == 0) {
751                                 fprintf(outputfile, "%s  %8s KB\n", infoname, memsize);
752                         } else if (strcmp("Buffers:", infoname) == 0) {
753                                 fprintf(outputfile, "%s  %8s KB\n", infoname, memsize);
754                         } else if (strcmp("Cached:", infoname) == 0) {
755                                 fprintf(outputfile, "%s   %8s KB\n", infoname, memsize);
756                                 break;
757                         }
758                 }
759                 close(fd);
760         }
761
762         snprintf(file_path, PATH_MAX, "/proc/%d/status", pid);
763         if ((fd = open(file_path, O_RDONLY)) < 0) {
764                 fprintf(errfile, "[crash-stack] cannot open %s\n", file_path);
765         } else {
766                 while (fgets_fd(linebuf, BUF_SIZE, fd) != NULL) {
767                         sscanf(linebuf, "%s %s %*s", infoname, memsize);
768                         if (strcmp("VmPeak:", infoname) == 0) {
769                                 fprintf(outputfile, "%s   %8s KB\n", infoname,
770                                                 memsize);
771                         } else if (strcmp("VmSize:", infoname) == 0) {
772                                 fprintf(outputfile, "%s   %8s KB\n", infoname,
773                                                 memsize);
774                         } else if (strcmp("VmLck:", infoname) == 0) {
775                                 fprintf(outputfile, "%s    %8s KB\n", infoname,
776                                                 memsize);
777                         } else if (strcmp("VmPin:", infoname) == 0) {
778                                 fprintf(outputfile, "%s    %8s KB\n", infoname,
779                                                 memsize);
780                         } else if (strcmp("VmHWM:", infoname) == 0) {
781                                 fprintf(outputfile, "%s    %8s KB\n",
782                                                 infoname, memsize);
783                         } else if (strcmp("VmRSS:", infoname) == 0) {
784                                 fprintf(outputfile, "%s    %8s KB\n",
785                                                 infoname, memsize);
786                         } else if (strcmp("VmData:", infoname) == 0) {
787                                 fprintf(outputfile, "%s   %8s KB\n",
788                                                 infoname, memsize);
789                         } else if (strcmp("VmStk:", infoname) == 0) {
790                                 fprintf(outputfile, "%s    %8s KB\n",
791                                                 infoname, memsize);
792                         } else if (strcmp("VmExe:", infoname) == 0) {
793                                 fprintf(outputfile, "%s    %8s KB\n",
794                                                 infoname, memsize);
795                         } else if (strcmp("VmLib:", infoname) == 0) {
796                                 fprintf(outputfile, "%s    %8s KB\n",
797                                                 infoname, memsize);
798                         } else if (strcmp("VmPTE:", infoname) == 0) {
799                                 fprintf(outputfile, "%s    %8s KB\n",
800                                                 infoname, memsize);
801                         } else if (strcmp("VmSwap:", infoname) == 0) {
802                                 fprintf(outputfile, "%s   %8s KB\n",
803                                                 infoname, memsize);
804                                 break;
805                         }
806                 }
807                 close(fd);
808         }
809 }
810
811 /**
812  * @brief Print information saved in buffer (bufferfile)
813  *
814  * @param bufferfile File handle for reading saved info.
815  * @param outputfile File handle for printing report.
816  */
817 static void __print_buffer_info(FILE* bufferfile, FILE *outputfile)
818 {
819         int cnt;
820         char buf[1024];
821
822         if (fseek(bufferfile, 0, SEEK_SET) < 0) {
823                 fprintf(errfile, "Failed to fseek\n");
824                 return;
825         }
826         while ((cnt = fread(buf, sizeof(char), sizeof(buf), bufferfile)) != 0) {
827                 if (cnt != fwrite(buf, sizeof(char), cnt, outputfile))
828                         break;
829         }
830 }
831
832 /**
833  * @brief Check wchan of thread
834  *
835  * @param pid PID of the inspected process
836  * @param tid TID of the thread to check
837  */
838 static int check_thread_wchan(int pid, int tid)
839 {
840         int fd, cnt;
841         char path[PATH_MAX], buf[100];
842
843         snprintf(path, PATH_MAX, "/proc/%d/task/%d/wchan", pid, tid);
844         fd = open(path, O_RDONLY);
845         if (fd == -1) {
846                 fprintf(errfile, "[crash-stack] cannot open %s\n", path);
847                 return -errno;
848         }
849         cnt = read(fd, buf, sizeof(buf));
850         if (cnt == -1 || cnt == sizeof(buf)) {
851                 fprintf(errfile, "[crash-stack] read %s error\n", path);
852                 close(fd);
853                 return -errno;
854         }
855         buf[cnt] = 0;
856         close(fd);
857
858         if (strncmp("do_coredump", buf, sizeof(buf)) == 0)
859                 return tid;
860         else
861                 return 0;
862 }
863
864 /**
865  * @brief Find crashed tid if tid was not offered
866  *
867  * @param pid PID of the inspected process
868  */
869 static int find_crash_tid(int pid)
870 {
871         int threadnum = 1;
872         int crash_tid = -1;
873         DIR *dir;
874         struct dirent entry;
875         struct dirent *dentry = NULL;
876         char task_path[PATH_MAX];
877         struct stat sb;
878
879         snprintf(task_path, PATH_MAX, "/proc/%d/task", pid);
880         if (stat(task_path, &sb) == -1) {
881                 return -1;
882         }
883
884         threadnum = sb.st_nlink - 2;
885
886         if (threadnum > 1) {
887                 dir = opendir(task_path);
888                 if (!dir) {
889                         fprintf(errfile, "[crash-stack] cannot open %s\n", task_path);
890                         return -1;
891                 } else {
892                         while (readdir_r(dir, &entry, &dentry) == 0 && dentry) {
893                                 if (strcmp(dentry->d_name, ".") == 0 ||
894                                     strcmp(dentry->d_name, "..") == 0)
895                                         continue;
896                                 crash_tid = check_thread_wchan(pid,
897                                                 atoi(dentry->d_name));
898                                 if (crash_tid > 0)
899                                         break;
900                         }
901                         closedir(dir);
902                         return crash_tid;
903                 }
904         }
905         return -1;
906 }
907
908 /**
909  * @brief Main function.
910  *
911  * Main module accepts should be launched with:
912  *
913  *     crash-stack --pid pid [--tid tid] [--sig sig]
914  *
915  * It allows connecting to a live process and displaying its call stack.
916  * It might be also used for connecting to a process from system's core dump handler.
917  */
918 int main(int argc, char **argv)
919 {
920         int c;
921         int signo = 0;
922         pid_t pid = 0;
923         pid_t tid = 0;
924         char bufferfile_path[20] = "/tmp/crash.XXXXXX";
925
926         prctl(PR_SET_DUMPABLE, 0);
927
928         while ((c = getopt_long_only(argc, argv, "", opts, NULL)) != -1) {
929                 switch (c) {
930                 case OPT_PID:
931                         pid = atoi(optarg);
932                         break;
933                 case OPT_TID:
934                         tid = atoi(optarg);
935                         break;
936                 case OPT_SIGNUM:
937                         signo = atoi(optarg);
938                         break;
939                 case OPT_OUTPUTFILE:
940                         outputfile = fopen(optarg, "w");
941                         break;
942                 case OPT_ERRFILE:
943                         errfile = fopen(optarg, "w");
944                         break;
945                 }
946         }
947
948         if (NULL == errfile) errfile = stderr;
949         if (NULL == outputfile) outputfile = stdout;
950
951         if (tid == 0) {
952                 if ((tid = find_crash_tid(pid)) < 0)
953                         tid = pid;
954         }
955
956         if (mkstemp(bufferfile_path) < 0) {
957                 fprintf(errfile, "Failed to create buffer file.\n");
958                 return errno;
959         }
960         bufferfile = fopen(bufferfile_path, "w+");
961         unlink(bufferfile_path);
962
963         argc -= optind;
964
965         elf_version(EV_CURRENT);
966
967         /* First, prepare dwfl and modules */
968         Dwfl *dwfl = NULL;
969
970         /* Executable File Path */
971         __crash_stack_print_exe(outputfile, pid);
972
973         /* Signal information */
974         __crash_stack_print_signal(signo);
975
976         /*
977          * Pre-ptrace info
978          *  Memory, thread, map info should be print in advance
979          *  because some of them will be lost after ptrace analysis
980          */
981
982         /* Memory information */
983         __crash_stack_print_meminfo(bufferfile, pid);
984
985         /* Threads */
986         __crash_stack_print_threads(bufferfile, pid, tid);
987
988         /* Maps information */
989         __crash_stack_print_maps(bufferfile, pid);
990
991         if (pid > 1)
992                 dwfl = __open_dwfl_with_pid(pid, tid);
993         else {
994                 fprintf(errfile,
995                                 "Usage: %s [--output file] [--erroutput file] [--pid <pid> [--tid <tid>]]\n",
996                                 argv[0]);
997                 return 1;
998         }
999
1000         if (NULL == dwfl)
1001                 return 1111;
1002
1003         dwfl_getmodules(dwfl, __module_callback, NULL, 0);
1004
1005         if (-1 == __get_registers_ptrace(tid))
1006                 return 3333;
1007
1008         /* Unwind call stack */
1009         Callstack callstack;
1010         callstack_constructor(&callstack);
1011
1012         _create_crash_stack(dwfl, tid, &callstack);
1013         size_t it;
1014         for (it = 0; it != callstack.elems; ++it)
1015                 __resolve_symbols(&callstack.proc[it], dwfl);
1016
1017         /* Print registers */
1018         _crash_stack_print_regs(outputfile);
1019
1020         /* Print pre-ptrace info */
1021         __print_buffer_info(bufferfile, outputfile);
1022
1023         /* Print the results */
1024         __print_callstack(&callstack, tid);
1025
1026         /* Clean up */
1027         callstack_destructor(&callstack);
1028         dwfl_report_end(dwfl, NULL, NULL);
1029         dwfl_end(dwfl);
1030
1031         return 0;
1032 }