From bc90bad27bfd84c69fb074ca87003890d517b4c3 Mon Sep 17 00:00:00 2001 From: Rafal Pietruch Date: Mon, 12 Dec 2016 17:19:07 +0100 Subject: [PATCH 01/16] crash-stack: separate libunw code Change-Id: I1f24781316a78439db862c3ab0d2492fea095c1c --- src/crash-stack/CMakeLists.txt | 1 + src/crash-stack/crash-stack-arm.c | 57 +------------------------- src/crash-stack/crash-stack-libunw.c | 78 ++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 55 deletions(-) create mode 100644 src/crash-stack/crash-stack-libunw.c diff --git a/src/crash-stack/CMakeLists.txt b/src/crash-stack/CMakeLists.txt index 6ad84d1..34c44ea 100644 --- a/src/crash-stack/CMakeLists.txt +++ b/src/crash-stack/CMakeLists.txt @@ -7,6 +7,7 @@ set(CRASH_STACK_BIN "crash-stack") set(CRASH_STACK_SRCS crash-stack.c crash-stack-libelf-helpers.c) # Add architecture dependent source files if (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "armv7l") + set(CRASH_STACK_SRCS ${CRASH_STACK_SRCS} crash-stack-libunw.c) set(CRASH_STACK_SRCS ${CRASH_STACK_SRCS} crash-stack-arm.c) else() if (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64") diff --git a/src/crash-stack/crash-stack-arm.c b/src/crash-stack/crash-stack-arm.c index 7d82911..1a9f5b0 100644 --- a/src/crash-stack/crash-stack-arm.c +++ b/src/crash-stack/crash-stack-arm.c @@ -14,15 +14,14 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Author: Adrian Szyndela - * Rafal Pietruch + * Authors: Adrian Szyndela + * Rafal Pietruch */ /** * @file crash-stack-arm.c * @brief unwinding call stacks, functions specific for ARM */ #include "crash-stack.h" -#include #include #include @@ -37,8 +36,6 @@ #define REG_PC 15 #define REG_SPSR 16 -#define MAXPROCNAMELEN 512 - /** * @brief Important registers for unwinding stack on ARM */ @@ -88,56 +85,6 @@ void _crash_stack_set_ptrace_registers(void *regbuf) } } -void _create_crash_stack(Dwfl *dwfl, Elf *core, pid_t pid, Mappings *mappings, Callstack *callstack) -{ - // reimplemented based on libunwind tests/test-ptrace.c file - unw_addr_space_t as = 0; - void *ui = 0; - do { - callstack->elems = 0; - - as = unw_create_addr_space(&_UPT_accessors, 0); - if (!as) - break; - - ui = _UPT_create(pid); - if (!ui) - break; - - unw_cursor_t cursor; - if (unw_init_remote(&cursor, as, ui) < 0) - break; - - char proc_name[MAXPROCNAMELEN]; - int n; - // MaxDeep as proposed in libunwind tests/test-ptrace.c file - // guard against bad unwind info in old libraries - static const int MaxDeep = 64; - for (n = 0; n < MaxDeep; ++n) { - - unw_word_t ip; - if (unw_get_reg(&cursor, UNW_REG_IP, &ip) < 0) - break; - callstack->tab[callstack->elems] = ip; - - proc_name[0] = '\0'; - unw_word_t off; - unw_get_proc_name(&cursor, proc_name, sizeof(proc_name), &off); - if (strlen(proc_name) > 0) - callstack->proc_name[callstack->elems] = strdup(proc_name); - - ++callstack->elems; - if (unw_step(&cursor) <= 0) - break; - } - } while (0); - - if (ui) - _UPT_destroy(ui); - if (as) - unw_destroy_addr_space(as); -} - void _crash_stack_print_regs(FILE* outputfile) { fprintf(outputfile, "\nRegister Information\n"); diff --git a/src/crash-stack/crash-stack-libunw.c b/src/crash-stack/crash-stack-libunw.c new file mode 100644 index 0000000..dca2af8 --- /dev/null +++ b/src/crash-stack/crash-stack-libunw.c @@ -0,0 +1,78 @@ +/* + * + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Author: Rafal Pietruch + */ +/** + * @file crash-stack-libunw.c + * @brief unwinding call stacks, functions specific for archs that use only libunwind + */ +#include "crash-stack.h" +#include + +#include + +#define MAXPROCNAMELEN 512 + +void _create_crash_stack(Dwfl *dwfl, Elf *core, pid_t pid, Mappings *mappings, Callstack *callstack) +{ + // reimplemented based on libunwind tests/test-ptrace.c file + unw_addr_space_t as = 0; + void *ui = 0; + do { + callstack->elems = 0; + + as = unw_create_addr_space(&_UPT_accessors, 0); + if (!as) + break; + + ui = _UPT_create(pid); + if (!ui) + break; + + unw_cursor_t cursor; + if (unw_init_remote(&cursor, as, ui) < 0) + break; + + char proc_name[MAXPROCNAMELEN]; + int n; + // MaxDeep as proposed in libunwind tests/test-ptrace.c file + // guard against bad unwind info in old libraries + static const int MaxDeep = 64; + for (n = 0; n < MaxDeep; ++n) { + + unw_word_t ip; + if (unw_get_reg(&cursor, UNW_REG_IP, &ip) < 0) + break; + callstack->tab[callstack->elems] = ip; + + proc_name[0] = '\0'; + unw_word_t off; + unw_get_proc_name(&cursor, proc_name, sizeof(proc_name), &off); + if (strlen(proc_name) > 0) + callstack->proc_name[callstack->elems] = strdup(proc_name); + + ++callstack->elems; + if (unw_step(&cursor) <= 0) + break; + } + } while (0); + + if (ui) + _UPT_destroy(ui); + if (as) + unw_destroy_addr_space(as); +} -- 2.7.4 From d19e325e41fc3754cafed1482e4615fa211545e1 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C5=81ukasz=20Stelmach?= Date: Fri, 9 Dec 2016 15:06:14 +0100 Subject: [PATCH 02/16] Update authorship information Change-Id: I064948790ce22c0167ce6986a4d0a0e78fd974ab --- src/crash-pipe/crash-pipe.c | 3 ++- src/crash-stack/crash-stack-aarch64.c | 3 ++- src/crash-stack/crash-stack-arm.c | 1 + src/crash-stack/crash-stack-x86_64.c | 3 ++- src/crash-stack/crash-stack.c | 3 ++- src/crash-stack/crash-stack.h | 3 ++- 6 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/crash-pipe/crash-pipe.c b/src/crash-pipe/crash-pipe.c index 187995b..290513c 100644 --- a/src/crash-pipe/crash-pipe.c +++ b/src/crash-pipe/crash-pipe.c @@ -14,7 +14,8 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Author: Karol Lewandowski + * Authors: Karol Lewandowski + * Łukasz Stelmach */ #define _GNU_SOURCE 1 diff --git a/src/crash-stack/crash-stack-aarch64.c b/src/crash-stack/crash-stack-aarch64.c index 4e8ef32..6461284 100644 --- a/src/crash-stack/crash-stack-aarch64.c +++ b/src/crash-stack/crash-stack-aarch64.c @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Author: Adrian Szyndela + * Authors: Adrian Szyndela + * Łukasz Stelmach */ /** * @file crash-stack-aarch64.c diff --git a/src/crash-stack/crash-stack-arm.c b/src/crash-stack/crash-stack-arm.c index 1a9f5b0..8d91486 100644 --- a/src/crash-stack/crash-stack-arm.c +++ b/src/crash-stack/crash-stack-arm.c @@ -16,6 +16,7 @@ * * Authors: Adrian Szyndela * Rafal Pietruch + * Łukasz Stelmach */ /** * @file crash-stack-arm.c diff --git a/src/crash-stack/crash-stack-x86_64.c b/src/crash-stack/crash-stack-x86_64.c index 8956d30..1aad750 100644 --- a/src/crash-stack/crash-stack-x86_64.c +++ b/src/crash-stack/crash-stack-x86_64.c @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Author: Adrian Szyndela + * Authors: Adrian Szyndela + * Łukasz Stelmach */ /** * @file crash-stack-x86_64.c diff --git a/src/crash-stack/crash-stack.c b/src/crash-stack/crash-stack.c index 5f2f3e2..4c41983 100644 --- a/src/crash-stack/crash-stack.c +++ b/src/crash-stack/crash-stack.c @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Author: Adrian Szyndela + * Authors: Adrian Szyndela + * Łukasz Stelmach */ /** * @file crash-stack.c diff --git a/src/crash-stack/crash-stack.h b/src/crash-stack/crash-stack.h index a706373..714cc18 100644 --- a/src/crash-stack/crash-stack.h +++ b/src/crash-stack/crash-stack.h @@ -14,7 +14,8 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Author: Adrian Szyndela + * Authors: Adrian Szyndela + * Łukasz Stelmach */ /* * @file crash-stack.h -- 2.7.4 From 3ec012cb708cb5f1535ecde6fef3990ca3e73cfb Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C5=81ukasz=20Stelmach?= Date: Tue, 13 Dec 2016 10:33:24 +0100 Subject: [PATCH 03/16] crash-stack: align output format with sys-assert Make crash-stack print register information the very same way as sys-assert does it. Change output format slightly for 64 bit architectures to match hw requirements. Support both i686 and x86_64 in the same architecture specific file. Change-Id: Ica03360b61c1aa133b83c5622334cf4f375db3c2 --- src/crash-stack/CMakeLists.txt | 5 +- src/crash-stack/crash-stack-aarch64.c | 35 ++++++------ src/crash-stack/crash-stack-arm.c | 34 +++++------- src/crash-stack/crash-stack-x86.c | 102 ++++++++++++++++++++++++++++++++++ src/crash-stack/crash-stack-x86_64.c | 73 ------------------------ 5 files changed, 138 insertions(+), 111 deletions(-) create mode 100644 src/crash-stack/crash-stack-x86.c delete mode 100644 src/crash-stack/crash-stack-x86_64.c diff --git a/src/crash-stack/CMakeLists.txt b/src/crash-stack/CMakeLists.txt index 34c44ea..ccf845e 100644 --- a/src/crash-stack/CMakeLists.txt +++ b/src/crash-stack/CMakeLists.txt @@ -14,7 +14,10 @@ else() set(CRASH_STACK_SRCS ${CRASH_STACK_SRCS} crash-stack-aarch64.c) elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64") set(CRASH_STACK_SRCS ${CRASH_STACK_SRCS} crash-stack-libelf.c) - set(CRASH_STACK_SRCS ${CRASH_STACK_SRCS} crash-stack-x86_64.c) + set(CRASH_STACK_SRCS ${CRASH_STACK_SRCS} crash-stack-x86.c) + elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "i686") + set(CRASH_STACK_SRCS ${CRASH_STACK_SRCS} crash-stack-libelf.c) + set(CRASH_STACK_SRCS ${CRASH_STACK_SRCS} crash-stack-x86.c) else() set(CRASH_STACK_SRCS ${CRASH_STACK_SRCS} crash-stack-libelf.c) set(CRASH_STACK_SRCS ${CRASH_STACK_SRCS} crash-stack-stub.c) diff --git a/src/crash-stack/crash-stack-aarch64.c b/src/crash-stack/crash-stack-aarch64.c index 6461284..0c67286 100644 --- a/src/crash-stack/crash-stack-aarch64.c +++ b/src/crash-stack/crash-stack-aarch64.c @@ -103,24 +103,25 @@ void *_get_place_for_register_value(const char *regname, int regnum) void _crash_stack_print_regs(FILE* outputfile) { - int i,top_reg; - - if ((g_registers.pstate & (PSR_MODE32_BIT | PSR_MODE_MASK)) == PSR_MODE32_BIT) { - top_reg = 12; - } else { - top_reg = 29; - } + int i; fprintf(outputfile, "\nRegister Information\n"); - fprintf(outputfile, "pc : [<%016llx>] lr : [<%016llx>] pstate: %08llx\n", - g_registers.pc, g_registers.regs[30], g_registers.pstate); - fprintf(outputfile, "sp : %016llx\n", g_registers.sp); - - for (i = top_reg; i >= 0; i--) { - fprintf(outputfile, "x%-2d: %016llx ", i, g_registers.regs[i]); - if ((i%2) == 0) { - fprintf(outputfile,"\n"); - } + for (i = 0; i <= 30; i++) { + fprintf(outputfile, "x%-2d = 0x%016llx", i, g_registers.regs[i]); + if (i != 30 && 0 == i % 2) + fprintf(outputfile, ", "); + else + fprintf(outputfile, "\n"); } - fprintf(outputfile,"\n"); + fprintf(outputfile, "\n"); + fprintf(outputfile, "xr = 0x%016llx, ip0 = 0x%016llx\nip1 = 0x%016llx, pr = 0x%016llx\n", + g_registers.regs[8], /* Indirect result location register */ + g_registers.regs[16], /* Intra-procedure call scratch register 0 */ + g_registers.regs[17], /* Intra-procedure call scratch register 1 */ + g_registers.regs[18]); /* Platform register */ + fprintf(outputfile, "fp = 0x%016llx, lr = 0x%016llx\npc = 0x%016llx, sp = 0x%016llx\n", + g_registers.regs[29], /* Frame register */ + g_registers.regs[30], /* Procedure link register */ + g_registers.pc, /* Program counter */ + g_registers.sp); /* Stack pointer */ } diff --git a/src/crash-stack/crash-stack-arm.c b/src/crash-stack/crash-stack-arm.c index 8d91486..5f9033f 100644 --- a/src/crash-stack/crash-stack-arm.c +++ b/src/crash-stack/crash-stack-arm.c @@ -89,24 +89,18 @@ void _crash_stack_set_ptrace_registers(void *regbuf) void _crash_stack_print_regs(FILE* outputfile) { fprintf(outputfile, "\nRegister Information\n"); - fprintf(outputfile, "pc : [<%08lx>] lr : [<%08lx>] psr: %08lx\n", - g_ptrace_registers.uregs[REG_PC], g_ptrace_registers.uregs[REG_LR], - g_ptrace_registers.uregs[REG_SPSR] - ); - fprintf(outputfile, "sp : %08lx ip : %08lx fp : %08lx\n", - g_ptrace_registers.uregs[REG_SP], g_ptrace_registers.uregs[REG_IP], - g_ptrace_registers.uregs[REG_FP] - ); - fprintf(outputfile, "r10: %08lx r9 : %08lx r8 : %08lx\n", - g_ptrace_registers.uregs[10], g_ptrace_registers.uregs[9], - g_ptrace_registers.uregs[8] - ); - fprintf(outputfile, "r7 : %08lx r6 : %08lx r5 : %08lx r4 : %08lx\n", - g_ptrace_registers.uregs[7], g_ptrace_registers.uregs[6], - g_ptrace_registers.uregs[5], g_ptrace_registers.uregs[4] - ); - fprintf(outputfile, "r3 : %08lx r2 : %08lx r1 : %08lx r0 : %08lx\n", - g_ptrace_registers.uregs[3], g_ptrace_registers.uregs[2], - g_ptrace_registers.uregs[1], g_ptrace_registers.uregs[0] - ); + fprintf(outputfile, "r0 = 0x%08lx, r1 = 0x%08lx\nr2 = 0x%08lx, r3 = 0x%08lx\n", + g_ptrace_registers.uregs[0], g_ptrace_registers.uregs[1], + g_ptrace_registers.uregs[2], g_ptrace_registers.uregs[3]); + fprintf(outputfile, "r4 = 0x%08lx, r5 = 0x%08lx\nr6 = 0x%08lx, r7 = 0x%08lx\n", + g_ptrace_registers.uregs[4], g_ptrace_registers.uregs[5], + g_ptrace_registers.uregs[6], g_ptrace_registers.uregs[7]); + fprintf(outputfile, "r8 = 0x%08lx, r9 = 0x%08lx\nr10 = 0x%08lx, fp = 0x%08lx\n", + g_ptrace_registers.uregs[8], g_ptrace_registers.uregs[9], + g_ptrace_registers.uregs[10], g_ptrace_registers.uregs[REG_FP]); + fprintf(outputfile, "ip = 0x%08lx, sp = 0x%08lx\nlr = 0x%08lx, pc = 0x%08lx\n", + g_ptrace_registers.uregs[REG_IP], g_ptrace_registers.uregs[REG_SP], + g_ptrace_registers.uregs[REG_LR], g_ptrace_registers.uregs[REG_PC]); + /* XXX the label should probably write "spsr" */ + fprintf(outputfile, "cpsr = 0x%08lx\n", g_ptrace_registers.uregs[REG_SPSR]); } diff --git a/src/crash-stack/crash-stack-x86.c b/src/crash-stack/crash-stack-x86.c new file mode 100644 index 0000000..b63f279 --- /dev/null +++ b/src/crash-stack/crash-stack-x86.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Authors: Adrian Szyndela + * Łukasz Stelmach + */ +/** + * @file crash-stack-x86_64.c + * @brief unwinding call stacks, functions specific for x86_64 + */ +#include "crash-stack.h" +#include +#include + +struct user_regs_struct g_registers; ///< static storage for ptrace buffer for registers + +void *_crash_stack_get_memory_for_ptrace_registers(size_t *size) +{ + if (NULL != size) + *size = sizeof(g_registers); + return &g_registers; +} + +void _crash_stack_set_ptrace_registers(void *regbuf) +{ + void *rsp = _get_place_for_register_value("rsp", 0); + void *rip = _get_place_for_register_value("rip", 0); + + struct user_regs_struct *regs = regbuf; + +#if defined(__x86_64__) + memcpy(rsp, ®s->rsp, sizeof(regs->rsp)); + memcpy(rip, ®s->rip, sizeof(regs->rip)); +#else + memcpy(rsp, ®s->esp, sizeof(regs->esp)); + memcpy(rip, ®s->eip, sizeof(regs->eip)); +#endif +} + +void _crash_stack_print_regs(FILE* outputfile) +{ + fprintf(outputfile, "\nRegister Information\n"); +#if defined(__x86_64__) + fprintf(outputfile, "gs = 0x%016llx, fs = 0x%016llx\nes = 0x%016llx, ds = 0x%016llx\n", + g_registers.gs, + g_registers.fs, + g_registers.es, + g_registers.ds); + fprintf(outputfile, "rdi = 0x%016llx, rsi = 0x%016llx\nrbp = 0x%016llx, rsp = 0x%016llx\n", + g_registers.rdi, + g_registers.rsi, + g_registers.rbp, + g_registers.rsp); + fprintf(outputfile, "rax = 0x%016llx, rbx = 0x%016llx\nrcx = 0x%016llx, rdx = 0x%016llx\n", + g_registers.rax, + g_registers.rbx, + g_registers.rcx, + g_registers.rdx); + fprintf(outputfile, "r8 = 0x%016llx, r9 = 0x%016llx\nr10 = 0x%016llx, r11 = 0x%016llx\n", + g_registers.r8, + g_registers.r9, + g_registers.r10, + g_registers.r11); + fprintf(outputfile, "r12 = 0x%016llx, r13 = 0x%016llx\nr14 = 0x%016llx, r15 = 0x%016llx\n", + g_registers.r12, + g_registers.r13, + g_registers.r14, + g_registers.r15); + fprintf(outputfile, "rip = 0x%016llx\n", + g_registers.rip); +#else + fprintf(outputfile, "gs = 0x%08lx, fs = 0x%08lx\nes = 0x%08lx, ds = 0x%08lx\n", + g_registers.xgs, + g_registers.xfs, + g_registers.xes, + g_registers.xds); + fprintf(outputfile, "edi = 0x%08lx, esi = 0x%08lx\nebp = 0x%08lx, esp = 0x%08lx\n", + g_registers.edi, + g_registers.esi, + g_registers.ebp, + g_registers.esp); + fprintf(outputfile, "eax = 0x%08lx, ebx = 0x%08lx\necx = 0x%08lx, edx = 0x%08lx\n", + g_registers.eax, + g_registers.ebx, + g_registers.ecx, + g_registers.edx); + fprintf(outputfile, "eip = 0x%08lx\n", + g_registers.eip); +#endif +} diff --git a/src/crash-stack/crash-stack-x86_64.c b/src/crash-stack/crash-stack-x86_64.c deleted file mode 100644 index 1aad750..0000000 --- a/src/crash-stack/crash-stack-x86_64.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2016 Samsung Electronics Co., Ltd. - * - * Licensed under the Apache License, Version 2.0 (the License); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Authors: Adrian Szyndela - * Łukasz Stelmach - */ -/** - * @file crash-stack-x86_64.c - * @brief unwinding call stacks, functions specific for x86_64 - */ -#include "crash-stack.h" -#include -#include - -struct user_regs_struct g_registers; ///< static storage for ptrace buffer for registers - -void *_crash_stack_get_memory_for_ptrace_registers(size_t *size) -{ - if (NULL != size) - *size = sizeof(g_registers); - return &g_registers; -} - -void _crash_stack_set_ptrace_registers(void *regbuf) -{ - void *rsp = _get_place_for_register_value("rsp", 0); - void *rip = _get_place_for_register_value("rip", 0); - - struct user_regs_struct *regs = regbuf; - - memcpy(rsp, ®s->rsp, sizeof(regs->rsp)); - memcpy(rip, ®s->rip, sizeof(regs->rip)); -} - -void _crash_stack_print_regs(FILE* outputfile) -{ -#define _PRINT_REGISTERS(a,b,c) \ - fprintf(outputfile, "%3s: %016llx %3s: %016llx %3s: %016llx\n", \ - #a, g_registers.a, \ - #b, g_registers.b, \ - #c, g_registers.c) - fprintf(outputfile, "\nRegister Information\n"); -#ifdef __x86_64__ - fprintf(outputfile, "rip: %04llx:[<%016llx>]\n", - g_registers.cs & 0xffff, - g_registers.rip); - fprintf(outputfile, "rsp: %04llx:%016llx eflags: %08llx\n", - g_registers.ss, - g_registers.rsp, - g_registers.eflags); - _PRINT_REGISTERS(rax, rbx, rcx); - _PRINT_REGISTERS(rdx, rsi, rdi); - _PRINT_REGISTERS(rbp, r8, r9); - _PRINT_REGISTERS(r10, r11, r12); - _PRINT_REGISTERS(r13, r14, r15); -#else - fprintf(outputfile, "Unsupported architecture\n") -#endif - fprintf(outputfile, "\n"); -#undef _PRINT_REGISTERS -} -- 2.7.4 From 31472ebf0024fc84e562c1afad933659703ec51b Mon Sep 17 00:00:00 2001 From: Sunmin Lee Date: Wed, 14 Dec 2016 12:51:31 +0900 Subject: [PATCH 04/16] crash-manager: make secure program - Use secure function (strncat) - Prevent buffer overrun Change-Id: I47acf1bb39c0be123a486116f811b78f30d6ff01 Signed-off-by: Sunmin Lee --- src/crash-manager/crash-manager.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/crash-manager/crash-manager.c b/src/crash-manager/crash-manager.c index a80b3f6..a61f063 100644 --- a/src/crash-manager/crash-manager.c +++ b/src/crash-manager/crash-manager.c @@ -424,14 +424,16 @@ static void dump_system_state(void) static void execute_crash_modules(int argc, char *argv[], int debug) { - int ret, i; + int ret, i, length; char arg_append[PATH_MAX]; char command[PATH_MAX]; + length = 0; arg_append[0] = '\0'; - for (i = 1; i < argc; i++) { - strcat(arg_append, argv[i]); - strcat(arg_append, " "); + for (i = 1; i < argc && length + strlen(argv[i]) + 1 < PATH_MAX; i++) { + strncat(arg_append, argv[i], strlen(argv[i])); + strncat(arg_append, " ", 1); + length += strlen(argv[i]) + 1; } /* Execute crash-pipe */ -- 2.7.4 From a5ac89ecad8aa45921128f8628952b08c4dfe1ed Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C5=81ukasz=20Stelmach?= Date: Tue, 13 Dec 2016 14:01:19 +0100 Subject: [PATCH 05/16] tests: Add a test program for crashing with threads Change-Id: I0b9ef8567b0bb1203fdd9fe3e0aa753e25ff50df --- tests/CMakeLists.txt | 4 ++++ tests/test3.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 tests/test3.c diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 5057355..dc3caee 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -16,3 +16,7 @@ pkg_check_modules (GLIB2 glib-2.0) add_executable(test2 test2.c) target_include_directories(test2 SYSTEM PUBLIC ${GLIB2_INCLUDE_DIRS}) target_link_libraries(test2 ${GLIB2_LDFLAGS}) + +add_executable(test3 test3.c) +target_include_directories(test3 SYSTEM PUBLIC ${GLIB2_INCLUDE_DIRS}) +target_link_libraries(test3 ${GLIB2_LDFLAGS} -lpthread) diff --git a/tests/test3.c b/tests/test3.c new file mode 100644 index 0000000..ca6ae03 --- /dev/null +++ b/tests/test3.c @@ -0,0 +1,46 @@ +#include +#include +#include + +int crash_other_thread = 0; +#define CRASHING_THREAD 19 + +gboolean crasher(gpointer data) +{ + *(int*)data = 1; + return TRUE; +} + +void *fun(void *arg) +{ + int threadnum = (int)arg; + if (crash_other_thread && threadnum == CRASHING_THREAD) + crasher(NULL); + else + while (1); + return NULL; +} + +int main(int argc) +{ + GMainLoop *loop = g_main_loop_new(NULL, FALSE); + + crash_other_thread = argc > 1; + + if (!crash_other_thread) + { + GSource *idle_source = g_idle_source_new(); + g_source_set_callback(idle_source, crasher, NULL, NULL); + g_source_attach(idle_source, g_main_context_ref_thread_default()); + } + + pthread_t t; + int i; + + for (i = 0; i <= CRASHING_THREAD; i++) + pthread_create(&t, NULL, fun, (void *)i); + + g_main_loop_run(loop); + + return 0; +} -- 2.7.4 From a13582d0dc5dd553fa19aa7a4f60ea6b10ed44a9 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C5=81ukasz=20Stelmach?= Date: Tue, 13 Dec 2016 16:03:49 +0100 Subject: [PATCH 06/16] crash-manager: pass tid number to identify failing thread Accept tid as second argument for crash-manager and pass it to crash-stack. Change-Id: Icfc0db6f5675eb781777ea7a7c5dc2d4cb581105 --- src/crash-manager/99-crash-manager.conf.in | 2 +- src/crash-manager/crash-manager.c | 14 +++++++++----- src/crash-stack/crash-stack.c | 6 ++++++ 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/crash-manager/99-crash-manager.conf.in b/src/crash-manager/99-crash-manager.conf.in index 481362f..a58a81c 100644 --- a/src/crash-manager/99-crash-manager.conf.in +++ b/src/crash-manager/99-crash-manager.conf.in @@ -1,3 +1,3 @@ # Tizen crash-manager -kernel.core_pattern=|/usr/bin/crash-manager %p %u %g %s %t %e %E +kernel.core_pattern=|/usr/bin/crash-manager %p %i %u %g %s %t %e %E kernel.core_pipe_limit=10 diff --git a/src/crash-manager/crash-manager.c b/src/crash-manager/crash-manager.c index a80b3f6..604009f 100644 --- a/src/crash-manager/crash-manager.c +++ b/src/crash-manager/crash-manager.c @@ -88,6 +88,7 @@ static bool allow_zip; static struct crash_info { char *cmd_info; char *pid_info; + char *tid_info; char time_info[80]; char temp_dir[PATH_MAX]; char name[FILENAME_MAX]; @@ -217,10 +218,11 @@ static int set_crash_info(char *argv[]) time_t time_val; struct tm loc_tm; - crash_info.cmd_info = argv[6]; crash_info.pid_info = argv[1]; + crash_info.tid_info = argv[2]; + crash_info.cmd_info = argv[7]; - time_val = atoll(argv[5]); + time_val = atoll(argv[6]); localtime_r(&time_val, &loc_tm); strftime(crash_info.time_info, sizeof(crash_info.time_info), "%Y%m%d%H%M%S", &loc_tm); @@ -456,9 +458,11 @@ static void execute_crash_modules(int argc, char *argv[], int debug) /* Execute crash-stack */ /* ret = snprintf(command, sizeof(command), - "%s --pid %s >> %s", + "%s --pid %s --tid %s >> %s", CRASH_STACK_PATH, - crash_info.pid_info, crash_info.info_path); + crash_info.pid_info, + crash_info.tid_info, + crash_info.info_path); if (ret < 0) { _E("Failed to snprintf for crash-stack command"); return; @@ -766,7 +770,7 @@ int main(int argc, char *argv[]) /* .dbugmode: launch crash-popup */ if (access(DEBUGMODE_FILE, F_OK) == 0) - launch_crash_popup(argv[7]); + launch_crash_popup(argv[8]); /* Exec dump_systemstate */ dump_system_state(); diff --git a/src/crash-stack/crash-stack.c b/src/crash-stack/crash-stack.c index 4c41983..0ec8990 100644 --- a/src/crash-stack/crash-stack.c +++ b/src/crash-stack/crash-stack.c @@ -58,6 +58,7 @@ static FILE *errfile = NULL; ///< global error stream */ enum { OPT_PID, + OPT_TID, OPT_OUTPUTFILE, OPT_ERRFILE }; @@ -67,6 +68,7 @@ enum { */ const struct option opts[] = { { "pid", required_argument, 0, OPT_PID }, + { "tid", required_argument, 0, OPT_TID }, { "output", required_argument, 0, OPT_OUTPUTFILE }, { "erroutput", required_argument, 0, OPT_ERRFILE }, { 0, 0, 0, 0 } @@ -710,6 +712,7 @@ int main(int argc, char **argv) { int c, i; pid_t pid = 0; + /* pid_t tid = 0; */ const char *core_file_name; @@ -720,6 +723,9 @@ int main(int argc, char **argv) case OPT_PID: pid = atoi(optarg); break; + case OPT_TID: + /* tid = atoi(optarg); */ + break; case OPT_OUTPUTFILE: outputfile = fopen(optarg, "w"); break; -- 2.7.4 From d798192a609c2c5f558447e43cd219fac34333ac Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C5=81ukasz=20Stelmach?= Date: Wed, 14 Dec 2016 14:51:14 +0100 Subject: [PATCH 07/16] crash-stack: print information about threads Change-Id: Ib0e2d9c2bdbd5fd4eacc0608a8c5ecccdfd4f2a8 --- src/crash-stack/crash-stack.c | 64 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 5 deletions(-) diff --git a/src/crash-stack/crash-stack.c b/src/crash-stack/crash-stack.c index 0ec8990..2e3b86f 100644 --- a/src/crash-stack/crash-stack.c +++ b/src/crash-stack/crash-stack.c @@ -48,6 +48,8 @@ #include #include #include +#include +#include static siginfo_t __siginfo; static FILE *outputfile = NULL; ///< global output stream @@ -646,9 +648,10 @@ static Elf_Data *__get_registers_core(Elf *core, const char *core_file_name, Map static void __print_callstack(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"); + fprintf(outputfile, "\nCallstack Information"); + if (pid > 1) fprintf(outputfile, " (PID:%d)", pid); + fprintf(outputfile, "\n"); + fprintf(outputfile, "Call Stack Count: %d\n", (int)callstack->elems); char *dem_buffer = NULL; size_t it; @@ -694,6 +697,54 @@ static void __print_callstack(Callstack *callstack, Dwfl *dwfl, Elf *core, pid_t fprintf(outputfile, "unknown function\n"); } } + fprintf(outputfile, "End of Call Stack\n"); +} + +/** + * @brief Print thread information + * + * @param outputfile File handle for printing report. + * @param pid PID of the inspected process + * @param tid TID of the inspected thread + */ +static void __crash_stack_print_threads(FILE* outputfile, pid_t pid, pid_t tid) +{ + int threadnum=1; + DIR *dir; + struct dirent entry; + struct dirent *dentry=NULL; + char task_path[PATH_MAX]; + struct stat sb; + + + snprintf(task_path, PATH_MAX, "/proc/%d/task", pid); + if (stat(task_path, &sb) == -1) { + return; + } + + threadnum = sb.st_nlink - 2; + + if (threadnum > 1) { + fprintf(outputfile, "\nThreads Information\n"); + fprintf(outputfile, + "Threads: %d\nPID = %d TID = %d\n", + threadnum, pid, tid); + /* print thread */ + dir = opendir(task_path); + if (!dir) { + fprintf(stderr, "[crash-stack] cannot open %s\n", task_path); + } else { + while (readdir_r(dir, &entry, &dentry) == 0 && dentry) { + if (strcmp(dentry->d_name, ".") == 0 || + strcmp(dentry->d_name, "..") == 0) + continue; + fprintf(outputfile, "%s ", dentry->d_name); + } + closedir(dir); + fprintf(outputfile, "\n"); + } + } + } /** @@ -712,7 +763,7 @@ int main(int argc, char **argv) { int c, i; pid_t pid = 0; - /* pid_t tid = 0; */ + pid_t tid = 0; const char *core_file_name; @@ -724,7 +775,7 @@ int main(int argc, char **argv) pid = atoi(optarg); break; case OPT_TID: - /* tid = atoi(optarg); */ + tid = atoi(optarg); break; case OPT_OUTPUTFILE: outputfile = fopen(optarg, "w"); @@ -804,6 +855,9 @@ int main(int argc, char **argv) /* Print registers */ _crash_stack_print_regs(outputfile); + /* Threads */ + __crash_stack_print_threads(outputfile, pid, tid); + /* Print the results */ __print_callstack(&callstack, dwfl, core, pid, notes); -- 2.7.4 From ff899b6ecdb1f6fa05b654aeda8ea6bb88b4f1e1 Mon Sep 17 00:00:00 2001 From: Rafal Pietruch Date: Wed, 14 Dec 2016 08:17:39 +0100 Subject: [PATCH 08/16] crash-stack: resolving symbols extracted from printing function Change-Id: I0ae01bc7a2a9a0e6f084a9e275e1025058645c77 --- src/crash-stack/crash-stack-aarch64.c | 6 +- src/crash-stack/crash-stack-libelf.c | 8 +- src/crash-stack/crash-stack-libunw.c | 4 +- src/crash-stack/crash-stack.c | 182 +++++++++++++++++++++++++--------- src/crash-stack/crash-stack.h | 14 ++- 5 files changed, 153 insertions(+), 61 deletions(-) diff --git a/src/crash-stack/crash-stack-aarch64.c b/src/crash-stack/crash-stack-aarch64.c index 0c67286..420cb9b 100644 --- a/src/crash-stack/crash-stack-aarch64.c +++ b/src/crash-stack/crash-stack-aarch64.c @@ -64,8 +64,8 @@ void _crash_stack_set_ptrace_registers(void *regbuf) void _create_crash_stack(Dwfl *dwfl, Elf *core, pid_t pid, Mappings *mappings, Callstack *callstack) { callstack->elems = 0; - callstack->tab[callstack->elems++] = g_regs.pc; - callstack->tab[callstack->elems++] = g_regs.x30; + callstack->proc[callstack->elems++].addr = g_regs.pc; + callstack->proc[callstack->elems++].addr = g_regs.x30; bool end = false; @@ -78,7 +78,7 @@ void _create_crash_stack(Dwfl *dwfl, Elf *core, pid_t pid, Mappings *mappings, C g_regs.x29 + sizeof(newx29), &newx30, sizeof(newx30), mappings); if (read29 && read30) { - callstack->tab[callstack->elems++] = newx30; + callstack->proc[callstack->elems++].addr = newx30; g_regs.x29 = newx29; } else end = true; diff --git a/src/crash-stack/crash-stack-libelf.c b/src/crash-stack/crash-stack-libelf.c index ff165c1..c341c96 100644 --- a/src/crash-stack/crash-stack-libelf.c +++ b/src/crash-stack/crash-stack-libelf.c @@ -49,7 +49,7 @@ static int __frame_callback(Dwfl_Frame *state, void *arg) Callstack *callstack = (Callstack*)arg; Dwarf_Addr address; dwfl_frame_pc(state, &address, NULL); - callstack->tab[callstack->elems++] = address; + callstack->proc[callstack->elems++].addr = address; return callstack->elems < MAX_CALLSTACK_LEN ? DWARF_CB_OK : DWARF_CB_ABORT; } @@ -147,7 +147,7 @@ static void _explore_stack_in_search_of_functions(Dwfl *dwfl, Elf *core, pid_t p dwfl_module_addrsym(module, value, &sym, &shndxp); Elf_Scn *scn = dwfl_module_address_section(module, &elfval, &bias); if (scn != 0 || shndxp != -1) { - callstack->tab[callstack->elems++] = value; + callstack->proc[callstack->elems++].addr = value; if (callstack->elems >= MAX_CALLSTACK_LEN) return; } @@ -156,7 +156,7 @@ static void _explore_stack_in_search_of_functions(Dwfl *dwfl, Elf *core, pid_t p int i; for (i = 0; i < mappings->elems; i++) { if (mappings->tab[i].m_start <= elfval && elfval < mappings->tab[i].m_end) { - callstack->tab[callstack->elems++] = value; + callstack->proc[callstack->elems++].addr = value; break; } } @@ -173,7 +173,7 @@ void _create_crash_stack(Dwfl *dwfl, Elf *core, pid_t pid, Mappings *mappings, C #if _ELFUTILS_PREREQ(0,158) dwfl_getthreads(dwfl, __thread_callback, callstack); #else - callstack->tab[callstack->elems++] = sizeof(uintptr_t) == 4 ? g_pc.reg32 : g_pc.reg64; + callstack->proc[callstack->elems++].addr = sizeof(uintptr_t) == 4 ? g_pc.reg32 : g_pc.reg64; _explore_stack_in_search_of_functions(dwfl, core, pid, mappings, callstack); #endif } diff --git a/src/crash-stack/crash-stack-libunw.c b/src/crash-stack/crash-stack-libunw.c index dca2af8..ba0b245 100644 --- a/src/crash-stack/crash-stack-libunw.c +++ b/src/crash-stack/crash-stack-libunw.c @@ -57,13 +57,13 @@ void _create_crash_stack(Dwfl *dwfl, Elf *core, pid_t pid, Mappings *mappings, C unw_word_t ip; if (unw_get_reg(&cursor, UNW_REG_IP, &ip) < 0) break; - callstack->tab[callstack->elems] = ip; + callstack->proc[callstack->elems].addr = ip; proc_name[0] = '\0'; unw_word_t off; unw_get_proc_name(&cursor, proc_name, sizeof(proc_name), &off); if (strlen(proc_name) > 0) - callstack->proc_name[callstack->elems] = strdup(proc_name); + callstack->proc[callstack->elems].name = strdup(proc_name); ++callstack->elems; if (unw_step(&cursor) <= 0) diff --git a/src/crash-stack/crash-stack.c b/src/crash-stack/crash-stack.c index 2e3b86f..e1cabf9 100644 --- a/src/crash-stack/crash-stack.c +++ b/src/crash-stack/crash-stack.c @@ -637,65 +637,150 @@ static Elf_Data *__get_registers_core(Elf *core, const char *core_file_name, Map } /** - * @brief Prints call stack to the screen. + * @brief Resolves procedure and module names using libdwfl * - * @param callstack gathered call stack database + * @param proc_info gathered call stack element + * @param dwfl dwfl handler + */ +static void __resolve_symbols_from_dwfl(ProcInfo *proc_info, Dwfl *dwfl) +{ + uintptr_t address = proc_info->addr; + Dwfl_Module *module = dwfl_addrmodule(dwfl, address); + if (module) { + + const char *module_name = proc_info->module_name; + if (!module_name) { + const char *fname = 0; + const char *module_name = dwfl_module_info(module, NULL, NULL, NULL, NULL, NULL, &fname, NULL); + if (fname) + proc_info->module_name = strdup(fname); + else if (module_name) + proc_info->module_name = strdup(module_name); + } + const char *symbol = proc_info->name; + if (!symbol) { + symbol = dwfl_module_addrname(module, proc_info->addr); + if (symbol) + proc_info->name = strdup(symbol); + } + } +} + +/** + * @brief Resolves procedure and module names using elfutils + * + * @param proc_info gathered call stack element + * @param core ELF handler for the core dump file, NULL if live process analyzed + * @param notes notes handler, NULL if live process analyzed + */ +static void __resolve_symbols_from_elf(ProcInfo *proc_info, Elf *core, Elf_Data *notes) +{ + const char *fname = 0; + char *symbol_from_elf = __try_symbol_from_elfs(core, notes, proc_info->addr, &fname); + if (!proc_info->module_name && fname) + proc_info->module_name = strdup(fname); + + if (!proc_info->name && symbol_from_elf) + proc_info->name = symbol_from_elf; +} + +/** + * @brief Checks if symbol starts with '_Z' prefix + * + * @param symbol string to compare + */ +static int is_symbol_demanglable(const char *symbol) +{ + return symbol != 0 && (strlen(symbol) >= 2) && + symbol[0] == '_' && symbol[1] == 'Z'; +} + +/** + * @brief Replaces symbols with demangled + * + * @param proc_info gathered call stack element + */ +static void __demangle_symbols(ProcInfo *proc_info) +{ + int status = -1; + char *dem_buffer = NULL; + char *demangled_symbol = __cxa_demangle(proc_info->name, dem_buffer, NULL, &status); + if (status == 0) { + free(proc_info->name); + proc_info->name = demangled_symbol; + } +} + +/** + * @brief Resolves procedure and module name + * + * @param proc_info gathered call stack element * @param dwfl dwfl handler * @param core ELF handler for the core dump file, NULL if live process analyzed - * @param pid PID of the live process, 0 if core dump file analyzed * @param notes notes handler, NULL if live process analyzed */ -static void __print_callstack(Callstack *callstack, Dwfl *dwfl, Elf *core, pid_t pid, - Elf_Data *notes) +static void __resolve_symbols(ProcInfo *proc_info, Dwfl *dwfl, Elf *core, Elf_Data *notes) +{ + if (!proc_info->module_name || !proc_info->name) + __resolve_symbols_from_dwfl(proc_info, dwfl); + + if (!proc_info->module_name || !proc_info->name) + __resolve_symbols_from_elf(proc_info, core, notes); + + if (is_symbol_demanglable(proc_info->name)) + __demangle_symbols(proc_info); +} + +/** + * @brief Prints call stack to the global outputfile. + * + * @param callstack gathered call stack database + * @param pid PID of the live process, 0 if core dump file analyzed + */ +static void __print_callstack(Callstack *callstack, pid_t pid) { fprintf(outputfile, "\nCallstack Information"); if (pid > 1) fprintf(outputfile, " (PID:%d)", pid); fprintf(outputfile, "\n"); fprintf(outputfile, "Call Stack Count: %d\n", (int)callstack->elems); - char *dem_buffer = NULL; size_t it; for (it = 0; it != callstack->elems; ++it) { - if (sizeof(callstack->tab[0]) > 4) - fprintf(outputfile, "0x%016llx: ", (long long)callstack->tab[it]); + if (sizeof(callstack->proc[0].addr) > 4) + fprintf(outputfile, "0x%016llx: ", (long long)callstack->proc[it].addr); else - fprintf(outputfile, "0x%08x: ", (int32_t)callstack->tab[it]); - const char *symbol = callstack->proc_name[it]; + fprintf(outputfile, "0x%08x: ", (int32_t)callstack->proc[it].addr); - Dwfl_Module *module = dwfl_addrmodule(dwfl, callstack->tab[it]); - if (module) { - char *demangled_symbol = 0; - 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 = dwfl_module_addrname(module, callstack->tab[it]); - if (symbol == NULL) - symbol = symbol_from_elf = __try_symbol_from_elfs(core, notes, callstack->tab[it], &fname); - if (symbol != 0 && symbol[0] == '_' && symbol[1] == 'Z') { - int status = -1; - - demangled_symbol = __cxa_demangle(symbol, dem_buffer, NULL, &status); - if (status == 0) - symbol = demangled_symbol; - } - if (symbol != 0) - fprintf(outputfile, "%s()", symbol); - else - fprintf(outputfile, ""); + const char *symbol = callstack->proc[it].name; + if (symbol != 0) + fprintf(outputfile, "%s()", symbol); + else + fprintf(outputfile, ""); - if (demangled_symbol != 0) - free(demangled_symbol); + const char *module_name = callstack->proc[it].module_name; + if (module_name != 0) + fprintf(outputfile, " from %s", module_name); - if (symbol_from_elf != 0) - free(symbol_from_elf); + fprintf(outputfile, "\n"); + } +} - fprintf(outputfile, " from %s\n", fname != NULL ? fname : module_name); - } else if (symbol) { - fprintf(outputfile, "%s()", symbol); - } else { - fprintf(outputfile, "unknown function\n"); - } +void callstack_constructor(Callstack *callstack) +{ + size_t it; + callstack->elems = 0; + for (it = 0; it < (int)sizeof(callstack->proc)/sizeof(callstack->proc[0]); ++it) { + callstack->proc[it].name = 0; + callstack->proc[it].module_name = 0; + } +} + +void callstack_destructor(Callstack *callstack) +{ + size_t it; + for (it = 0; it < callstack->elems; ++it) { + free(callstack->proc[it].name); + free(callstack->proc[it].module_name); } fprintf(outputfile, "End of Call Stack\n"); } @@ -761,7 +846,7 @@ static void __crash_stack_print_threads(FILE* outputfile, pid_t pid, pid_t tid) */ int main(int argc, char **argv) { - int c, i; + int c; pid_t pid = 0; pid_t tid = 0; @@ -847,10 +932,12 @@ int main(int argc, char **argv) /* Unwind call stack */ Callstack callstack; - callstack.elems = 0; - memset(callstack.proc_name, 0, sizeof(callstack.proc_name)); + callstack_constructor(&callstack); _create_crash_stack(dwfl, core, pid, &mappings, &callstack); + size_t it; + for (it = 0; it != callstack.elems; ++it) + __resolve_symbols(&callstack.proc[it], dwfl, core, notes); /* Print registers */ _crash_stack_print_regs(outputfile); @@ -859,13 +946,10 @@ int main(int argc, char **argv) __crash_stack_print_threads(outputfile, pid, tid); /* Print the results */ - __print_callstack(&callstack, dwfl, core, pid, notes); - - for (i = 0; i < callstack.elems; ++i) - if (callstack.proc_name[i]) - free(callstack.proc_name[i]); + __print_callstack(&callstack, pid); /* Clean up */ + callstack_destructor(&callstack); dwfl_report_end(dwfl, NULL, NULL); dwfl_end(dwfl); if (NULL != core) elf_end(core); diff --git a/src/crash-stack/crash-stack.h b/src/crash-stack/crash-stack.h index 714cc18..142e0ac 100644 --- a/src/crash-stack/crash-stack.h +++ b/src/crash-stack/crash-stack.h @@ -27,14 +27,22 @@ #include #include -#define MAX_CALLSTACK_LEN 1000 +/** + * @brief callstack.procedure info + */ +struct ProcInfo { + uintptr_t addr; ///< procedure address + char *name; ///< procedure name + char *module_name; ///< module name +}; +typedef struct ProcInfo ProcInfo; +#define MAX_CALLSTACK_LEN 1000 /** * @brief call stack database */ struct Callstack { - uintptr_t tab[MAX_CALLSTACK_LEN]; ///< storage for elements - char *proc_name[MAX_CALLSTACK_LEN]; ///< procedure name related to tab element with the same index + ProcInfo proc[MAX_CALLSTACK_LEN]; ///< storage for elements size_t elems; ///< number of elements in the database }; typedef struct Callstack Callstack; -- 2.7.4 From 753d359c44f4f61aa894fdc3a842c750a09f08bd Mon Sep 17 00:00:00 2001 From: Rafal Pietruch Date: Wed, 14 Dec 2016 13:11:12 +0100 Subject: [PATCH 09/16] crash-stack: reformat callstack output Change-Id: Ica727d63de389d8a4a2f1ff7cfced2a463630282 --- src/crash-stack/crash-stack-libunw.c | 1 + src/crash-stack/crash-stack.c | 49 ++++++++++++++++++++++-------------- src/crash-stack/crash-stack.h | 1 + 3 files changed, 32 insertions(+), 19 deletions(-) diff --git a/src/crash-stack/crash-stack-libunw.c b/src/crash-stack/crash-stack-libunw.c index ba0b245..23e3df3 100644 --- a/src/crash-stack/crash-stack-libunw.c +++ b/src/crash-stack/crash-stack-libunw.c @@ -64,6 +64,7 @@ void _create_crash_stack(Dwfl *dwfl, Elf *core, pid_t pid, Mappings *mappings, C unw_get_proc_name(&cursor, proc_name, sizeof(proc_name), &off); if (strlen(proc_name) > 0) callstack->proc[callstack->elems].name = strdup(proc_name); + callstack->proc[callstack->elems].offset = off; ++callstack->elems; if (unw_step(&cursor) <= 0) diff --git a/src/crash-stack/crash-stack.c b/src/crash-stack/crash-stack.c index e1cabf9..07cdb46 100644 --- a/src/crash-stack/crash-stack.c +++ b/src/crash-stack/crash-stack.c @@ -732,6 +732,29 @@ static void __resolve_symbols(ProcInfo *proc_info, Dwfl *dwfl, Elf *core, Elf_Da } /** + * @brief Prints call stack element to the global outputfile. + * + * @param proc_info gathered call stack element + */ +static void __print_proc_info(ProcInfo *proc_info) +{ + if (proc_info->name) { + fprintf(outputfile, "%s ", proc_info->name); + if (proc_info->offset >= 0) + fprintf(outputfile, "+ 0x%x ", proc_info->offset); + } + if (sizeof(proc_info->addr) > 4) + fprintf(outputfile, "(0x%016llx)", (long long)proc_info->addr); + else + fprintf(outputfile, "(0x%08x)", (int32_t)proc_info->addr); + + if (proc_info->module_name != 0) + fprintf(outputfile, " [%s]", proc_info->module_name); + + fprintf(outputfile, "\n"); +} + +/** * @brief Prints call stack to the global outputfile. * * @param callstack gathered call stack database @@ -740,29 +763,16 @@ static void __resolve_symbols(ProcInfo *proc_info, Dwfl *dwfl, Elf *core, Elf_Da static void __print_callstack(Callstack *callstack, pid_t pid) { fprintf(outputfile, "\nCallstack Information"); - if (pid > 1) fprintf(outputfile, " (PID:%d)", pid); - fprintf(outputfile, "\n"); - fprintf(outputfile, "Call Stack Count: %d\n", (int)callstack->elems); + if (pid > 1) + fprintf(outputfile, " (PID:%d)", pid); + fprintf(outputfile, "\nCall Stack Count: %zu\n", callstack->elems); size_t it; for (it = 0; it != callstack->elems; ++it) { - if (sizeof(callstack->proc[0].addr) > 4) - fprintf(outputfile, "0x%016llx: ", (long long)callstack->proc[it].addr); - else - fprintf(outputfile, "0x%08x: ", (int32_t)callstack->proc[it].addr); - - const char *symbol = callstack->proc[it].name; - if (symbol != 0) - fprintf(outputfile, "%s()", symbol); - else - fprintf(outputfile, ""); - - const char *module_name = callstack->proc[it].module_name; - if (module_name != 0) - fprintf(outputfile, " from %s", module_name); - - fprintf(outputfile, "\n"); + fprintf(outputfile, "%2zu: ", it); + __print_proc_info(&callstack->proc[it]); } + fprintf(outputfile, "End of Call Stack\n"); } void callstack_constructor(Callstack *callstack) @@ -770,6 +780,7 @@ void callstack_constructor(Callstack *callstack) size_t it; callstack->elems = 0; for (it = 0; it < (int)sizeof(callstack->proc)/sizeof(callstack->proc[0]); ++it) { + callstack->proc[it].offset = -1; callstack->proc[it].name = 0; callstack->proc[it].module_name = 0; } diff --git a/src/crash-stack/crash-stack.h b/src/crash-stack/crash-stack.h index 142e0ac..385a31d 100644 --- a/src/crash-stack/crash-stack.h +++ b/src/crash-stack/crash-stack.h @@ -32,6 +32,7 @@ */ struct ProcInfo { uintptr_t addr; ///< procedure address + int offset; ///< procedure offset char *name; ///< procedure name char *module_name; ///< module name }; -- 2.7.4 From 1c23e085a8377ee92f2200af9b98a0841edf3e87 Mon Sep 17 00:00:00 2001 From: Adrian Szyndela Date: Wed, 14 Dec 2016 08:16:22 +0100 Subject: [PATCH 10/16] crash-stack: put more effort into getting names It seems libdwfl-0.153 sometimes can't get symbol names automatically. This commit adds fallback procedure, that takes module name and mapping provided by libdwfl, and - using libelf - looks for the symbol name, instead of relying only on libdwfl. Change-Id: I7e65f810b46dc43bea217b715852a5ae5c3d70c9 --- src/crash-stack/crash-stack.c | 197 ++++++++++++++++++++---------------------- 1 file changed, 93 insertions(+), 104 deletions(-) diff --git a/src/crash-stack/crash-stack.c b/src/crash-stack/crash-stack.c index 07cdb46..d839a4f 100644 --- a/src/crash-stack/crash-stack.c +++ b/src/crash-stack/crash-stack.c @@ -209,102 +209,58 @@ static void __get_mapping_item(Elf *elf, size_t addr_size, const void *item, __get_value(elf, item + 2 * addr_size, addr_size*8, offset_in_pages); } -/** - * @brief Tries to get symbol name from ELF files - * - * @remarks This function is used in case that symbol name is not available by libelf, - * e.g. when old libelf version does not take into account some modules. - * - * @param core ELF handler for the core dump file - * @param notes notes descriptor from core file - * @param address address to get symbol name for - * @param[out] module_name name of the module of the found symbol. Not touched when - * symbol is not found - * @return name of the symbol or NULL if not found - */ -static char *__try_symbol_from_elfs(Elf *core, Elf_Data *notes, uintptr_t address, - const char **module_name) +void __find_symbol_in_elf(ProcInfo *proc_info, Dwarf_Addr mapping_start) { - GElf_Nhdr nhdr; - char *symbol = NULL; - size_t pos = 0; - size_t new_pos = 0; - size_t name_pos; - size_t desc_pos; - - while ((new_pos = gelf_getnote(notes, pos, &nhdr, &name_pos, &desc_pos)) > 0) { - if (nhdr.n_type == NT_FILE) { - uint64_t values_cnt = 0, page_size = 0; - const char *values; - const char *filenames; - size_t addr_size = 0; + Elf *elf; + int fd; + const char *elf_name = proc_info->module_name; + Dwarf_Addr address = proc_info->addr; - __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 = 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); - - if (mapping_start <= address && address < mapping_end) { - Elf *elf; - int fd; - fd = open(filenames, O_RDONLY); - if (-1 == fd) - return NULL; + fd = open(elf_name, O_RDONLY); + if (-1 == fd) + return; - elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); + elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); - if (NULL == elf) { - close(fd); - return NULL; - } + if (NULL == elf) { + close(fd); + return; + } - Elf_Scn *scn = NULL; - *module_name = filenames; - - while ((scn = elf_nextscn(elf, scn)) != NULL) { - GElf_Shdr shdr_mem; - GElf_Shdr *shdr = gelf_getshdr(scn, &shdr_mem); - if (shdr != NULL && (shdr->sh_type == SHT_SYMTAB || shdr->sh_type == SHT_DYNSYM)) { - Elf_Data *sdata = elf_getdata(scn, NULL); - unsigned int nsyms = sdata->d_size / (gelf_getclass(elf) == ELFCLASS32 ? - sizeof(Elf32_Sym) : - sizeof(Elf64_Sym)); - unsigned int cnt; - uintptr_t address_offset = address; - if (shdr->sh_type == SHT_DYNSYM) - address_offset -= mapping_start; - for (cnt = 0; cnt < nsyms; ++cnt) { - GElf_Sym sym_mem; - Elf32_Word xndx; - GElf_Sym *sym = gelf_getsymshndx(sdata, NULL, cnt, &sym_mem, &xndx); - if (sym != NULL && sym->st_shndx != SHN_UNDEF) { - if (sym->st_value <= address_offset && address_offset < sym->st_value + sym->st_size) { - symbol = strdup(elf_strptr(elf, shdr->sh_link, sym->st_name)); - break; - } - } - } - } + Elf_Scn *scn = NULL; + int found = 0; + + while ((scn = elf_nextscn(elf, scn)) != NULL && !found) { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr(scn, &shdr_mem); + if (shdr != NULL && (shdr->sh_type == SHT_SYMTAB || shdr->sh_type == SHT_DYNSYM)) { + Elf_Data *sdata = elf_getdata(scn, NULL); + unsigned int nsyms = sdata->d_size / (gelf_getclass(elf) == ELFCLASS32 ? + sizeof(Elf32_Sym) : + sizeof(Elf64_Sym)); + unsigned int cnt; + uintptr_t address_offset = address; + if (shdr->sh_type == SHT_DYNSYM) + address_offset -= mapping_start; + for (cnt = 0; cnt < nsyms; ++cnt) { + GElf_Sym sym_mem; + Elf32_Word xndx; + GElf_Sym *sym = gelf_getsymshndx(sdata, NULL, cnt, &sym_mem, &xndx); + if (sym != NULL && sym->st_shndx != SHN_UNDEF) { + if (sym->st_value <= address_offset && address_offset < sym->st_value + sym->st_size) { + free(proc_info->name); + proc_info->name = strdup(elf_strptr(elf, shdr->sh_link, sym->st_name)); + proc_info->offset = address_offset - sym->st_value; + found = 1; + break; } - - elf_end(elf); - close(fd); - return symbol; } - - filenames += strlen(filenames)+1; } } - pos = new_pos; } - return NULL; + elf_end(elf); + close(fd); } /** @@ -323,7 +279,6 @@ static Dwfl *__open_dwfl_with_pid(pid_t pid) return NULL; } - ptrace(PTRACE_INTERRUPT, pid, 0, 0); stopped_pid = waitpid(pid, &status, 0); @@ -648,20 +603,23 @@ static void __resolve_symbols_from_dwfl(ProcInfo *proc_info, Dwfl *dwfl) Dwfl_Module *module = dwfl_addrmodule(dwfl, address); if (module) { - const char *module_name = proc_info->module_name; - if (!module_name) { - const char *fname = 0; - const char *module_name = dwfl_module_info(module, NULL, NULL, NULL, NULL, NULL, &fname, NULL); + Dwarf_Addr mapping_start = 0; + const char *fname = 0; + const char *module_name = dwfl_module_info(module, NULL, &mapping_start, NULL, NULL, NULL, &fname, NULL); + if (!proc_info->module_name) { if (fname) proc_info->module_name = strdup(fname); else if (module_name) proc_info->module_name = strdup(module_name); } - const char *symbol = proc_info->name; - if (!symbol) { - symbol = dwfl_module_addrname(module, proc_info->addr); - if (symbol) - proc_info->name = strdup(symbol); + + const char *symbol = dwfl_module_addrname(module, address); + if (symbol) { + free(proc_info->name); + proc_info->name = strdup(symbol); + } + else if (proc_info->module_name != NULL) { + __find_symbol_in_elf(proc_info, mapping_start); } } } @@ -669,19 +627,51 @@ static void __resolve_symbols_from_dwfl(ProcInfo *proc_info, Dwfl *dwfl) /** * @brief Resolves procedure and module names using elfutils * + * @remarks This function is used in case that symbol name is not available by libelf, + * e.g. when old libelf version does not take into account some modules. + * * @param proc_info gathered call stack element * @param core ELF handler for the core dump file, NULL if live process analyzed * @param notes notes handler, NULL if live process analyzed */ static void __resolve_symbols_from_elf(ProcInfo *proc_info, Elf *core, Elf_Data *notes) { - const char *fname = 0; - char *symbol_from_elf = __try_symbol_from_elfs(core, notes, proc_info->addr, &fname); - if (!proc_info->module_name && fname) - proc_info->module_name = strdup(fname); + GElf_Nhdr nhdr; + size_t pos = 0; + size_t new_pos = 0; + size_t name_pos; + size_t desc_pos; + + while ((new_pos = gelf_getnote(notes, pos, &nhdr, &name_pos, &desc_pos)) > 0) { + if (nhdr.n_type == NT_FILE) { + uint64_t values_cnt = 0, page_size = 0; + const char *values; + const char *filenames; + 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 = 0, mapping_end = 0, offset_in_pages = 0; + const char *item = values + 3 * addr_size * ii; - if (!proc_info->name && symbol_from_elf) - proc_info->name = symbol_from_elf; + __get_mapping_item(core, addr_size, item, &mapping_start, &mapping_end, + &offset_in_pages); + + if (mapping_start <= proc_info->addr && proc_info->addr < mapping_end) { + free(proc_info->module_name); + proc_info->module_name = strdup(filenames); + __find_symbol_in_elf(proc_info, mapping_start); + return; + } + + filenames += strlen(filenames)+1; + } + } + pos = new_pos; + } } /** @@ -721,10 +711,9 @@ static void __demangle_symbols(ProcInfo *proc_info) */ static void __resolve_symbols(ProcInfo *proc_info, Dwfl *dwfl, Elf *core, Elf_Data *notes) { - if (!proc_info->module_name || !proc_info->name) - __resolve_symbols_from_dwfl(proc_info, dwfl); + __resolve_symbols_from_dwfl(proc_info, dwfl); - if (!proc_info->module_name || !proc_info->name) + if (core != NULL && (!proc_info->module_name || !proc_info->name)) __resolve_symbols_from_elf(proc_info, core, notes); if (is_symbol_demanglable(proc_info->name)) -- 2.7.4 From 78b75f2ef9fece4a3cc2bf8251c7a9ed20c61de5 Mon Sep 17 00:00:00 2001 From: Adrian Szyndela Date: Wed, 14 Dec 2016 14:52:37 +0100 Subject: [PATCH 11/16] crash-stack: support for resolving stack from threads Change-Id: Ic80b6b83acb80b3c332b6b6674fbf662b1003586 --- src/crash-stack/crash-stack.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/crash-stack/crash-stack.c b/src/crash-stack/crash-stack.c index d839a4f..a377306 100644 --- a/src/crash-stack/crash-stack.c +++ b/src/crash-stack/crash-stack.c @@ -269,17 +269,24 @@ void __find_symbol_in_elf(ProcInfo *proc_info, Dwarf_Addr mapping_start) * @param pid pid of the process to attach to * @return Dwfl handle */ -static Dwfl *__open_dwfl_with_pid(pid_t pid) +static Dwfl *__open_dwfl_with_pid(pid_t pid, pid_t tid) { int status; pid_t stopped_pid; - if (ptrace(PTRACE_SEIZE, pid, NULL, PTRACE_O_TRACEEXIT) != 0) { - fprintf(errfile, "PTRACE_SEIZE failed on PID %d: %m\n", pid); + if (ptrace(PTRACE_SEIZE, tid, NULL, PTRACE_O_TRACEEXIT) != 0) { + fprintf(errfile, "PTRACE_SEIZE failed on TID %d: %m\n", tid); return NULL; } + if (pid != tid) + if (ptrace(PTRACE_SEIZE, pid, NULL, PTRACE_O_TRACEEXIT) != 0) { + fprintf(errfile, "PTRACE_SEIZE failed on PID %d: %m\n", pid); + return NULL; + } + ptrace(PTRACE_INTERRUPT, pid, 0, 0); + ptrace(PTRACE_INTERRUPT, tid, 0, 0); stopped_pid = waitpid(pid, &status, 0); if (stopped_pid == -1 || stopped_pid != pid || !WIFSTOPPED(status)) { @@ -874,6 +881,8 @@ int main(int argc, char **argv) if (NULL == errfile) errfile = stderr; if (NULL == outputfile) outputfile = stdout; + if (tid == 0) tid = pid; + core_file_name = argv[optind]; argc -= optind; @@ -885,11 +894,11 @@ int main(int argc, char **argv) Dwfl *dwfl = NULL; if (pid > 1) - dwfl = __open_dwfl_with_pid(pid); + dwfl = __open_dwfl_with_pid(pid, tid); else { if (argc != 1) { fprintf(errfile, - "Usage: %s [--output file] [--erroutput file] [--pid | ]\n", + "Usage: %s [--output file] [--erroutput file] [--pid [--tid ] | ]\n", argv[0]); return 1; } @@ -934,7 +943,7 @@ int main(int argc, char **argv) Callstack callstack; callstack_constructor(&callstack); - _create_crash_stack(dwfl, core, pid, &mappings, &callstack); + _create_crash_stack(dwfl, core, tid, &mappings, &callstack); size_t it; for (it = 0; it != callstack.elems; ++it) __resolve_symbols(&callstack.proc[it], dwfl, core, notes); @@ -946,7 +955,7 @@ int main(int argc, char **argv) __crash_stack_print_threads(outputfile, pid, tid); /* Print the results */ - __print_callstack(&callstack, pid); + __print_callstack(&callstack, tid); /* Clean up */ callstack_destructor(&callstack); -- 2.7.4 From 34e2c15681edf0ebb9d81dba8a51a2922e21a38e Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C5=81ukasz=20Stelmach?= Date: Wed, 14 Dec 2016 16:26:54 +0100 Subject: [PATCH 12/16] crash-stack: print executable file path Change-Id: Ib5946bcfb5bbad8af7b7bbfc7c8568a3cb3ab207 --- src/crash-stack/crash-stack.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/crash-stack/crash-stack.c b/src/crash-stack/crash-stack.c index a377306..2507055 100644 --- a/src/crash-stack/crash-stack.c +++ b/src/crash-stack/crash-stack.c @@ -793,9 +793,24 @@ void callstack_destructor(Callstack *callstack) } /** + * @brief Print full path of executable file + */ +static void __crash_stack_print_exe(FILE* outputfile, pid_t pid) +{ + char file_path[PATH_MAX]; + char link_path[PATH_MAX]; + + snprintf(link_path, PATH_MAX, "/proc/%d/exe", pid); + if (readlink(link_path, file_path, PATH_MAX) == -1) { + return; + } + fprintf(outputfile, "Executable File Path: %s\n", file_path); +} + +/** * @brief Print thread information * - * @param outputfile File handle for printing report. + * @param outputfile File handle for printing report * @param pid PID of the inspected process * @param tid TID of the inspected thread */ @@ -927,6 +942,9 @@ int main(int argc, char **argv) dwfl_getmodules(dwfl, __module_callback, &mappings, 0); Elf_Data *notes = 0; + /* Executable File Path */ + __crash_stack_print_exe(outputfile, pid); + /* Now, get registers */ if (pid > 1) { if (-1 == __get_signal_ptrace(pid)) -- 2.7.4 From 443f2c042b036fed60b4c09eb13f8b50dea7ed68 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C5=81ukasz=20Stelmach?= Date: Wed, 14 Dec 2016 15:06:43 +0100 Subject: [PATCH 13/16] crash-stack: print maps information Print information about mapped memory regions. Add stub for printing system and process VM information. Change-Id: I47b2c5f837620f9d22b3270a75d8f5e663d44c78 --- src/crash-stack/crash-stack.c | 229 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 211 insertions(+), 18 deletions(-) diff --git a/src/crash-stack/crash-stack.c b/src/crash-stack/crash-stack.c index 2507055..bd5731f 100644 --- a/src/crash-stack/crash-stack.c +++ b/src/crash-stack/crash-stack.c @@ -16,6 +16,8 @@ * Authors: Adrian Szyndela * Łukasz Stelmach */ +#define _GNU_SOURCE 1 + /** * @file crash-stack.c * @brief This file contains Main module of call stack unwinding program @@ -24,9 +26,27 @@ * of a crashed program. Crash-stack must be called with proper arguments: * either core dump file name or PID of a crashed program. */ -#include -#include +#include "crash-stack.h" +#include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include #include /* * In case the program is compiled with core dumps, the license may switch to GPL2. @@ -34,22 +54,13 @@ #ifdef WITH_CORE_DUMP #include #endif -#include -#include -#include -#include -#include -#include -#include "crash-stack.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include + +#define BUF_SIZE (BUFSIZ) +#define HEXA 16 +#define PERM_LEN 5 +#define ADDR_LEN 16 +#define STR_ANONY "[anony]" +#define STR_ANONY_LEN 8 static siginfo_t __siginfo; static FILE *outputfile = NULL; ///< global output stream @@ -76,6 +87,22 @@ const struct option opts[] = { { 0, 0, 0, 0 } }; +/** + * @brief container for information from /proc/PID/maps + */ +struct addr_node { + uintptr_t startaddr; + uintptr_t endaddr; + char perm[PERM_LEN]; + char *fpath; + struct addr_node *next; +}; + +/* helper functions for reading /proc/PID/maps */ +static struct addr_node *get_addr_list_from_maps(int fd); +static void free_all_nodes(struct addr_node *start); +static char *fgets_fd(char *str, int len, int fd); + /* * __cxa_demangle() is taken from libstdc++, however there is no header that we * can take a declaration from. Importing through 'extern' allows using it. @@ -855,6 +882,166 @@ static void __crash_stack_print_threads(FILE* outputfile, pid_t pid, pid_t tid) } /** + * @brief Print information about mapped memory regions + * + * @param outputfile File handle for printing report. + * @param pid PID of the inspected process + */ +static void __crash_stack_print_maps(FILE* outputfile, pid_t pid) +{ + char file_path[PATH_MAX]; + struct addr_node *head = NULL; + struct addr_node *t_node; + int fd; + + snprintf(file_path, PATH_MAX, "/proc/%d/maps", pid); + + if ((fd = open(file_path, O_RDONLY)) < 0) { + fprintf(errfile, "[crash-stack] cannot open %s\n", file_path); + } else { + /* parsing the maps to get code segment address*/ + head = get_addr_list_from_maps(fd); + close(fd); + } + if (head == NULL) { + return; + } + + t_node = head; + fprintf(outputfile, "\nMaps Information\n"); + while (t_node) { + if (!strncmp(STR_ANONY, t_node->fpath, STR_ANONY_LEN)) { + t_node = t_node->next; + } else { + printf( "%16lx %16lx %s %s\n", + (unsigned long)t_node->startaddr, + (unsigned long)t_node->endaddr, + t_node->perm, t_node->fpath); + t_node = t_node->next; + } + } + fprintf(outputfile, "End of Maps Information\n"); + free_all_nodes(head); +} + +static struct addr_node *get_addr_list_from_maps(int fd) +{ + int fpath_len, result; + uintptr_t saddr; + uintptr_t eaddr; + char perm[PERM_LEN]; + char path[PATH_MAX]; + char addr[ADDR_LEN * 2 + 2]; + char linebuf[BUF_SIZE]; + struct addr_node *head = NULL; + struct addr_node *tail = NULL; + struct addr_node *t_node = NULL; + + /* parsing the maps to get executable code address */ + while (fgets_fd(linebuf, BUF_SIZE, fd) != NULL) { + memset(path, 0, PATH_MAX); + result = sscanf(linebuf, "%s %s %*s %*s %*s %s ", addr, perm, path); + if (result < 0) + continue; + perm[PERM_LEN - 1] = 0; + /* rwxp */ + if ((perm[2] == 'x' && path[0] == '/') || + (perm[1] == 'w' && path[0] != '/')) + { + char* addr2 = strchr(addr, '-'); + *(addr2++) = '\0'; + /* add addr node to list */ + saddr = strtoul(addr, NULL, HEXA); + /* ffff0000-ffff1000 */ + eaddr = strtoul(addr2, NULL, HEXA); + /* make node and attach to the list */ + t_node = (struct addr_node *)mmap(0, sizeof(struct addr_node), + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (t_node == NULL) { + fprintf(stderr, "error : mmap\n"); + return NULL; + } + memcpy(t_node->perm, perm, PERM_LEN); + t_node->startaddr = saddr; + t_node->endaddr = eaddr; + t_node->fpath = NULL; + fpath_len = strlen(path); + if (fpath_len > 0) { + t_node->fpath = (char *)mmap(0, fpath_len + 1, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + memset(t_node->fpath, 0, fpath_len + 1); + memcpy(t_node->fpath, path, fpath_len); + } else { + t_node->fpath = (char *)mmap(0, STR_ANONY_LEN, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + memset(t_node->fpath, 0, STR_ANONY_LEN); + memcpy(t_node->fpath, STR_ANONY, STR_ANONY_LEN); + } + t_node->next = NULL; + if (head == NULL) { + head = t_node; + tail = t_node; + } else { + tail->next = t_node; + tail = t_node; + } + } + } + return head; +} + +static void free_all_nodes(struct addr_node *start) +{ + struct addr_node *t_node, *n_node; + int fpath_len; + + if (start == NULL) + return; + t_node = start; + n_node = t_node->next; + while (t_node) { + if (t_node->fpath != NULL) { + fpath_len = strlen(t_node->fpath); + munmap(t_node->fpath, fpath_len + 1); + } + munmap(t_node, sizeof(struct addr_node)); + if (n_node == NULL) + break; + t_node = n_node; + n_node = n_node->next; + } +} + +static char *fgets_fd(char *str, int len, int fd) +{ + char ch; + register char *cs; + int num = 0; + + cs = str; + while (--len > 0 && (num = read(fd, &ch, 1) > 0)) { + if ((*cs++ = ch) == '\n') + break; + } + *cs = '\0'; + return (num == 0 && cs == str) ? NULL : str; +} + +/** + * @brief Print process and system memory information + * + * @param outputfile File handle for printing report. + * @param pid PID of the inspected process + */ +static void __crash_stack_print_meminfo(FILE* outputfile, pid_t pid) +{ + fprintf(outputfile, "\nMemory Information\n"); +} + +/** * @brief Main function. * * Main module accepts two forms of launching: @@ -969,9 +1156,15 @@ int main(int argc, char **argv) /* Print registers */ _crash_stack_print_regs(outputfile); + /* Memory information */ + __crash_stack_print_meminfo(outputfile, pid); + /* Threads */ __crash_stack_print_threads(outputfile, pid, tid); + /* Maps Information */ + __crash_stack_print_maps(outputfile, pid); + /* Print the results */ __print_callstack(&callstack, tid); -- 2.7.4 From 65113e02bd5de3e83ffafcb37e74e5a47b0e5353 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C5=81ukasz=20Stelmach?= Date: Wed, 14 Dec 2016 17:28:10 +0100 Subject: [PATCH 14/16] crash-stack: change error reporting file handle Change-Id: I734b431f56f9e32c440839e1bd4e5b90112773ec --- src/crash-stack/crash-stack.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/crash-stack/crash-stack.c b/src/crash-stack/crash-stack.c index bd5731f..9da6d93 100644 --- a/src/crash-stack/crash-stack.c +++ b/src/crash-stack/crash-stack.c @@ -161,7 +161,7 @@ static void __get_value(Elf *core, const void *from, size_t size, void *to) case 32: type = ELF_T_WORD; break; case 64: type = ELF_T_XWORD; break; default: - fprintf(stderr, "__get_value for strange size: %llu\n", (unsigned long long)size); + fprintf(errfile, "__get_value for strange size: %llu\n", (unsigned long long)size); break; } Elf_Data out = { @@ -866,7 +866,7 @@ static void __crash_stack_print_threads(FILE* outputfile, pid_t pid, pid_t tid) /* print thread */ dir = opendir(task_path); if (!dir) { - fprintf(stderr, "[crash-stack] cannot open %s\n", task_path); + fprintf(errfile, "[crash-stack] cannot open %s\n", task_path); } else { while (readdir_r(dir, &entry, &dentry) == 0 && dentry) { if (strcmp(dentry->d_name, ".") == 0 || @@ -959,7 +959,7 @@ static struct addr_node *get_addr_list_from_maps(int fd) PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (t_node == NULL) { - fprintf(stderr, "error : mmap\n"); + fprintf(errfile, "error : mmap\n"); return NULL; } memcpy(t_node->perm, perm, PERM_LEN); -- 2.7.4 From 1b0c3b283ae9a30a8c323596296a17e0bbb61224 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C5=81ukasz=20Stelmach?= Date: Wed, 14 Dec 2016 17:30:54 +0100 Subject: [PATCH 15/16] crash-stack: print memory information Print information from /proc/meminfo and /proc/PID/status Change-Id: I6c66e9ee6c8eca20a8925e9ecc23e09c0dabcb25 --- src/crash-stack/crash-stack.c | 75 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/src/crash-stack/crash-stack.c b/src/crash-stack/crash-stack.c index 9da6d93..fbf39c0 100644 --- a/src/crash-stack/crash-stack.c +++ b/src/crash-stack/crash-stack.c @@ -1038,7 +1038,80 @@ static char *fgets_fd(char *str, int len, int fd) */ static void __crash_stack_print_meminfo(FILE* outputfile, pid_t pid) { - fprintf(outputfile, "\nMemory Information\n"); + char infoname[BUF_SIZE]; + char memsize[BUF_SIZE]; + char linebuf[BUF_SIZE]; + char file_path[PATH_MAX]; + int fd; + + printf("\nMemory information\n"); + + if ((fd = open("/proc/meminfo", O_RDONLY)) < 0) { + fprintf(errfile, "[crash-stack] cannot open /proc/meminfo\n"); + } else { + while (fgets_fd(linebuf, BUF_SIZE, fd) != NULL) { + sscanf(linebuf, "%s %s %*s", infoname, memsize); + if (strcmp("MemTotal:", infoname) == 0) { + printf("%s %8s KB\n", infoname, memsize); + } else if (strcmp("MemFree:", infoname) == 0) { + printf("%s %8s KB\n", infoname, memsize); + } else if (strcmp("Buffers:", infoname) == 0) { + printf("%s %8s KB\n", infoname, memsize); + } else if (strcmp("Cached:", infoname) == 0) { + printf("%s %8s KB\n", infoname, memsize); + break; + } + } + close(fd); + } + + snprintf(file_path, PATH_MAX, "/proc/%d/status", pid); + if ((fd = open(file_path, O_RDONLY)) < 0) { + fprintf(errfile, "[crash-stack] cannot open %s\n", file_path); + } else { + while (fgets_fd(linebuf, BUF_SIZE, fd) != NULL) { + sscanf(linebuf, "%s %s %*s", infoname, memsize); + if (strcmp("VmPeak:", infoname) == 0) { + printf("%s %8s KB\n", infoname, + memsize); + } else if (strcmp("VmSize:", infoname) == 0) { + printf("%s %8s KB\n", infoname, + memsize); + } else if (strcmp("VmLck:", infoname) == 0) { + printf("%s %8s KB\n", infoname, + memsize); + } else if (strcmp("VmPin:", infoname) == 0) { + printf("%s %8s KB\n", infoname, + memsize); + } else if (strcmp("VmHWM:", infoname) == 0) { + printf("%s %8s KB\n", + infoname, memsize); + } else if (strcmp("VmRSS:", infoname) == 0) { + printf("%s %8s KB\n", + infoname, memsize); + } else if (strcmp("VmData:", infoname) == 0) { + printf("%s %8s KB\n", + infoname, memsize); + } else if (strcmp("VmStk:", infoname) == 0) { + printf("%s %8s KB\n", + infoname, memsize); + } else if (strcmp("VmExe:", infoname) == 0) { + printf("%s %8s KB\n", + infoname, memsize); + } else if (strcmp("VmLib:", infoname) == 0) { + printf("%s %8s KB\n", + infoname, memsize); + } else if (strcmp("VmPTE:", infoname) == 0) { + printf("%s %8s KB\n", + infoname, memsize); + } else if (strcmp("VmSwap:", infoname) == 0) { + printf("%s %8s KB\n", + infoname, memsize); + break; + } + } + close(fd); + } } /** -- 2.7.4 From 3727dd3d16dfaf79f6feda44af681f9fc14e18b7 Mon Sep 17 00:00:00 2001 From: Karol Lewandowski Date: Wed, 14 Dec 2016 17:53:05 +0100 Subject: [PATCH 16/16] crash-stack: Drop duplicate call stack footer Change-Id: I938f2ead95d312450edb853740cce47becf796fc --- src/crash-stack/crash-stack.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/crash-stack/crash-stack.c b/src/crash-stack/crash-stack.c index fbf39c0..ef1814c 100644 --- a/src/crash-stack/crash-stack.c +++ b/src/crash-stack/crash-stack.c @@ -816,7 +816,6 @@ void callstack_destructor(Callstack *callstack) free(callstack->proc[it].name); free(callstack->proc[it].module_name); } - fprintf(outputfile, "End of Call Stack\n"); } /** -- 2.7.4