Print pre-ptrace info to buffer file
[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         char file_path[PATH_MAX];
514         char link_path[PATH_MAX];
515
516         snprintf(link_path, PATH_MAX, "/proc/%d/exe", pid);
517         if (readlink(link_path, file_path, PATH_MAX) == -1) {
518                 return;
519         }
520         fprintf(outputfile, "Executable File Path: %s\n", file_path);
521 }
522
523 /**
524  * @brief Print thread information
525  *
526  * @param outputfile File handle for printing report
527  * @param pid PID of the inspected process
528  * @param tid TID of the inspected thread
529  */
530 static void __crash_stack_print_threads(FILE* outputfile, pid_t pid, pid_t tid)
531 {
532         int threadnum=1;
533         DIR *dir;
534         struct dirent entry;
535         struct dirent *dentry=NULL;
536         char task_path[PATH_MAX];
537         struct stat sb;
538
539
540         snprintf(task_path, PATH_MAX, "/proc/%d/task", pid);
541         if (stat(task_path, &sb) == -1) {
542                 return;
543         }
544
545         threadnum = sb.st_nlink - 2;
546
547         if (threadnum > 1) {
548                 fprintf(outputfile, "\nThreads Information\n");
549                 fprintf(outputfile,
550                         "Threads: %d\nPID = %d TID = %d\n",
551                         threadnum, pid, tid);
552                 /* print thread */
553                 dir = opendir(task_path);
554                 if (!dir) {
555                         fprintf(errfile, "[crash-stack] cannot open %s\n", task_path);
556                 } else {
557                         while (readdir_r(dir, &entry, &dentry) == 0 && dentry) {
558                                 if (strcmp(dentry->d_name, ".") == 0 ||
559                                     strcmp(dentry->d_name, "..") == 0)
560                                         continue;
561                                 fprintf(outputfile, "%s ", dentry->d_name);
562                         }
563                         closedir(dir);
564                         fprintf(outputfile, "\n");
565                 }
566         }
567
568 }
569
570 /**
571  * @brief Print information about mapped memory regions
572  *
573  * @param outputfile File handle for printing report.
574  * @param pid PID of the inspected process
575  */
576 static void __crash_stack_print_maps(FILE* outputfile, pid_t pid)
577 {
578         char file_path[PATH_MAX];
579         struct addr_node *head = NULL;
580         struct addr_node *t_node;
581         int fd;
582
583         snprintf(file_path, PATH_MAX, "/proc/%d/maps", pid);
584
585         if ((fd = open(file_path, O_RDONLY)) < 0) {
586                 fprintf(errfile, "[crash-stack] cannot open %s\n", file_path);
587         } else {
588                 /* parsing the maps to get code segment address*/
589                 head = get_addr_list_from_maps(fd);
590                 close(fd);
591         }
592         if (head == NULL) {
593                 return;
594         }
595
596         t_node = head;
597         fprintf(outputfile, "\nMaps Information\n");
598         while (t_node) {
599                 if (!strncmp(STR_ANONY, t_node->fpath, STR_ANONY_LEN)) {
600                         t_node = t_node->next;
601                 } else {
602                         fprintf(outputfile, "%16lx %16lx %s %s\n",
603                                 (unsigned long)t_node->startaddr,
604                                 (unsigned long)t_node->endaddr,
605                                 t_node->perm, t_node->fpath);
606                         t_node = t_node->next;
607                 }
608         }
609         fprintf(outputfile, "End of Maps Information\n");
610         free_all_nodes(head);
611 }
612
613 static struct addr_node *get_addr_list_from_maps(int fd)
614 {
615         int fpath_len, result;
616         uintptr_t saddr;
617         uintptr_t eaddr;
618         char perm[PERM_LEN];
619         char path[PATH_MAX];
620         char addr[ADDR_LEN * 2 + 2];
621         char linebuf[BUF_SIZE];
622         struct addr_node *head = NULL;
623         struct addr_node *tail = NULL;
624         struct addr_node *t_node = NULL;
625
626         /* parsing the maps to get executable code address */
627         while (fgets_fd(linebuf, BUF_SIZE, fd) != NULL) {
628                 memset(path, 0, PATH_MAX);
629                 result = sscanf(linebuf, "%s %s %*s %*s %*s %s ", addr, perm, path);
630                 if (result < 0)
631                         continue;
632                 perm[PERM_LEN - 1] = 0;
633                 /* rwxp */
634                 if ((perm[2] == 'x' && path[0] == '/') ||
635                     (perm[1] == 'w' && path[0] != '/'))
636                 {
637                         char* addr2 = strchr(addr, '-');
638                         *(addr2++) = '\0';
639                         /* add addr node to list */
640                         saddr = strtoul(addr, NULL, HEXA);
641                         /* ffff0000-ffff1000 */
642                         eaddr = strtoul(addr2, NULL, HEXA);
643                         /* make node and attach to the list */
644                         t_node = (struct addr_node *)mmap(0, sizeof(struct addr_node),
645                                                           PROT_READ | PROT_WRITE,
646                                                           MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
647                         if (t_node == NULL) {
648                                 fprintf(errfile, "error : mmap\n");
649                                 return NULL;
650                         }
651                         memcpy(t_node->perm, perm, PERM_LEN);
652                         t_node->startaddr = saddr;
653                         t_node->endaddr = eaddr;
654                         t_node->fpath = NULL;
655                         fpath_len = strlen(path);
656                         if (fpath_len > 0) {
657                                 t_node->fpath = (char *)mmap(0, fpath_len + 1,
658                                                              PROT_READ | PROT_WRITE,
659                                                              MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
660                                 memset(t_node->fpath, 0, fpath_len + 1);
661                                 memcpy(t_node->fpath, path, fpath_len);
662                         } else {
663                                 t_node->fpath = (char *)mmap(0, STR_ANONY_LEN,
664                                                              PROT_READ | PROT_WRITE,
665                                                              MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
666                                 memset(t_node->fpath, 0, STR_ANONY_LEN);
667                                 memcpy(t_node->fpath, STR_ANONY, STR_ANONY_LEN);
668                         }
669                         t_node->next = NULL;
670                         if (head == NULL) {
671                                 head = t_node;
672                                 tail = t_node;
673                         } else {
674                                 tail->next = t_node;
675                                 tail = t_node;
676                         }
677                 }
678         }
679         return head;
680 }
681
682 static void free_all_nodes(struct addr_node *start)
683 {
684         struct addr_node *t_node, *n_node;
685         int fpath_len;
686
687         if (start == NULL)
688                 return;
689         t_node = start;
690         n_node = t_node->next;
691         while (t_node) {
692                 if (t_node->fpath != NULL) {
693                         fpath_len = strlen(t_node->fpath);
694                         munmap(t_node->fpath, fpath_len + 1);
695                 }
696                 munmap(t_node, sizeof(struct addr_node));
697                 if (n_node == NULL)
698                         break;
699                 t_node = n_node;
700                 n_node = n_node->next;
701         }
702 }
703
704 static char *fgets_fd(char *str, int len, int fd)
705 {
706         char ch;
707         register char *cs;
708         int num = 0;
709
710         cs = str;
711         while (--len > 0 && (num = read(fd, &ch, 1) > 0)) {
712                 if ((*cs++ = ch) == '\n')
713                         break;
714         }
715         *cs = '\0';
716         return (num == 0 && cs == str) ? NULL : str;
717 }
718
719 /**
720  * @brief Print process and system memory information
721  *
722  * @param outputfile File handle for printing report.
723  * @param pid PID of the inspected process
724  */
725 static void __crash_stack_print_meminfo(FILE* outputfile, pid_t pid)
726 {
727         char infoname[BUF_SIZE];
728         char memsize[BUF_SIZE];
729         char linebuf[BUF_SIZE];
730         char file_path[PATH_MAX];
731         int fd;
732
733         fprintf(outputfile, "\nMemory information\n");
734
735         if ((fd = open("/proc/meminfo", O_RDONLY)) < 0) {
736                 fprintf(errfile, "[crash-stack] cannot open /proc/meminfo\n");
737         } else {
738                 while (fgets_fd(linebuf, BUF_SIZE, fd) != NULL) {
739                         sscanf(linebuf, "%s %s %*s", infoname, memsize);
740                         if (strcmp("MemTotal:", infoname) == 0) {
741                                 fprintf(outputfile, "%s %8s KB\n", infoname, memsize);
742                         } else if (strcmp("MemFree:", infoname) == 0) {
743                                 fprintf(outputfile, "%s  %8s KB\n", infoname, memsize);
744                         } else if (strcmp("Buffers:", infoname) == 0) {
745                                 fprintf(outputfile, "%s  %8s KB\n", infoname, memsize);
746                         } else if (strcmp("Cached:", infoname) == 0) {
747                                 fprintf(outputfile, "%s   %8s KB\n", infoname, memsize);
748                                 break;
749                         }
750                 }
751                 close(fd);
752         }
753
754         snprintf(file_path, PATH_MAX, "/proc/%d/status", pid);
755         if ((fd = open(file_path, O_RDONLY)) < 0) {
756                 fprintf(errfile, "[crash-stack] cannot open %s\n", file_path);
757         } else {
758                 while (fgets_fd(linebuf, BUF_SIZE, fd) != NULL) {
759                         sscanf(linebuf, "%s %s %*s", infoname, memsize);
760                         if (strcmp("VmPeak:", infoname) == 0) {
761                                 fprintf(outputfile, "%s   %8s KB\n", infoname,
762                                                 memsize);
763                         } else if (strcmp("VmSize:", infoname) == 0) {
764                                 fprintf(outputfile, "%s   %8s KB\n", infoname,
765                                                 memsize);
766                         } else if (strcmp("VmLck:", infoname) == 0) {
767                                 fprintf(outputfile, "%s    %8s KB\n", infoname,
768                                                 memsize);
769                         } else if (strcmp("VmPin:", infoname) == 0) {
770                                 fprintf(outputfile, "%s    %8s KB\n", infoname,
771                                                 memsize);
772                         } else if (strcmp("VmHWM:", infoname) == 0) {
773                                 fprintf(outputfile, "%s    %8s KB\n",
774                                                 infoname, memsize);
775                         } else if (strcmp("VmRSS:", infoname) == 0) {
776                                 fprintf(outputfile, "%s    %8s KB\n",
777                                                 infoname, memsize);
778                         } else if (strcmp("VmData:", infoname) == 0) {
779                                 fprintf(outputfile, "%s   %8s KB\n",
780                                                 infoname, memsize);
781                         } else if (strcmp("VmStk:", infoname) == 0) {
782                                 fprintf(outputfile, "%s    %8s KB\n",
783                                                 infoname, memsize);
784                         } else if (strcmp("VmExe:", infoname) == 0) {
785                                 fprintf(outputfile, "%s    %8s KB\n",
786                                                 infoname, memsize);
787                         } else if (strcmp("VmLib:", infoname) == 0) {
788                                 fprintf(outputfile, "%s    %8s KB\n",
789                                                 infoname, memsize);
790                         } else if (strcmp("VmPTE:", infoname) == 0) {
791                                 fprintf(outputfile, "%s    %8s KB\n",
792                                                 infoname, memsize);
793                         } else if (strcmp("VmSwap:", infoname) == 0) {
794                                 fprintf(outputfile, "%s   %8s KB\n",
795                                                 infoname, memsize);
796                                 break;
797                         }
798                 }
799                 close(fd);
800         }
801 }
802
803 /**
804  * @brief Print information saved in buffer (bufferfile)
805  *
806  * @param bufferfile File handle for reading saved info.
807  * @param outputfile File handle for printing report.
808  */
809 static void __print_buffer_info(FILE* bufferfile, FILE *outputfile)
810 {
811         int cnt;
812         char buf[1024];
813
814         if (fseek(bufferfile, 0, SEEK_SET) < 0) {
815                 fprintf(errfile, "Failed to fseek\n");
816                 return;
817         }
818         while ((cnt = fread(buf, sizeof(char), sizeof(buf), bufferfile)) != 0) {
819                 if (cnt != fwrite(buf, sizeof(char), cnt, outputfile))
820                         break;
821         }
822 }
823
824 /**
825  * @brief Check wchan of thread
826  *
827  * @param pid PID of the inspected process
828  * @param tid TID of the thread to check
829  */
830 static int check_thread_wchan(int pid, int tid)
831 {
832         int fd, cnt;
833         char path[PATH_MAX], buf[100];
834
835         snprintf(path, PATH_MAX, "/proc/%d/task/%d/wchan", pid, tid);
836         fd = open(path, O_RDONLY);
837         if (fd == -1) {
838                 fprintf(errfile, "[crash-stack] cannot open %s\n", path);
839                 return -errno;
840         }
841         cnt = read(fd, buf, sizeof(buf));
842         if (cnt == -1 || cnt == sizeof(buf)) {
843                 fprintf(errfile, "[crash-stack] read %s error\n", path);
844                 close(fd);
845                 return -errno;
846         }
847         buf[cnt] = 0;
848         close(fd);
849
850         if (strncmp("do_coredump", buf, sizeof(buf)) == 0)
851                 return tid;
852         else
853                 return 0;
854 }
855
856 /**
857  * @brief Find crashed tid if tid was not offered
858  *
859  * @param pid PID of the inspected process
860  */
861 static int find_crash_tid(int pid)
862 {
863         int threadnum = 1;
864         int crash_tid = -1;
865         DIR *dir;
866         struct dirent entry;
867         struct dirent *dentry = NULL;
868         char task_path[PATH_MAX];
869         struct stat sb;
870
871         snprintf(task_path, PATH_MAX, "/proc/%d/task", pid);
872         if (stat(task_path, &sb) == -1) {
873                 return -1;
874         }
875
876         threadnum = sb.st_nlink - 2;
877
878         if (threadnum > 1) {
879                 dir = opendir(task_path);
880                 if (!dir) {
881                         fprintf(errfile, "[crash-stack] cannot open %s\n", task_path);
882                         return -1;
883                 } else {
884                         while (readdir_r(dir, &entry, &dentry) == 0 && dentry) {
885                                 if (strcmp(dentry->d_name, ".") == 0 ||
886                                     strcmp(dentry->d_name, "..") == 0)
887                                         continue;
888                                 crash_tid = check_thread_wchan(pid,
889                                                 atoi(dentry->d_name));
890                                 if (crash_tid > 0)
891                                         break;
892                         }
893                         closedir(dir);
894                         return crash_tid;
895                 }
896         }
897         return -1;
898 }
899
900 /**
901  * @brief Main function.
902  *
903  * Main module accepts should be launched with:
904  *
905  *     crash-stack --pid pid [--tid tid] [--sig sig]
906  *
907  * It allows connecting to a live process and displaying its call stack.
908  * It might be also used for connecting to a process from system's core dump handler.
909  */
910 int main(int argc, char **argv)
911 {
912         int c;
913         int signo = 0;
914         pid_t pid = 0;
915         pid_t tid = 0;
916         char bufferfile_path[20] = "/tmp/crash.XXXXXX";
917
918         prctl(PR_SET_DUMPABLE, 0);
919
920         while ((c = getopt_long_only(argc, argv, "", opts, NULL)) != -1) {
921                 switch (c) {
922                 case OPT_PID:
923                         pid = atoi(optarg);
924                         break;
925                 case OPT_TID:
926                         tid = atoi(optarg);
927                         break;
928                 case OPT_SIGNUM:
929                         signo = atoi(optarg);
930                         break;
931                 case OPT_OUTPUTFILE:
932                         outputfile = fopen(optarg, "w");
933                         break;
934                 case OPT_ERRFILE:
935                         errfile = fopen(optarg, "w");
936                         break;
937                 }
938         }
939
940         if (NULL == errfile) errfile = stderr;
941         if (NULL == outputfile) outputfile = stdout;
942
943         if (tid == 0) {
944                 if ((tid = find_crash_tid(pid)) < 0)
945                         tid = pid;
946         }
947
948         if (mkstemp(bufferfile_path) < 0) {
949                 fprintf(errfile, "Failed to create buffer file.\n");
950                 return errno;
951         }
952         bufferfile = fopen(bufferfile_path, "w+");
953         unlink(bufferfile_path);
954
955         argc -= optind;
956
957         elf_version(EV_CURRENT);
958
959         /* First, prepare dwfl and modules */
960         Dwfl *dwfl = NULL;
961
962         /* Executable File Path */
963         __crash_stack_print_exe(outputfile, pid);
964
965         /* Signal information */
966         __crash_stack_print_signal(signo);
967
968         /*
969          * Pre-ptrace info
970          *  Memory, thread, map info should be print in advance
971          *  because some of them will be lost after ptrace analysis
972          */
973
974         /* Memory information */
975         __crash_stack_print_meminfo(bufferfile, pid);
976
977         /* Threads */
978         __crash_stack_print_threads(bufferfile, pid, tid);
979
980         /* Maps information */
981         __crash_stack_print_maps(bufferfile, pid);
982
983         if (pid > 1)
984                 dwfl = __open_dwfl_with_pid(pid, tid);
985         else {
986                 fprintf(errfile,
987                                 "Usage: %s [--output file] [--erroutput file] [--pid <pid> [--tid <tid>]]\n",
988                                 argv[0]);
989                 return 1;
990         }
991
992         if (NULL == dwfl)
993                 return 1111;
994
995         dwfl_getmodules(dwfl, __module_callback, NULL, 0);
996
997         if (-1 == __get_registers_ptrace(tid))
998                 return 3333;
999
1000         /* Unwind call stack */
1001         Callstack callstack;
1002         callstack_constructor(&callstack);
1003
1004         _create_crash_stack(dwfl, tid, &callstack);
1005         size_t it;
1006         for (it = 0; it != callstack.elems; ++it)
1007                 __resolve_symbols(&callstack.proc[it], dwfl);
1008
1009         /* Print registers */
1010         _crash_stack_print_regs(outputfile);
1011
1012         /* Print pre-ptrace info */
1013         __print_buffer_info(bufferfile, outputfile);
1014
1015         /* Print the results */
1016         __print_callstack(&callstack, tid);
1017
1018         /* Clean up */
1019         callstack_destructor(&callstack);
1020         dwfl_report_end(dwfl, NULL, NULL);
1021         dwfl_end(dwfl);
1022
1023         return 0;
1024 }