#include "crash-stack.h"
#include <string.h>
#include <elfutils/version.h>
+#include <getopt.h>
+#include <sys/ptrace.h>
+#include <sys/uio.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+static FILE *outputfile = NULL;
+static FILE *errfile = NULL;
+
+enum {
+ OPT_PID,
+ OPT_OUTPUTFILE,
+ OPT_ERRFILE
+};
+
+const struct option opts[] = {
+ { "pid", required_argument, 0, OPT_PID },
+ { "output", required_argument, 0, OPT_OUTPUTFILE },
+ { "erroutput", required_argument, 0, OPT_ERRFILE },
+ { 0, 0, 0, 0 }
+};
extern char *__cxa_demangle (const char *mangled_name, char *output_buffer,
size_t *length, int *status);
mappings->elems++;
}
}
+/* fprintf(errfile, "Got module %s @0x%llx\n", name, (long long)address);*/
return DWARF_CB_OK;
}
else
data = elf64_xlatetom (&out, &in, elf_getident (core, NULL)[EI_DATA]);
if (data == NULL)
- fprintf (stderr, "failed to get value from core file\n");
+ fprintf (errfile, "failed to get value from core file\n");
}
static void updateMapping (Mappings *mappings, uint64_t mapping_start, uint64_t mapping_end,
{
if (nhdr.n_type == NT_FILE)
{
- uint64_t values_cnt, page_size;
+ uint64_t values_cnt = 0, page_size = 0;
const char *values;
const char *filenames;
- size_t addr_size;
+ size_t addr_size = 0;
parse_note_file(core, notes->d_buf + desc_pos, &values_cnt, &page_size, &addr_size, &values, &filenames);
int ii;
for (ii = 0; ii < values_cnt; ii++)
{
- uint64_t mapping_start, mapping_end, offset_in_pages;
+ uint64_t mapping_start = 0, mapping_end = 0, offset_in_pages = 0;
const char *item = values + 3 * addr_size * ii;
get_mapping_item (core, addr_size, item, &mapping_start, &mapping_end, &offset_in_pages);
return NULL;
}
-int main(int argc, char **argv)
+static Dwfl *open_dwfl_with_pid (pid_t pid)
{
- prctl (PR_SET_DUMPABLE, 0);
+ int status;
+ pid_t stopped_pid;
- if (argc != 2)
+ if (ptrace (PTRACE_SEIZE, pid, NULL, PTRACE_O_TRACEEXIT) != 0)
{
- fprintf (stderr, "Usage: %s <core-file>\n", argv[0]);
- return 1;
+ fprintf(errfile, "PTRACE_SEIZE failed on PID %d: %m\n", pid);
+ return NULL;
}
- int core_fd = open (argv[1], O_RDONLY);
- if (core_fd < 0)
+ ptrace (PTRACE_INTERRUPT, pid, 0, 0);
+
+ stopped_pid = waitpid(pid, &status, 0);
+ if (stopped_pid == -1 || stopped_pid != pid || !WIFSTOPPED(status))
{
- perror (argv[1]);
- return 2;
+ fprintf(errfile, "waitpid failed: %m, stopped_pid=%d, status=%d\n", stopped_pid, status);
+ return NULL;
}
- elf_version (EV_CURRENT);
+ static const Dwfl_Callbacks proc_callbacks =
+ {
+ .find_elf = dwfl_linux_proc_find_elf,
+ .find_debuginfo = dwfl_standard_find_debuginfo,
+ .section_address = NULL,
+ .debuginfo_path = NULL
+ };
+
+ Dwfl *dwfl = dwfl_begin (&proc_callbacks);
+ if (dwfl == NULL)
+ {
+ fprintf (errfile, "process %d : Can't start dwfl (%s)\n", pid, dwfl_errmsg(-1));
+ return NULL;
+ }
+
+ if (dwfl_linux_proc_report (dwfl, pid) < 0)
+ {
+ fprintf (errfile, "process %d : dwfl report failed (%s)\n", pid, dwfl_errmsg(-1));
+ dwfl_end (dwfl);
+ return NULL;
+ }
- Elf *core = elf_begin (core_fd, ELF_C_READ_MMAP, NULL);
- if (core == NULL)
+#if _ELFUTILS_PREREQ(0,158)
+ if (dwfl_linux_proc_attach (dwfl, pid, true) < 0)
{
- fprintf (stderr, "%s : Can't open ELF (%s)\n", argv[1], elf_errmsg(-1));
- return 3;
+ fprintf (errfile, "process %d : dwfl attach failed (%s)\n", pid, dwfl_errmsg(-1));
+ dwfl_end (dwfl);
+ return NULL;
}
+#endif
+ return dwfl;
+}
- const Dwfl_Callbacks core_callbacks =
+static Dwfl *open_dwfl_with_core (Elf *core, const char *core_file_name)
+{
+ static const Dwfl_Callbacks core_callbacks =
{
.find_elf = dwfl_build_id_find_elf,
.find_debuginfo = dwfl_standard_find_debuginfo,
Dwfl *dwfl = dwfl_begin (&core_callbacks);
if (dwfl == NULL)
{
- fprintf (stderr, "%s : Can't start dwfl (%s)\n", argv[1], dwfl_errmsg(-1));
- return 4;
+ fprintf (errfile, "%s : Can't start dwfl (%s)\n", core_file_name, dwfl_errmsg(-1));
+ return NULL;
}
#if _ELFUTILS_PREREQ(0,158)
if (dwfl_core_file_report (dwfl, core) < 0)
#endif
{
- fprintf (stderr, "%s : dwfl report failed (%s)\n", argv[1], dwfl_errmsg(-1));
- return 5;
+ fprintf (errfile, "%s : dwfl report failed (%s)\n", core_file_name, dwfl_errmsg(-1));
+ dwfl_end (dwfl);
+ return NULL;
}
#if _ELFUTILS_PREREQ(0,158)
if (dwfl_core_file_attach (dwfl, core) < 0)
{
- fprintf (stderr, "%s : dwfl attach failed (%s)\n", argv[1], dwfl_errmsg(-1));
- return 6;
+ fprintf (errfile, "%s : dwfl attach failed (%s)\n", core_file_name, dwfl_errmsg(-1));
+ dwfl_end (dwfl);
+ return NULL;
}
#endif
+ return dwfl;
+}
- Regs *regs = get_regs_struct();
+static int get_registers_ptrace (pid_t pid)
+{
+ struct iovec data;
+ uintptr_t regbuf[20];
- Mappings mappings;
- mappings.elems = 0;
+ data.iov_base = regbuf;
+ data.iov_len = sizeof (regbuf);
- dwfl_getmodules (dwfl, module_callback, &mappings, 0);
+ if (ptrace (PTRACE_GETREGSET, pid, NT_PRSTATUS, &data) != 0)
+ {
+ fprintf(errfile, "PTRACE_GETREGSET failed on PID %d: %m\n", pid);
+ return -1;
+ }
+
+ size_t i;
+ for (i = 0;
+ i * sizeof (regbuf[0]) < data.iov_len && i < sizeof (regbuf)/sizeof (regbuf[0]);
+ i++)
+ {
+ void *reg = get_place_for_register_value ("", i);
+
+ if (NULL != reg)
+ memcpy (reg, ®buf[i], sizeof (regbuf[i]));
+ }
+ return 0;
+}
+static Elf_Data *get_registers_core (Elf *core, const char *core_file_name, Mappings *mappings)
+{
GElf_Phdr mem;
GElf_Phdr *phdr = gelf_getphdr (core, 0, &mem);
+
if (phdr == NULL || phdr->p_type != PT_NOTE)
{
- fprintf (stderr, "%s : Missing note section at the first position in core file\n", argv[1]);
- return 8;
+ fprintf (errfile, "%s : Missing note section at the first position in core file\n",
+ core_file_name);
+ return NULL;
}
Elf_Data *notes = elf_getdata_rawchunk (core, phdr->p_offset, phdr->p_filesz, ELF_T_NHDR);
if (notes == NULL)
{
- fprintf (stderr, "%s : error getting notes (%s)\n", argv[1], dwfl_errmsg(-1));
- return 9;
+ fprintf (errfile, "%s : error getting notes (%s)\n", core_file_name, dwfl_errmsg(-1));
+ return NULL;
}
Ebl *ebl = ebl_openbackend (core);
if (ebl == NULL)
{
- fprintf (stderr, "%s : Can't initialize ebl\n", argv[1]);
- return 7;
+ fprintf (errfile, "%s : Can't initialize ebl\n", core_file_name);
+ return NULL;
}
GElf_Nhdr nhdr;
got_regs = 1;
- if (0 == ebl_core_note (ebl, &nhdr, "CORE", ®s_offset, &nregloc, ®locs, &nitems, &items))
+ if (0 == ebl_core_note (ebl, &nhdr, "CORE", ®s_offset, &nregloc,
+ ®locs, &nitems, &items))
{
- fprintf (stderr, "%s : error parsing notes\n", argv[1]);
- return 100;
+ fprintf (errfile,
+ "%s : error parsing notes (built with different build of libebl?)\n",
+ core_file_name);
+ return NULL;
}
- const char *regs_location = (const char *)(notes->d_buf) + pos + desc_pos + regs_offset;
+ const char *regs_location = (const char *)(notes->d_buf) + pos + desc_pos
+ + regs_offset;
unsigned i;
for (i = 0; i < nregloc; i++)
{
const char *register_location = regs_location + reglocs[i].offset;
int regnum;
- for (regnum = reglocs[i].regno; regnum < reglocs[i].regno + reglocs[i].count; regnum++)
+ for (regnum = reglocs[i].regno;
+ regnum < reglocs[i].regno + reglocs[i].count;
+ regnum++)
{
char regname[5];
int bits, type;
const char *prefix = 0;
const char *setname = 0;
- ssize_t ret = ebl_register_info (ebl, regnum, regname, sizeof(regname), &prefix, &setname, &bits, &type);
+
+ ssize_t ret = ebl_register_info (ebl, regnum, regname,
+ sizeof(regname), &prefix, &setname,
+ &bits, &type);
if (ret < 0)
{
- fprintf (stderr, "%s : can't get register info\n", argv[1]);
- return 11;
+ fprintf (errfile, "%s : can't get register info\n", core_file_name);
+ return NULL;
}
void *place_for_reg_value = get_place_for_register_value (regname, regnum);
}
else if (nhdr.n_type == NT_FILE)
{
- uint64_t values_cnt, page_size;
+ uint64_t values_cnt = 0, page_size = 0;
const char *values;
const char *filenames;
- size_t addr_size;
+ size_t addr_size = 0;
- parse_note_file(core, notes->d_buf + desc_pos, &values_cnt, &page_size, &addr_size, &values, &filenames);
-// printf("addr_size: %d, mappings: %llu, page size: %llu\n", addr_size, values_cnt, page_size);
+ parse_note_file(core, notes->d_buf + desc_pos, &values_cnt, &page_size,
+ &addr_size, &values, &filenames);
int ii;
/* First: triplets of <mapping-start> <mapping-end> <offset-in-pages>
*/
for (ii = 0; ii < values_cnt; ii++)
{
- uint64_t mapping_start, mapping_end, offset_in_pages;
+ uint64_t mapping_start = 0, mapping_end = 0, offset_in_pages = 0;
const char *item = values + 3 * addr_size * ii;
- get_mapping_item (core, addr_size, item, &mapping_start, &mapping_end, &offset_in_pages);
-/* printf ("<0x%08llx-0x%08llx>@0x%08llx: %s\n", mapping_start, mapping_end, offset_in_pages,
- filenames);
-*/
- updateMapping (&mappings, mapping_start, mapping_end, offset_in_pages*page_size, filenames);
- filenames += strlen(filenames)+1;
+ get_mapping_item (core, addr_size, item, &mapping_start, &mapping_end,
+ &offset_in_pages);
+ updateMapping (mappings, mapping_start, mapping_end,
+ offset_in_pages*page_size, filenames);
+ filenames += strlen (filenames)+1;
}
}
pos = new_pos;
}
+ ebl_closebackend (ebl);
+ return notes;
+}
-/* printf ("PC: 0x%llx\n", (unsigned long long)regs.pc);
- printf ("SP: 0x%llx\n", (unsigned long long)regs.sp);*/
-
- Callstack callstack;
-
- create_crash_stack (regs, dwfl, core, &mappings, &callstack);
+static void printCallstack (Callstack *callstack, Dwfl *dwfl, Elf *core, pid_t pid,
+ Elf_Data *notes)
+{
+ fprintf (outputfile, "Call stack");
+ if (pid > 1) fprintf (outputfile, " for PID %d", pid);
+ fprintf (outputfile, ":\n");
char *dem_buffer = NULL;
size_t it;
-
- printf ("Call stack:\n");
- for (it = 0; it != callstack.elems; ++it)
+ for (it = 0; it != callstack->elems; ++it)
{
- if (sizeof (callstack.tab[0]) > 4)
- printf ("0x%016llx: ", (long long)callstack.tab[it]);
+ if (sizeof (callstack->tab[0]) > 4)
+ fprintf (outputfile, "0x%016llx: ", (long long)callstack->tab[it]);
else
- printf ("0x%08x: ", (int32_t)callstack.tab[it]);
- Dwfl_Module *module = dwfl_addrmodule (dwfl, callstack.tab[it]);
+ fprintf (outputfile, "0x%08x: ", (int32_t)callstack->tab[it]);
+ Dwfl_Module *module = dwfl_addrmodule (dwfl, callstack->tab[it]);
if (module)
{
char *demangled_symbol = 0;
- const char *symbol = dwfl_module_addrname (module, callstack.tab[it]);
+ const char *symbol = dwfl_module_addrname (module, callstack->tab[it]);
const char *fname = 0;
const char *module_name = dwfl_module_info (module, NULL, NULL, NULL, NULL, NULL, &fname, NULL);
char *symbol_from_elf = 0;
if (symbol == NULL)
{
- symbol = symbol_from_elf = try_symbol_from_elfs (core, notes, callstack.tab[it], &fname);
+ symbol = symbol_from_elf = try_symbol_from_elfs (core, notes, callstack->tab[it], &fname);
}
if (symbol != 0 && symbol[0] == '_' && symbol[1] == 'Z')
{
symbol = demangled_symbol;
}
if (symbol != 0)
- printf ("%s()", symbol);
+ fprintf (outputfile, "%s()", symbol);
else
- printf ("<unknown>");
+ fprintf (outputfile, "<unknown>");
if (demangled_symbol != 0)
free (demangled_symbol);
if (symbol_from_elf != 0)
free (symbol_from_elf);
- printf (" from %s\n", fname != NULL ? fname : module_name);
+ fprintf (outputfile, " from %s\n", fname != NULL ? fname : module_name);
}
else
{
- printf ("unknown function\n");
+ fprintf (outputfile, "unknown function\n");
}
}
+}
+
+int main(int argc, char **argv)
+{
+ int c;
+ pid_t pid = 0;
+
+ const char *core_file_name;
+
+ prctl (PR_SET_DUMPABLE, 0);
+
+ while ((c = getopt_long_only(argc, argv, "", opts, NULL)) != -1)
+ {
+ switch (c)
+ {
+ case OPT_PID:
+ pid = atoi(optarg);
+ break;
+ case OPT_OUTPUTFILE:
+ outputfile = fopen(optarg, "w");
+ break;
+ case OPT_ERRFILE:
+ errfile = fopen(optarg, "w");
+ break;
+ }
+ }
+
+ if (NULL == errfile) errfile = stderr;
+ if (NULL == outputfile) outputfile = stdout;
+
+ core_file_name = argv[optind];
+ argc -= optind;
+
+ elf_version (EV_CURRENT);
+
+ /* First, prepare dwfl and modules */
+ Elf *core = NULL;
+ int core_fd = -1;
+ Dwfl *dwfl = NULL;
+
+ if (pid > 1)
+ {
+ dwfl = open_dwfl_with_pid (pid);
+ }
+ else
+ {
+ if (argc != 1)
+ {
+ fprintf (errfile,
+ "Usage: %s [--output file] [--erroutput file] [--pid <pid> | <core-file>]\n",
+ argv[0]);
+ return 1;
+ }
+
+ core_fd = open (core_file_name, O_RDONLY);
+ if (core_fd < 0)
+ {
+ perror (core_file_name);
+ return 2;
+ }
+
+ core = elf_begin (core_fd, ELF_C_READ_MMAP, NULL);
+ if (core == NULL)
+ {
+ fprintf (errfile, "%s : Can't open ELF (%s)\n", core_file_name, elf_errmsg(-1));
+ return 3;
+ }
+
+ dwfl = open_dwfl_with_core (core, core_file_name);
+ }
+
+ if (NULL == dwfl)
+ return 1111;
+
+ Mappings mappings;
+ mappings.elems = 0;
+
+ dwfl_getmodules (dwfl, module_callback, &mappings, 0);
+ Elf_Data *notes = 0;
+
+ /* Now, get registers */
+ if (pid > 1)
+ {
+ if (-1 == get_registers_ptrace (pid))
+ return 3333;
+ }
+ else
+ {
+ notes = get_registers_core (core, core_file_name, &mappings);
+ if (NULL == notes)
+ return 2222;
+ }
+
+ /* Unwind call stack */
+ Callstack callstack;
+
+ create_crash_stack (dwfl, core, pid, &mappings, &callstack);
+
+ /* Print the results */
+ printCallstack (&callstack, dwfl, core, pid, notes);
+ /* Clean up */
dwfl_report_end (dwfl, NULL, NULL);
dwfl_end (dwfl);
- ebl_closebackend(ebl);
- elf_end (core);
- close (core_fd);
+ if (NULL != core) elf_end (core);
+ if (-1 != core_fd) close (core_fd);
return 0;
}