LCOV - code coverage report
Current view: top level - coredump - stacktrace.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 0 99 0.0 %
Date: 2019-08-23 13:36:53 Functions: 0 4 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 70 0.0 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : 
       3                 :            : #include <dwarf.h>
       4                 :            : #include <elfutils/libdwfl.h>
       5                 :            : #include <sys/types.h>
       6                 :            : #include <unistd.h>
       7                 :            : 
       8                 :            : #include "alloc-util.h"
       9                 :            : #include "fileio.h"
      10                 :            : #include "fd-util.h"
      11                 :            : #include "format-util.h"
      12                 :            : #include "macro.h"
      13                 :            : #include "stacktrace.h"
      14                 :            : #include "string-util.h"
      15                 :            : #include "util.h"
      16                 :            : 
      17                 :            : #define FRAMES_MAX 64
      18                 :            : #define THREADS_MAX 64
      19                 :            : 
      20                 :            : struct stack_context {
      21                 :            :         FILE *f;
      22                 :            :         Dwfl *dwfl;
      23                 :            :         Elf *elf;
      24                 :            :         unsigned n_thread;
      25                 :            :         unsigned n_frame;
      26                 :            : };
      27                 :            : 
      28                 :          0 : static int frame_callback(Dwfl_Frame *frame, void *userdata) {
      29                 :          0 :         struct stack_context *c = userdata;
      30                 :          0 :         Dwarf_Addr pc, pc_adjusted, bias = 0;
      31                 :          0 :         _cleanup_free_ Dwarf_Die *scopes = NULL;
      32                 :          0 :         const char *fname = NULL, *symbol = NULL;
      33                 :            :         Dwfl_Module *module;
      34                 :            :         bool is_activation;
      35                 :            : 
      36         [ #  # ]:          0 :         assert(frame);
      37         [ #  # ]:          0 :         assert(c);
      38                 :            : 
      39         [ #  # ]:          0 :         if (c->n_frame >= FRAMES_MAX)
      40                 :          0 :                 return DWARF_CB_ABORT;
      41                 :            : 
      42         [ #  # ]:          0 :         if (!dwfl_frame_pc(frame, &pc, &is_activation))
      43                 :          0 :                 return DWARF_CB_ABORT;
      44                 :            : 
      45                 :          0 :         pc_adjusted = pc - (is_activation ? 0 : 1);
      46                 :            : 
      47                 :          0 :         module = dwfl_addrmodule(c->dwfl, pc_adjusted);
      48         [ #  # ]:          0 :         if (module) {
      49                 :            :                 Dwarf_Die *s, *cudie;
      50                 :            :                 int n;
      51                 :            : 
      52                 :          0 :                 cudie = dwfl_module_addrdie(module, pc_adjusted, &bias);
      53         [ #  # ]:          0 :                 if (cudie) {
      54                 :          0 :                         n = dwarf_getscopes(cudie, pc_adjusted - bias, &scopes);
      55         [ #  # ]:          0 :                         for (s = scopes; s < scopes + n; s++) {
      56   [ #  #  #  # ]:          0 :                                 if (IN_SET(dwarf_tag(s), DW_TAG_subprogram, DW_TAG_inlined_subroutine, DW_TAG_entry_point)) {
      57                 :            :                                         Dwarf_Attribute *a, space;
      58                 :            : 
      59                 :          0 :                                         a = dwarf_attr_integrate(s, DW_AT_MIPS_linkage_name, &space);
      60         [ #  # ]:          0 :                                         if (!a)
      61                 :          0 :                                                 a = dwarf_attr_integrate(s, DW_AT_linkage_name, &space);
      62         [ #  # ]:          0 :                                         if (a)
      63                 :          0 :                                                 symbol = dwarf_formstring(a);
      64         [ #  # ]:          0 :                                         if (!symbol)
      65                 :          0 :                                                 symbol = dwarf_diename(s);
      66                 :            : 
      67         [ #  # ]:          0 :                                         if (symbol)
      68                 :          0 :                                                 break;
      69                 :            :                                 }
      70                 :            :                         }
      71                 :            :                 }
      72                 :            : 
      73         [ #  # ]:          0 :                 if (!symbol)
      74                 :          0 :                         symbol = dwfl_module_addrname(module, pc_adjusted);
      75                 :            : 
      76                 :          0 :                 fname = dwfl_module_info(module, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
      77                 :            :         }
      78                 :            : 
      79                 :          0 :         fprintf(c->f, "#%-2u 0x%016" PRIx64 " %s (%s)\n", c->n_frame, (uint64_t) pc, strna(symbol), strna(fname));
      80                 :          0 :         c->n_frame++;
      81                 :            : 
      82                 :          0 :         return DWARF_CB_OK;
      83                 :            : }
      84                 :            : 
      85                 :          0 : static int thread_callback(Dwfl_Thread *thread, void *userdata) {
      86                 :          0 :         struct stack_context *c = userdata;
      87                 :            :         pid_t tid;
      88                 :            : 
      89         [ #  # ]:          0 :         assert(thread);
      90         [ #  # ]:          0 :         assert(c);
      91                 :            : 
      92         [ #  # ]:          0 :         if (c->n_thread >= THREADS_MAX)
      93                 :          0 :                 return DWARF_CB_ABORT;
      94                 :            : 
      95         [ #  # ]:          0 :         if (c->n_thread != 0)
      96                 :          0 :                 fputc('\n', c->f);
      97                 :            : 
      98                 :          0 :         c->n_frame = 0;
      99                 :            : 
     100                 :          0 :         tid = dwfl_thread_tid(thread);
     101                 :          0 :         fprintf(c->f, "Stack trace of thread " PID_FMT ":\n", tid);
     102                 :            : 
     103         [ #  # ]:          0 :         if (dwfl_thread_getframes(thread, frame_callback, c) < 0)
     104                 :          0 :                 return DWARF_CB_ABORT;
     105                 :            : 
     106                 :          0 :         c->n_thread++;
     107                 :            : 
     108                 :          0 :         return DWARF_CB_OK;
     109                 :            : }
     110                 :            : 
     111                 :          0 : static int make_stack_trace(int fd, const char *executable, char **ret) {
     112                 :            : 
     113                 :            :         static const Dwfl_Callbacks callbacks = {
     114                 :            :                 .find_elf = dwfl_build_id_find_elf,
     115                 :            :                 .find_debuginfo = dwfl_standard_find_debuginfo,
     116                 :            :         };
     117                 :            : 
     118                 :          0 :         struct stack_context c = {};
     119                 :          0 :         char *buf = NULL;
     120                 :          0 :         size_t sz = 0;
     121                 :            :         int r;
     122                 :            : 
     123         [ #  # ]:          0 :         assert(fd >= 0);
     124         [ #  # ]:          0 :         assert(ret);
     125                 :            : 
     126         [ #  # ]:          0 :         if (lseek(fd, 0, SEEK_SET) == (off_t) -1)
     127                 :          0 :                 return -errno;
     128                 :            : 
     129                 :          0 :         c.f = open_memstream_unlocked(&buf, &sz);
     130         [ #  # ]:          0 :         if (!c.f)
     131                 :          0 :                 return -ENOMEM;
     132                 :            : 
     133                 :          0 :         elf_version(EV_CURRENT);
     134                 :            : 
     135                 :          0 :         c.elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
     136         [ #  # ]:          0 :         if (!c.elf) {
     137                 :          0 :                 r = -EINVAL;
     138                 :          0 :                 goto finish;
     139                 :            :         }
     140                 :            : 
     141                 :          0 :         c.dwfl = dwfl_begin(&callbacks);
     142         [ #  # ]:          0 :         if (!c.dwfl) {
     143                 :          0 :                 r = -EINVAL;
     144                 :          0 :                 goto finish;
     145                 :            :         }
     146                 :            : 
     147         [ #  # ]:          0 :         if (dwfl_core_file_report(c.dwfl, c.elf, executable) < 0) {
     148                 :          0 :                 r = -EINVAL;
     149                 :          0 :                 goto finish;
     150                 :            :         }
     151                 :            : 
     152         [ #  # ]:          0 :         if (dwfl_report_end(c.dwfl, NULL, NULL) != 0) {
     153                 :          0 :                 r = -EINVAL;
     154                 :          0 :                 goto finish;
     155                 :            :         }
     156                 :            : 
     157         [ #  # ]:          0 :         if (dwfl_core_file_attach(c.dwfl, c.elf) < 0) {
     158                 :          0 :                 r = -EINVAL;
     159                 :          0 :                 goto finish;
     160                 :            :         }
     161                 :            : 
     162         [ #  # ]:          0 :         if (dwfl_getthreads(c.dwfl, thread_callback, &c) < 0) {
     163                 :          0 :                 r = -EINVAL;
     164                 :          0 :                 goto finish;
     165                 :            :         }
     166                 :            : 
     167                 :          0 :         c.f = safe_fclose(c.f);
     168                 :            : 
     169                 :          0 :         *ret = TAKE_PTR(buf);
     170                 :            : 
     171                 :          0 :         r = 0;
     172                 :            : 
     173                 :          0 : finish:
     174         [ #  # ]:          0 :         if (c.dwfl)
     175                 :          0 :                 dwfl_end(c.dwfl);
     176                 :            : 
     177         [ #  # ]:          0 :         if (c.elf)
     178                 :          0 :                 elf_end(c.elf);
     179                 :            : 
     180                 :          0 :         safe_fclose(c.f);
     181                 :            : 
     182                 :          0 :         free(buf);
     183                 :            : 
     184                 :          0 :         return r;
     185                 :            : }
     186                 :            : 
     187                 :          0 : void coredump_make_stack_trace(int fd, const char *executable, char **ret) {
     188                 :            :         int r;
     189                 :            : 
     190                 :          0 :         r = make_stack_trace(fd, executable, ret);
     191         [ #  # ]:          0 :         if (r == -EINVAL)
     192         [ #  # ]:          0 :                 log_warning("Failed to generate stack trace: %s", dwfl_errmsg(dwfl_errno()));
     193         [ #  # ]:          0 :         else if (r < 0)
     194         [ #  # ]:          0 :                 log_warning_errno(r, "Failed to generate stack trace: %m");
     195                 :          0 : }

Generated by: LCOV version 1.14