Disable New Crash Stack
[platform/core/system/crash-worker.git] / src / sys-assert / sys-assert.c
1 /*
2  * SYS-ASSERT
3  * Copyright (c) 2012-2016 Samsung Electronics Co., Ltd.
4  *
5  * Licensed under the Apache License, Version 2.0 (the License);
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #define _GNU_SOURCE
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdarg.h>
23 #include <errno.h>
24 #include <execinfo.h>
25 #include <dlfcn.h>
26 #include <elf.h>
27 #include <fcntl.h>
28 #include <ucontext.h>
29 #include <signal.h>
30 #include <linux/unistd.h>
31 #include <sys/mman.h>
32 #include <sys/prctl.h>
33 #include <sys/stat.h>
34 #include <sys/sysinfo.h>
35 #include <sys/socket.h>
36 #include <sys/un.h>
37 #include <unistd.h>
38 #include <dirent.h>
39 #include <time.h>
40 #include <libunwind.h>
41 #include "sys-assert.h"
42 #include "util.h"
43
44 #define CMDLINE_PATH "/proc/self/cmdline"
45 #define EXE_PATH "/proc/self/exe"
46 #define MAPS_PATH "/proc/self/maps"
47 #define MEMINFO_PATH "/proc/meminfo"
48 #define VERINFO_PATH "/etc/info.ini"
49 #define STATUS_PATH "/proc/self/status"
50 #define TASK_PATH "/proc/self/task"
51
52 #define CRASH_INFO_PATH "/tmp/crash_stack"
53 #define CRASH_SOCKET "/tmp/crash_socket"
54 #define CRASH_SOCKET_PATH_LEN 17
55
56 #define CRASH_CALLSTACKINFO_TITLE "Callstack Information"
57 #define CRASH_CALLSTACKINFO_TITLE_E "End of Call Stack"
58 #define CRASH_MAPSINFO_TITLE "Maps Information"
59 #define CRASH_MAPSINFO_TITLE_E "End of Maps Information"
60 #define CRASH_MEMINFO_TITLE "Memory Information"
61 #define CRASH_THREADINFO_TITLE "Threads Information"
62
63 #define STR_ANONY "[anony]"
64 #define STR_ANNOY_LEN 8
65
66 #define HEXA 16
67 #define PERM_LEN 5
68 #ifdef ARCH_64
69 #define ADDR_LEN 10
70 #else
71 #define ADDR_LEN 8
72 #endif
73 #define INFO_LEN 20
74 #define VALUE_LEN 24
75 #define TIME_MAX_LEN 64
76 #define FILE_LEN 255
77 #define BUF_SIZE (BUFSIZ)
78 #define CALLSTACK_SIZE 100
79 #define FUNC_NAME_MAX_LEN 128
80 #define PATH_LEN (FILE_LEN + NAME_MAX)
81
82 #define KB(bytes)       ((bytes)/1024)
83
84 /* permission for open file */
85 #define DIR_PERMS (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
86 /* permission for open file */
87 #define FILE_PERMS (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
88
89 int sig_to_handle[] = {
90         SIGILL, SIGTRAP, SIGABRT, SIGBUS,
91         SIGFPE, SIGSEGV, SIGSTKFLT, SIGXCPU, SIGXFSZ, SIGSYS };
92
93 #define NUM_SIG_TO_HANDLE       \
94         ((int)(sizeof(sig_to_handle)/sizeof(sig_to_handle[0])))
95
96 struct sigaction g_oldact[NUM_SIG_TO_HANDLE];
97
98 extern void dump_registers(int fd, void *context);
99 extern int dump_callstack(void **callstack_addrs, int size, void *context, int retry);
100
101 /* get function symbol from elf */
102 static int trace_symbols(void *const *array, int size, struct addr_node *start, int fd)
103 {
104         Dl_info info_funcs;
105         Elf32_Ehdr elf_h = {{0, }, 0, };
106         Elf32_Shdr *s_headers;
107         Elf32_Sym *symtab_entry;
108         int i, cnt, file, ret;
109         char *fname;
110         unsigned long addr, start_addr, offset_addr;
111         unsigned int strtab_index = 0;
112         unsigned int symtab_index = 0;
113         int num_st = 0;
114         int found_symtab = 0;
115
116         for (cnt = 0; cnt < size; cnt++) {
117                 num_st = 0;
118                 /* FIXME : for walking on stack trace */
119                 if (dladdr(array[cnt], &info_funcs) == 0) {
120                         fprintf(stderr, "[sys-assert]dladdr returnes error!\n");
121                         /* print just address */
122                         fprintf_fd(fd,
123                                         "%2d: (%p) %s\n",
124                                         cnt, array[cnt], dlerror());
125                         continue;
126                 }
127                 start_addr = (unsigned long)get_start_addr(array[cnt], start);
128                 addr = (unsigned long)array[cnt];
129                 /* because of launchpad,
130                  * return value of dladdr when find executable is wrong.
131                  * so fix dli_fname here */
132                 if (info_funcs.dli_fbase &&
133                         info_funcs.dli_fname &&
134                         info_funcs.dli_fbase == (void *)BASE_LAUNCHPAD_ADDR &&
135                         (strncmp("/opt/apps/", info_funcs.dli_fname,
136                                          strlen("/opt/apps/")) == 0)) {
137                         info_funcs.dli_fname = get_fpath(array[cnt], start);
138                         offset_addr = addr;
139                 } else {
140                         offset_addr = addr - start_addr;
141                 }
142
143                 /* find symbol from elf file */
144                 if (info_funcs.dli_sname == NULL) {
145
146                         /* Both dli_sname and dli_fname is NULL, sys-assert cannot trace any information.
147                            Thus, sys-assert skips to translate such address entry.
148                            However, if a developer wants raw information, we need to fix the code to print raw data */
149                         if (info_funcs.dli_fname == NULL)
150                                 continue;
151
152                         file = open(info_funcs.dli_fname, O_RDONLY);
153                         if (file < 0) {
154                                 fname = strchr(info_funcs.dli_fname, '/');
155                                 if (!fname)
156                                         continue;
157                                 file = open(fname, O_RDONLY);
158                                 if (file < 0) {
159                                         fprintf_fd(fd,
160                                                         "%2d: (%p) [%s] + %p\n",
161                                                         cnt, array[cnt],
162                                                         info_funcs.dli_fname, offset_addr);
163                                         continue;
164                                 }
165                         }
166                         ret = read(file, &elf_h, sizeof(Elf32_Ehdr));
167                         if (ret < sizeof(Elf32_Ehdr) ||
168                                         elf_h.e_shnum <= 0 ||
169                                         SHN_LORESERVE < elf_h.e_shnum) {
170                                 fprintf_fd(fd, "%2d: (%p) [%s] + %p\n",
171                                                 cnt, array[cnt], info_funcs.dli_fname, offset_addr);
172                                 close(file);
173                                 continue;
174                         }
175                         if (elf_h.e_type == ET_EXEC) {
176                                 info_funcs.dli_fbase = 0;
177                                 offset_addr = addr;
178                         }
179                         s_headers =
180                                 (Elf32_Shdr *) mmap(0, elf_h.e_shnum * sizeof(Elf32_Shdr),
181                                                 PROT_READ | PROT_WRITE,
182                                                 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
183                         if (s_headers == NULL) {
184                                 fprintf(stderr, "[sys-assert]malloc failed\n");
185                                 fprintf_fd(fd, "%2d: (%p) [%s] + %p\n",
186                                                 cnt, array[cnt], info_funcs.dli_fname, offset_addr);
187                                 close(file);
188                                 continue;
189                         }
190                         ret = lseek(file, elf_h.e_shoff, SEEK_SET);
191                         if (ret < 0 || elf_h.e_shentsize > sizeof(Elf32_Shdr) ||
192                                         elf_h.e_shentsize <= 0) {
193                                 close(file);
194                                 munmap(s_headers, elf_h.e_shnum * sizeof(Elf32_Shdr));
195                                 return -1;
196                         }
197                         for (i = 0; i < elf_h.e_shnum; i++) {
198                                 ret = read(file, &s_headers[i], elf_h.e_shentsize);
199                                 if (ret < elf_h.e_shentsize) {
200                                         fprintf(stderr, "[sys-assert]read error\n");
201                                         munmap(s_headers, elf_h.e_shnum * sizeof(Elf32_Shdr));
202                                         close(file);
203                                         return -1;
204                                 }
205                         }
206                         for (i = 0; i < elf_h.e_shnum; i++) {
207                                 if (s_headers[i].sh_type == SHT_SYMTAB) {
208                                         symtab_index = i;
209                                         if (s_headers[i].sh_entsize != 0 &&
210                                                         s_headers[i].sh_size != 0) {
211                                                 num_st =
212                                                         s_headers[i].sh_size / s_headers[i].sh_entsize;
213                                                 found_symtab = 1;
214                                         }
215                                         break;
216                                 }
217                         }
218                         if (!found_symtab) {
219                                 fprintf(stderr,
220                                                 "[sys-assert] can't find symtab\n");
221                                 munmap(s_headers, elf_h.e_shnum * sizeof(Elf32_Shdr));
222                                 close(file);
223                         } else {
224                                 /*.strtab index */
225                                 if (symtab_index < elf_h.e_shnum)
226                                         strtab_index = s_headers[symtab_index].sh_link;
227                                 if (!strtab_index ||  elf_h.e_shnum <= strtab_index) {
228                                         fprintf_fd(fd, "%2d: (%p) [%s] + %p\n",
229                                                 cnt, array[cnt], info_funcs.dli_fname, offset_addr);
230                                         munmap(s_headers, elf_h.e_shnum * sizeof(Elf32_Shdr));
231                                         close(file);
232                                         continue;
233                                 }
234                                 symtab_entry =
235                                         (Elf32_Sym *)mmap(0, sizeof(Elf32_Sym) * num_st,
236                                                 PROT_READ | PROT_WRITE,
237                                                 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
238                                 if (symtab_entry == NULL) {
239                                         fprintf(stderr, "[sys-assert]malloc failed\n");
240                                         munmap(s_headers, elf_h.e_shnum * sizeof(Elf32_Shdr));
241                                         close(file);
242                                         return -1;
243                                 }
244                                 ret = lseek(file, s_headers[symtab_index].sh_offset, SEEK_SET);
245                                 if (ret < 0) {
246                                         fprintf_fd(fd, "%2d: (%p) [%s] + %p\n",
247                                                 cnt, array[cnt], info_funcs.dli_fname, offset_addr);
248                                         munmap(symtab_entry, sizeof(Elf32_Sym) * num_st);
249                                         munmap(s_headers, elf_h.e_shnum * sizeof(Elf32_Shdr));
250                                         close(file);
251                                         continue;
252                                 }
253                                 for (i = 0; i < num_st; i++) {
254                                         ret = read(file, &symtab_entry[i], sizeof(Elf32_Sym));
255                                         if (ret < sizeof(Elf32_Sym)) {
256                                                 fprintf_fd(fd,
257                                                         "[sys-assert]symtab_entry[%d], num_st=%d, readnum = %d\n",
258                                                                 i, num_st, ret);
259                                                 break;
260                                         }
261                                         if (((info_funcs.dli_fbase +
262                                                                         symtab_entry[i].st_value)
263                                                                 <= array[cnt])
264                                                         && (array[cnt] <=
265                                                                 (info_funcs.dli_fbase +
266                                                                  symtab_entry[i].st_value +
267                                                                  symtab_entry[i].st_size))) {
268                                                 if (symtab_entry[i].st_shndx != STN_UNDEF) {
269                                                         ret = lseek(file,
270                                                                         s_headers[strtab_index].sh_offset +
271                                                                         symtab_entry[i].st_name,
272                                                                         SEEK_SET);
273                                                         if (ret < 0)
274                                                                 break;
275                                                         info_funcs.dli_sname =
276                                                                 (void *)mmap(0, FUNC_NAME_MAX_LEN,
277                                                                         PROT_READ | PROT_WRITE,
278                                                                         MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
279                                                         ret = read(file, (void *)info_funcs.dli_sname,
280                                                                         FUNC_NAME_MAX_LEN);
281                                                         if (ret < 0)
282                                                                 break;
283                                                         info_funcs.dli_saddr =
284                                                                 info_funcs.dli_fbase +
285                                                                 symtab_entry[i].st_value;
286                                                 }
287                                                 break;
288                                         }
289                                 }
290                                 munmap(s_headers, elf_h.e_shnum * sizeof(Elf32_Shdr));
291                                 munmap(symtab_entry, sizeof(Elf32_Sym) * num_st);
292                                 close(file);
293                         }
294                 }
295                 /* print symbol name and address. */
296                 if (info_funcs.dli_sname != NULL) {
297                         if (array[cnt] >= info_funcs.dli_saddr)
298                                 fprintf_fd(fd, "%2d: %s + 0x%x (%p) [%s] + %p\n",
299                                                 cnt, info_funcs.dli_sname,
300                                                 (array[cnt] - info_funcs.dli_saddr),
301                                                 array[cnt], info_funcs.dli_fname, offset_addr);
302                         else
303                                 fprintf_fd(fd, "%2d: %s - 0x%x (%p) [%s] + %p\n",
304                                                 cnt, info_funcs.dli_sname,
305                                                 (info_funcs.dli_saddr - array[cnt]),
306                                                 array[cnt], info_funcs.dli_fname, offset_addr);
307                 } else {
308                         fprintf_fd(fd, "%2d: (%p) [%s] + %p\n",
309                                         cnt, array[cnt], info_funcs.dli_fname, offset_addr);
310                 }
311         }
312         return 0;
313 }
314 /* get address list from maps */
315 static struct addr_node *get_addr_list_from_maps(int fd)
316 {
317         int fpath_len, result;
318         long *saddr;
319         long *eaddr;
320         char perm[PERM_LEN];
321         char path[PATH_LEN];
322         char addr[ADDR_LEN * 2];
323         char linebuf[BUF_SIZE];
324         struct addr_node *head = NULL;
325         struct addr_node *tail = NULL;
326         struct addr_node *t_node = NULL;
327
328         /* parsing the maps to get executable code address */
329         while (fgets_fd(linebuf, BUF_SIZE, fd) != NULL) {
330                 memset(path, 0, PATH_LEN);
331                 result = sscanf(linebuf, "%s %s %*s %*s %*s %s ", addr, perm, path);
332                 if (result < 0)
333                         continue;
334                 perm[PERM_LEN - 1] = 0;
335                 /* rwxp */
336 #ifdef ARCH_ARM
337                 if ((perm[2] == 'x' && path[0] == '/') ||
338                                 (perm[1] == 'w' && path[0] != '/')) {
339 #else
340                 if (strncmp(perm, "r-xp", strlen("r-xp")) == 0) {
341 #endif
342                         /* add addr node to list */
343                         addr[ADDR_LEN] = 0;
344                         saddr = (long *)strtoul(addr, NULL, HEXA);
345                         /* ffff0000-ffff1000 */
346                         eaddr = (long *)strtoul(&addr[ADDR_LEN + 1], NULL, HEXA);
347                         /* make node and attach to the list */
348                         t_node = (struct addr_node *)mmap(0, sizeof(struct addr_node),
349                                         PROT_READ | PROT_WRITE,
350                                         MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
351                         if (t_node == NULL) {
352                                 fprintf(stderr, "error : mmap\n");
353                                 return NULL;
354                         }
355                         memcpy(t_node->perm, perm, PERM_LEN);
356                         t_node->startaddr = saddr;
357                         t_node->endaddr = eaddr;
358                         t_node->fpath = NULL;
359                         fpath_len = strlen(path);
360                         if (fpath_len > 0) {
361                                 t_node->fpath = (char *)mmap(0, fpath_len + 1,
362                                                 PROT_READ | PROT_WRITE,
363                                                 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
364                                 memset(t_node->fpath, 0, fpath_len + 1);
365                                 memcpy(t_node->fpath, path, fpath_len);
366                         } else {
367                                 t_node->fpath = (char *)mmap(0, STR_ANNOY_LEN,
368                                                 PROT_READ | PROT_WRITE,
369                                                 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
370                                 memset(t_node->fpath, 0, STR_ANNOY_LEN);
371                                 memcpy(t_node->fpath, STR_ANONY, STR_ANNOY_LEN);
372                         }
373                         t_node->next = NULL;
374                         if (head == NULL) {
375                                 head = t_node;
376                                 tail = t_node;
377                         } else {
378                                 tail->next = t_node;
379                                 tail = t_node;
380                         }
381                 }
382         }
383         return head;
384 }
385
386 static void print_node_to_file(struct addr_node *start, int fd)
387 {
388         struct addr_node *t_node;
389
390         t_node = start;
391         fprintf_fd(fd, "\n%s\n", CRASH_MAPSINFO_TITLE);
392         while (t_node) {
393                 if (!strncmp(STR_ANONY, t_node->fpath, STR_ANNOY_LEN)) {
394                         t_node = t_node->next;
395                 } else {
396                         fprintf_fd(fd,
397                                         "%16lx %16lx %s %s\n",
398                                         (unsigned long)t_node->startaddr,
399                                         (unsigned long)t_node->endaddr,
400                                         t_node->perm, t_node->fpath);
401                         t_node = t_node->next;
402                 }
403         }
404         fprintf_fd(fd, "%s\n", CRASH_MAPSINFO_TITLE_E);
405 }
406
407 static void free_all_nodes(struct addr_node *start)
408 {
409         struct addr_node *t_node, *n_node;
410         int fpath_len;
411
412         if (start == NULL)
413                 return;
414         t_node = start;
415         n_node = t_node->next;
416         while (t_node) {
417                 if (t_node->fpath != NULL) {
418                         fpath_len = strlen(t_node->fpath);
419                         munmap(t_node->fpath, fpath_len + 1);
420                 }
421                 munmap(t_node, sizeof(struct addr_node));
422                 if (n_node == NULL)
423                         break;
424                 t_node = n_node;
425                 n_node = n_node->next;
426         }
427 }
428
429 static void print_signal_info(int signum, const siginfo_t *info, int fd)
430 {
431         fprintf_fd(fd, "Signal: %d\n", signum);
432         switch (signum) {
433         case SIGILL:
434                 fprintf_fd(fd, "      (SIGILL)\n");
435                 break;
436         case SIGTRAP:
437                 fprintf_fd(fd, "      (SIGTRAP)\n");
438                 break;
439         case SIGABRT:
440                 fprintf_fd(fd, "      (SIGABRT)\n");
441                 break;
442         case SIGBUS:
443                 fprintf_fd(fd, "      (SIGBUS)\n");
444                 break;
445         case SIGFPE:
446                 fprintf_fd(fd, "      (SIGFPE)\n");
447                 break;
448         case SIGSEGV:
449                 fprintf_fd(fd, "      (SIGSEGV)\n");
450                 break;
451         case SIGTERM:
452                 fprintf_fd(fd, "      (SIGTERM)\n");
453                 break;
454         case SIGSTKFLT:
455                 fprintf_fd(fd, "      (SIGSTKFLT)\n");
456                 break;
457         case SIGXCPU:
458                 fprintf_fd(fd, "      (SIGXCPU)\n");
459                 break;
460         case SIGXFSZ:
461                 fprintf_fd(fd, "      (SIGXFSZ)\n");
462                 break;
463         case SIGSYS:
464                 fprintf_fd(fd, "      (SIGSYS)\n");
465                 break;
466         default:
467                 fprintf_fd(fd, "\n");
468         }
469         /* print signal si_code info */
470         fprintf_fd(fd, "      si_code: %d\n", info->si_code);
471         if (info->si_code <= 0 || info->si_code >= 0x80) {
472                 switch (info->si_code) {
473 #ifdef SI_TKILL
474                 case SI_TKILL:
475                         fprintf_fd(fd,
476                                         "      signal sent by tkill (sent by pid %d, uid %d)\n",
477                                 info->si_pid, info->si_uid);
478                         break;
479 #endif
480 #ifdef SI_USER
481                 case SI_USER:
482                         fprintf_fd(fd,
483                                 "      signal sent by kill (sent by pid %d, uid %d)\n",
484                                 info->si_pid, info->si_uid);
485                         break;
486 #endif
487 #ifdef SI_KERNEL
488                 case SI_KERNEL:
489                         fprintf_fd(fd, "      signal sent by the kernel\n");
490                         break;
491 #endif
492                 }
493         } else if (signum == SIGILL) {
494                 switch (info->si_code) {
495                 case ILL_ILLOPC:
496                         fprintf_fd(fd, "      illegal opcode\n");
497                         break;
498                 case ILL_ILLOPN:
499                         fprintf_fd(fd, "      illegal operand\n");
500                         break;
501                 case ILL_ILLADR:
502                         fprintf_fd(fd, "      illegal addressing mode\n");
503                         break;
504                 case ILL_ILLTRP:
505                         fprintf_fd(fd, "      illegal trap\n");
506                         break;
507                 case ILL_PRVOPC:
508                         fprintf_fd(fd, "      privileged opcode\n");
509                         break;
510                 case ILL_PRVREG:
511                         fprintf_fd(fd, "      privileged register\n");
512                         break;
513                 case ILL_COPROC:
514                         fprintf_fd(fd, "      coprocessor error\n");
515                         break;
516                 case ILL_BADSTK:
517                         fprintf_fd(fd, "      internal stack error\n");
518                         break;
519                 default:
520                         fprintf_fd(fd, "      illegal si_code = %d\n", info->si_code);
521                         break;
522                 }
523                 fprintf_fd(fd, "      si_addr: %p\n", info->si_addr);
524         } else if (signum == SIGFPE) {
525                 switch (info->si_code) {
526                 case FPE_INTDIV:
527                         fprintf_fd(fd, "      integer divide by zero\n");
528                         break;
529                 case FPE_INTOVF:
530                         fprintf_fd(fd, "      integer overflow\n");
531                         break;
532                 case FPE_FLTDIV:
533                         fprintf_fd(fd, "      floating-point divide by zero\n");
534                         break;
535                 case FPE_FLTOVF:
536                         fprintf_fd(fd, "      floating-point overflow\n");
537                         break;
538                 case FPE_FLTUND:
539                         fprintf_fd(fd, "      floating-point underflow\n");
540                         break;
541                 case FPE_FLTRES:
542                         fprintf_fd(fd, "      floating-point inexact result\n");
543                         break;
544                 case FPE_FLTINV:
545                         fprintf_fd(fd, "      invalid floating-point operation\n");
546                         break;
547                 case FPE_FLTSUB:
548                         fprintf_fd(fd, "      subscript out of range\n");
549                         break;
550                 default:
551                         fprintf_fd(fd, "      illegal si_code: %d\n", info->si_code);
552                         break;
553                 }
554         } else if (signum == SIGSEGV) {
555                 switch (info->si_code) {
556                 case SEGV_MAPERR:
557                         fprintf_fd(fd, "      address not mapped to object\n");
558                         break;
559                 case SEGV_ACCERR:
560                         fprintf_fd(fd,
561                                         "      invalid permissions for mapped object\n");
562                         break;
563                 default:
564                         fprintf_fd(fd, "      illegal si_code: %d\n", info->si_code);
565                         break;
566                 }
567                 fprintf_fd(fd, "      si_addr = %p\n", info->si_addr);
568         } else if (signum == SIGBUS) {
569                 switch (info->si_code) {
570                 case BUS_ADRALN:
571                         fprintf_fd(fd, "      invalid address alignment\n");
572                         break;
573                 case BUS_ADRERR:
574                         fprintf_fd(fd, "      nonexistent physical address\n");
575                         break;
576                 case BUS_OBJERR:
577                         fprintf_fd(fd, "      object-specific hardware error\n");
578                         break;
579                 default:
580                         fprintf_fd(fd, "      illegal si_code: %d\n", info->si_code);
581                         break;
582                 }
583                 fprintf_fd(fd, "      si_addr: %p\n", info->si_addr);
584         }
585 }
586
587 void sighandler(int signum, siginfo_t *info, void *context)
588 {
589         int idx;
590         int readnum;
591         int threadnum;
592         /* file descriptor */
593         int fd;
594         int fd_cs;              /* for cs file */
595         pid_t pid;
596         pid_t tid;
597         DIR *dir;
598         struct dirent entry;
599         struct dirent *dentry=NULL;
600         char timestr[TIME_MAX_LEN];
601         char processname[NAME_MAX] = {0,};
602         char exepath[PATH_LEN] = {0,};
603         char filepath[PATH_LEN];
604         char crashid[TIME_MAX_LEN] = {0,};
605         /* for get time  */
606         time_t cur_time;
607         /* for get info */
608         char infoname[INFO_LEN];
609         char value[VALUE_LEN];
610         char linebuf[BUF_SIZE];
611         char *p_exepath = NULL;
612         void *callstack_addrs[CALLSTACK_SIZE];
613         int cnt_callstack = 0;
614         /* for backtrace_symbols() */
615         struct addr_node *head = NULL;
616         /* for preventing recursion */
617         static int retry_count = 0;
618         struct sysinfo si = {0,};
619
620         if (retry_count > 1) {
621                 fprintf(stderr, "[sys-assert] recurcive called\n");
622                 return;
623         }
624
625         cur_time = time(NULL);
626         /* get pid */
627         pid = getpid();
628         tid = (long int)syscall(__NR_gettid);
629         /* open maps file */
630         if ((fd = open(MAPS_PATH, O_RDONLY)) < 0) {
631                 fprintf(stderr, "[sys-assert]can't open %s\n", MAPS_PATH);
632         } else {
633                 /* parsing the maps to get code segment address*/
634                 head = get_addr_list_from_maps(fd);
635                 close(fd);
636         }
637         if (retry_count)
638                 fprintf(stderr, "retry backtrace in sighandler");
639         cnt_callstack = dump_callstack(callstack_addrs, CALLSTACK_SIZE, context, retry_count);
640         retry_count += 1;
641         /* get exepath */
642         if ((readnum = open_read(CMDLINE_PATH, exepath, sizeof(exepath) - 1)) <= 0) {
643                 fprintf(stderr, "[sys-assert]can't read %s\n", CMDLINE_PATH);
644                 readnum = snprintf(exepath, sizeof(exepath), "unknown_process");
645         }
646         exepath[readnum] = '\0';
647         /* get processname */
648         if ((p_exepath = remove_path(exepath)) == NULL)
649                 return;
650         snprintf(processname, NAME_MAX, "%s", p_exepath);
651         /* added temporary skip  when crash-worker is asserted */
652         if (!strcmp(processname, "crash-worker") ||
653                         !strcmp(processname, "crash-popup"))
654                 return;
655         /* make crash info file name */
656         snprintf(timestr, sizeof(timestr), "%.10ld", cur_time);
657         snprintf(crashid, sizeof(crashid), "%s_%d", processname, pid);
658         if (snprintf(filepath, PATH_LEN,
659                                 "%s/%s.info", CRASH_INFO_PATH, crashid) == 0) {
660                 fprintf(stderr,
661                                 "[sys-assert]can't make crash info file name : %s\n",
662                                 crashid);
663                 return;
664         }
665         /* check crash info dump directory, make directory if absent */
666         if (access(CRASH_INFO_PATH, F_OK) == -1) {
667                 fprintf(stderr, "[sys-assert] No directory (%s)", CRASH_INFO_PATH);
668                 /*TODO: making directory */
669                 return;
670         }
671         /* logging crash information to stderr */
672         fprintf(stderr, "crashed [%s] processname=%s, pid=%d, tid=%d, signal=%d",
673                         timestr, processname, pid, tid, signum);
674         /* complete filepath_cs */
675         if (!strlen(filepath))
676                 return;
677         /* create cs file */
678         if ((fd_cs = creat(filepath, FILE_PERMS)) < 0) {
679                 fprintf(stderr,
680                                 "[sys-assert]can't create %s. errno = %d\n",
681                                 filepath, errno);
682                 return;
683         }
684
685         /* print exepath info */
686         fprintf_fd(fd_cs, "Executable File Path: %s\n", exepath);
687
688         /* print signal info */
689         print_signal_info(signum, info, fd_cs);
690         fsync(fd_cs);
691         /* print register info */
692         dump_registers(fd_cs, context);
693
694         /* print meminfo */
695         fprintf_fd(fd_cs, "\n%s\n", CRASH_MEMINFO_TITLE);
696          if (!sysinfo(&si)) {
697                  fprintf_fd(fd_cs, "MemTotal: %8ld KB\n", KB(si.totalram));
698                  fprintf_fd(fd_cs, "MemFree:  %8ld KB\n", KB(si.freeram));
699                  fprintf_fd(fd_cs, "Buffers:  %8ld KB\n", KB(si.bufferram));
700         } else
701                 fprintf(stderr, "[sys-assert]can't get sysinfo\n");
702
703         if ((fd = open(MEMINFO_PATH, O_RDONLY)) < 0) {
704                 fprintf(stderr, "[sys-assert]can't open %s\n", MEMINFO_PATH);
705         } else {
706                 while (fgets_fd(linebuf, BUF_SIZE, fd) != NULL) {
707                         sscanf(linebuf, "%s %s %*s", infoname, value);
708                         if (strcmp("Cached:", infoname) == 0) {
709                                 fprintf_fd(fd_cs, "%s   %8s KB\n", infoname, value);
710                                 break;
711                         }
712                 }
713                 close(fd);
714         }
715
716         threadnum = 0;
717         if ((fd = open(STATUS_PATH, O_RDONLY)) < 0) {
718                 fprintf(stderr, "[sys-assert]can't open %s\n", STATUS_PATH);
719         } else {
720                 while (fgets_fd(linebuf, BUF_SIZE, fd) != NULL) {
721                         sscanf(linebuf, "%s %s %*s", infoname, value);
722                         if (strcmp("VmPeak:", infoname) == 0) {
723                                 fprintf_fd(fd_cs, "%s   %8s KB\n", infoname,
724                                                 value);
725                         } else if (strcmp("VmSize:", infoname) == 0) {
726                                 fprintf_fd(fd_cs, "%s   %8s KB\n", infoname,
727                                                 value);
728                         } else if (strcmp("VmLck:", infoname) == 0) {
729                                 fprintf_fd(fd_cs, "%s    %8s KB\n", infoname,
730                                                 value);
731                         } else if (strcmp("VmPin:", infoname) == 0) {
732                                 fprintf_fd(fd_cs, "%s    %8s KB\n", infoname,
733                                                 value);
734                         } else if (strcmp("VmHWM:", infoname) == 0) {
735                                 fprintf_fd(fd_cs, "%s    %8s KB\n",
736                                                 infoname, value);
737                         } else if (strcmp("VmRSS:", infoname) == 0) {
738                                 fprintf_fd(fd_cs, "%s    %8s KB\n",
739                                                 infoname, value);
740                         } else if (strcmp("VmData:", infoname) == 0) {
741                                 fprintf_fd(fd_cs, "%s   %8s KB\n",
742                                                 infoname, value);
743                         } else if (strcmp("VmStk:", infoname) == 0) {
744                                 fprintf_fd(fd_cs, "%s    %8s KB\n",
745                                                 infoname, value);
746                         } else if (strcmp("VmExe:", infoname) == 0) {
747                                 fprintf_fd(fd_cs, "%s    %8s KB\n",
748                                                 infoname, value);
749                         } else if (strcmp("VmLib:", infoname) == 0) {
750                                 fprintf_fd(fd_cs, "%s    %8s KB\n",
751                                                 infoname, value);
752                         } else if (strcmp("VmPTE:", infoname) == 0) {
753                                 fprintf_fd(fd_cs, "%s    %8s KB\n",
754                                                 infoname, value);
755                         } else if (strcmp("VmSwap:", infoname) == 0) {
756                                 fprintf_fd(fd_cs, "%s   %8s KB\n",
757                                                 infoname, value);
758                         } else if (strcmp("Threads:", infoname) == 0) {
759                                 threadnum = atoi(value);
760                                 break;
761                         }
762                 }
763                 close(fd);
764         }
765         /* print thread info */
766         if (1 < threadnum) {
767                 fprintf_fd(fd_cs, "\n%s\n", CRASH_THREADINFO_TITLE);
768                 fprintf_fd(fd_cs,
769                                 "Threads: %d\nPID = %d TID = %d\n",
770                                 threadnum, pid, tid);
771                 /* print thread */
772                 dir = opendir(TASK_PATH);
773                 if (!dir) {
774                         fprintf(stderr, "[sys-assert]can't open %s\n", TASK_PATH);
775                 } else {
776                         while (readdir_r(dir, &entry, &dentry) == 0 && dentry) {
777                                 if (strcmp(dentry->d_name, ".") == 0
778                                                 || strcmp(dentry->d_name, "..") == 0)
779                                         continue;
780                                 fprintf_fd(fd_cs, "%s ", dentry->d_name);
781                         }
782                         closedir(dir);
783                         fprintf_fd(fd_cs, "\n");
784                 }
785         }
786         if (head != NULL) {
787                 /* print maps information */
788                 print_node_to_file(head, fd_cs);
789                 /* print callstack */
790                 fprintf_fd(fd_cs, "\n%s (PID:%d)\n", CRASH_CALLSTACKINFO_TITLE, pid);
791                 fprintf_fd(fd_cs, "Call Stack Count: %d\n", cnt_callstack);
792                 if (trace_symbols(&callstack_addrs[CALLSTACK_BASE],
793                                         cnt_callstack, head, fd_cs) < 0)
794                         fprintf(stderr, "[sys-assert] trace_symbols failed\n");
795                 fprintf_fd(fd_cs, "%s\n", CRASH_CALLSTACKINFO_TITLE_E);
796                 free_all_nodes(head);
797         }
798         /* cs file sync */
799         fsync(fd_cs);
800         /* clean up */
801         if (close(fd_cs) == -1)
802                 fprintf(stderr, "[sys-assert] fd_cs close error!!\n");
803         /* core dump set */
804         if (prctl(PR_GET_DUMPABLE) == 0)
805                 prctl(PR_SET_DUMPABLE, 1);
806
807         for (idx = 0; idx < NUM_SIG_TO_HANDLE; idx++) {
808                 if (sig_to_handle[idx] == signum) {
809                         sigaction(signum, &g_oldact[idx], NULL);
810                         break;
811                 }
812         }
813         raise(signum);
814 }
815
816 __attribute__ ((constructor))
817 void init()
818 {
819         int idx;
820
821         for (idx = 0; idx < NUM_SIG_TO_HANDLE; idx++) {
822                 struct sigaction act;
823                 act.sa_sigaction = (void *)sighandler;
824                 sigemptyset(&act.sa_mask);
825                 act.sa_flags = SA_SIGINFO;
826                 act.sa_flags |= SA_RESETHAND;
827                 if (sigaction(sig_to_handle[idx], &act, &g_oldact[idx]) < 0) {
828                         perror("[sys-assert]could not set signal handler ");
829                         continue;
830                 }
831         }
832 }