From be6568a9bba0254ecb01b7cb4f9d52f07098a917 Mon Sep 17 00:00:00 2001 From: Kunhoon Baik Date: Tue, 28 Jun 2016 21:16:29 +0900 Subject: [PATCH 01/16] Disable New CallStack Generation If new callstack generation issues are fixed, this feature will be re-enabled Change-Id: I7619acc80444d1d1ba0695e148241345df70803e --- src/crash-manager/crash-manager.sh.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/crash-manager/crash-manager.sh.in b/src/crash-manager/crash-manager.sh.in index b3ed342..fbdc81a 100644 --- a/src/crash-manager/crash-manager.sh.in +++ b/src/crash-manager/crash-manager.sh.in @@ -29,10 +29,10 @@ mkdir -p "$CRASH_PATH" "$pfx" if [ $DEBUG -eq 1 ] then - @CRASH_STACK_PATH@ --pid "$pid" > "$tmp_callstack_path" +# @CRASH_STACK_PATH@ --pid "$pid" > "$tmp_callstack_path" @CRASH_PIPE_PATH@ --save-core "$core_path" --report "$@" > "$info_path" - cat "$tmp_callstack_path" >> "$info_path" - rm "$tmp_callstack_path" +# cat "$tmp_callstack_path" >> "$info_path" +# rm "$tmp_callstack_path" else @CRASH_PIPE_PATH@ --report "$@" > "$info_path" @CRASH_STACK_PATH@ --pid "$pid" >> "$info_path" -- 2.7.4 From c8b398f7b97fda1b745f7644ba8e508a18f6e509 Mon Sep 17 00:00:00 2001 From: taeyoung Date: Thu, 23 Jun 2016 16:59:19 +0900 Subject: [PATCH 02/16] sys-assert: enable sys-assert - Now we can choose crash-pipe/crash-stack or sys-assert to get callstacks Change-Id: Ibb166c9206235cd7884aafd31fab008a8003236a Signed-off-by: taeyoung --- CMakeLists.txt | 6 + packaging/crash-worker.spec | 53 ++- src/crash-manager/crash-manager.sh.in | 5 + src/dump_systemstate/CMakeLists.txt | 2 +- src/sys-assert/CMakeLists.txt | 47 ++ src/sys-assert/arm/backtrace.c | 48 ++ src/sys-assert/arm/context.c | 60 +++ src/sys-assert/sys-assert.c | 827 ++++++++++++++++++++++++++++++++++ src/sys-assert/sys-assert.conf.in | 2 + src/sys-assert/sys-assert.h | 61 +++ src/sys-assert/util.c | 134 ++++++ src/sys-assert/util.h | 31 ++ src/sys-assert/x86/backtrace.c | 55 +++ src/sys-assert/x86/context.c | 55 +++ 14 files changed, 1383 insertions(+), 3 deletions(-) create mode 100644 src/sys-assert/CMakeLists.txt create mode 100644 src/sys-assert/arm/backtrace.c create mode 100644 src/sys-assert/arm/context.c create mode 100644 src/sys-assert/sys-assert.c create mode 100644 src/sys-assert/sys-assert.conf.in create mode 100755 src/sys-assert/sys-assert.h create mode 100644 src/sys-assert/util.c create mode 100644 src/sys-assert/util.h create mode 100644 src/sys-assert/x86/backtrace.c create mode 100644 src/sys-assert/x86/context.c diff --git a/CMakeLists.txt b/CMakeLists.txt index f273bb0..2f65b81 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,13 @@ SET(PREFIX ${CMAKE_INSTALL_PREFIX}) # Sub modules ADD_SUBDIRECTORY(src/crash-manager) + +IF("${SYS_ASSERT}" STREQUAL "on") + ADD_SUBDIRECTORY(src/sys-assert) +ENDIF("${SYS_ASSERT}" STREQUAL "on") + ADD_SUBDIRECTORY(src/crash-pipe) ADD_SUBDIRECTORY(src/crash-stack) + ADD_SUBDIRECTORY(src/dump_systemstate) diff --git a/packaging/crash-worker.spec b/packaging/crash-worker.spec index aacf5bf..dc39f47 100644 --- a/packaging/crash-worker.spec +++ b/packaging/crash-worker.spec @@ -1,3 +1,5 @@ +%define sys_assert on + Name: crash-worker Summary: Crash-manager Version: 0.2.0 @@ -9,6 +11,9 @@ Source1001: crash-worker.manifest BuildRequires: pkgconfig(dlog) BuildRequires: pkgconfig(libtzplatform-config) BuildRequires: cmake +%if "%{?sys_assert}" == "on" +BuildRequires: pkgconfig(libunwind) +%endif BuildRequires: libelf-devel libelf BuildRequires: libebl-devel libebl BuildRequires: libdw-devel libdw @@ -17,6 +22,7 @@ Requires(post): coreutils Requires(post): tar Requires(post): gzip Requires: libebl +Requires: libunwind %description crash-manager @@ -34,13 +40,23 @@ cp %{SOURCE1001} . export CFLAGS+=" -Werror" +%ifarch %{arm} +export CFLAGS+=" -DARM" +%else +%ifarch %{ix86} +export CFLAGS+=" -DX86" +%endif +%endif + + %cmake . \ -DCMAKE_INSTALL_PREFIX=%{_prefix} \ -DTZ_SYS_BIN=%{TZ_SYS_BIN} \ -DCRASH_PATH=%{crash_path} \ -DCRASH_TEMP=%{crash_temp} \ -DCRASH_PIPE_PATH=%{_libexecdir}/crash-pipe \ - -DCRASH_STACK_PATH=%{_libexecdir}/crash-stack + -DCRASH_STACK_PATH=%{_libexecdir}/crash-stack \ + -DSYS_ASSERT=%{sys_assert} make %{?jobs:-j%jobs} @@ -51,6 +67,32 @@ mkdir -p %{buildroot}%{crash_root_path} mkdir -p %{buildroot}%{crash_path} mkdir -p %{buildroot}%{crash_temp} + + +%if "%{?sys_assert}" == "on" + +%post +if [ ! -d /.build ]; then + orig="%{_libdir}/libsys-assert.so" + pattern=$(echo $orig | sed -e 's|/|\\/|g') + ret=$(sed -n "/${pattern}/p" %{_sysconfdir}/ld.so.preload) + if [ -z "$ret" ]; then + echo "%{_libdir}/libsys-assert.so" >> %{_sysconfdir}/ld.so.preload + fi + chmod 644 %{_sysconfdir}/ld.so.preload +fi +/sbin/ldconfig + +%postun +orig="%{_libdir}/libsys-assert.so" +pattern=$(echo $orig | sed -e 's|/|\\/|g') +sed -i "/${pattern}/D" %{_sysconfdir}/ld.so.preload +/sbin/ldconfig + +%endif + + + %files %license LICENSE %manifest crash-worker.manifest @@ -60,6 +102,13 @@ mkdir -p %{buildroot}%{crash_temp} %dir %{crash_temp} %attr(0755,system,system) %{_bindir}/dump_systemstate %{_bindir}/crash-manager.sh +%{_prefix}/lib/sysctl.d/99-crash-manager.conf + +%if "%{?sys_assert}" == "on" +%{_libdir}/libsys-assert.so +%{_libdir}/tmpfiles.d/sys-assert.conf +%endif + %{_libexecdir}/crash-pipe %{_libexecdir}/crash-stack -%{_prefix}/lib/sysctl.d/99-crash-manager.conf + diff --git a/src/crash-manager/crash-manager.sh.in b/src/crash-manager/crash-manager.sh.in index fbdc81a..4ab6b58 100644 --- a/src/crash-manager/crash-manager.sh.in +++ b/src/crash-manager/crash-manager.sh.in @@ -24,11 +24,16 @@ info_path="${pfx}/${name}.info" core_path="${pfx}/${name}.coredump" log_path="${pfx}/${name}.log" tmp_callstack_path="${pfx}/${name}.callstack" +sysassert_cs_path="/tmp/crash_stack/${cmd}_${pid}.info" mkdir -p "$CRASH_PATH" "$pfx" if [ $DEBUG -eq 1 ] then + if [ "@SYS_ASSERT@" = "on" ] + then + mv "$sysassert_cs_path" "$pfx/" + fi # @CRASH_STACK_PATH@ --pid "$pid" > "$tmp_callstack_path" @CRASH_PIPE_PATH@ --save-core "$core_path" --report "$@" > "$info_path" # cat "$tmp_callstack_path" >> "$info_path" diff --git a/src/dump_systemstate/CMakeLists.txt b/src/dump_systemstate/CMakeLists.txt index 8625c10..bd00d95 100755 --- a/src/dump_systemstate/CMakeLists.txt +++ b/src/dump_systemstate/CMakeLists.txt @@ -8,7 +8,7 @@ SET(SRCS ) INCLUDE(FindPkgConfig) -pkg_check_modules(pkgs REQUIRED dlog) +pkg_check_modules(pkgs REQUIRED dlog libunwind) FOREACH(flag ${pkgs_CFLAGS}) SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") diff --git a/src/sys-assert/CMakeLists.txt b/src/sys-assert/CMakeLists.txt new file mode 100644 index 0000000..42f1471 --- /dev/null +++ b/src/sys-assert/CMakeLists.txt @@ -0,0 +1,47 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) + +SET(LIBNAME sys-assert) +SET(SRCS + sys-assert.c + util.c +) + +IF("$ENV{CFLAGS}" MATCHES "-DARM") +SET(SRCS ${SRCS} + arm/context.c + arm/backtrace.c +) +ELSE("$ENV{CFLAGS}" MATCHES "-DARM") +SET(SRCS ${SRCS} + x86/context.c + x86/backtrace.c +) +ENDIF("$ENV{CFLAGS}" MATCHES "-DARM") + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) + +INCLUDE(FindPkgConfig) +pkg_check_modules(ppkgs REQUIRED libtzplatform-config libunwind) + +FOREACH(flag ${ppkgs_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}") +SET(CMAKE_C_FLAGS_DEBUG "-O0 -g") +SET(CMAKE_C_FLAGS_RELEASE "-O2") + +FIND_PROGRAM(UNAME NAMES uname) +EXEC_PROGRAM("${UNAME}" ARGS "-m" OUTPUT_VARIABLE "ARCH") +IF("${ARCH}" STREQUAL "arm") + ADD_DEFINITIONS("-DTARGET") + MESSAGE("add -DTARGET") +ENDIF("${ARCH}" STREQUAL "arm") + +ADD_LIBRARY(${LIBNAME} SHARED ${SRCS}) +TARGET_LINK_LIBRARIES(${LIBNAME} ${ppkgs_LDFLAGS} -ldl) + +INSTALL(TARGETS ${LIBNAME} LIBRARY DESTINATION ${LIB_INSTALL_DIR}) + +CONFIGURE_FILE(sys-assert.conf.in sys-assert.conf) +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/sys-assert.conf DESTINATION /usr/lib/tmpfiles.d) diff --git a/src/sys-assert/arm/backtrace.c b/src/sys-assert/arm/backtrace.c new file mode 100644 index 0000000..7520bba --- /dev/null +++ b/src/sys-assert/arm/backtrace.c @@ -0,0 +1,48 @@ +/* + * SYS-ASSERT + * Copyright (c) 2012-2013 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. + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include "util.h" + +int dump_callstack(void **callstack_addrs, int size, void *context, int retry) +{ + ucontext_t *ucontext = context; + int count; + + if (!callstack_addrs) + return 0; + + if (!retry && (context && ((int)ucontext->uc_mcontext.arm_pc != 0))) + count = unw_backtrace(callstack_addrs, size); + else + count = backtrace(callstack_addrs, size); + + if (count > CALLSTACK_BASE) { + count -= CALLSTACK_BASE; + } else if (context) { + callstack_addrs[CALLSTACK_BASE] = (long *)ucontext->uc_mcontext.arm_pc; + callstack_addrs[CALLSTACK_BASE] = (long *)ucontext->uc_mcontext.arm_lr; + count = 2; + } else { + count = 0; + } + return count; +}; diff --git a/src/sys-assert/arm/context.c b/src/sys-assert/arm/context.c new file mode 100644 index 0000000..ec59f9e --- /dev/null +++ b/src/sys-assert/arm/context.c @@ -0,0 +1,60 @@ +/* + * SYS-ASSERT + * Copyright (c) 2012-2013 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. + */ + +#include +#include +#include +#include "sys-assert.h" +#include "util.h" + +#define CRASH_REGISTERINFO_TITLE "Register Information" + +void dump_registers(int fd, void *context) +{ + ucontext_t *ucontext = context; + /* for context info */ + if (!context) + return; + + fprintf_fd(fd, "\n%s\n", CRASH_REGISTERINFO_TITLE); + fprintf_fd(fd, + "r0 = 0x%08x, r1 = 0x%08x\nr2 = 0x%08x, r3 = 0x%08x\n", + ucontext->uc_mcontext.arm_r0, + ucontext->uc_mcontext.arm_r1, + ucontext->uc_mcontext.arm_r2, + ucontext->uc_mcontext.arm_r3); + fprintf_fd(fd, + "r4 = 0x%08x, r5 = 0x%08x\nr6 = 0x%08x, r7 = 0x%08x\n", + ucontext->uc_mcontext.arm_r4, + ucontext->uc_mcontext.arm_r5, + ucontext->uc_mcontext.arm_r6, + ucontext->uc_mcontext.arm_r7); + fprintf_fd(fd, + "r8 = 0x%08x, r9 = 0x%08x\nr10 = 0x%08x, fp = 0x%08x\n", + ucontext->uc_mcontext.arm_r8, + ucontext->uc_mcontext.arm_r9, + ucontext->uc_mcontext.arm_r10, + ucontext->uc_mcontext.arm_fp); + fprintf_fd(fd, + "ip = 0x%08x, sp = 0x%08x\nlr = 0x%08x, pc = 0x%08x\n", + ucontext->uc_mcontext.arm_ip, + ucontext->uc_mcontext.arm_sp, + ucontext->uc_mcontext.arm_lr, + ucontext->uc_mcontext.arm_pc); + fprintf_fd(fd, "cpsr = 0x%08x\n", + ucontext->uc_mcontext.arm_cpsr); +}; diff --git a/src/sys-assert/sys-assert.c b/src/sys-assert/sys-assert.c new file mode 100644 index 0000000..0fb70de --- /dev/null +++ b/src/sys-assert/sys-assert.c @@ -0,0 +1,827 @@ +/* + * SYS-ASSERT + * Copyright (c) 2012-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. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sys-assert.h" +#include "util.h" + +#define CMDLINE_PATH "/proc/self/cmdline" +#define EXE_PATH "/proc/self/exe" +#define MAPS_PATH "/proc/self/maps" +#define MEMINFO_PATH "/proc/meminfo" +#define VERINFO_PATH "/etc/info.ini" +#define STATUS_PATH "/proc/self/status" +#define TASK_PATH "/proc/self/task" + +#define CRASH_INFO_PATH "/tmp/crash_stack" +#define CRASH_SOCKET "/tmp/crash_socket" +#define CRASH_SOCKET_PATH_LEN 17 + +#define CRASH_CALLSTACKINFO_TITLE "Callstack Information" +#define CRASH_CALLSTACKINFO_TITLE_E "End of Call Stack" +#define CRASH_MAPSINFO_TITLE "Maps Information" +#define CRASH_MAPSINFO_TITLE_E "End of Maps Information" +#define CRASH_MEMINFO_TITLE "Memory Information" +#define CRASH_THREADINFO_TITLE "Threads Information" + +#define STR_ANONY "[anony]" +#define STR_ANNOY_LEN 8 + +#define HEXA 16 +#define PERM_LEN 5 +#define ADDR_LEN 8 +#define INFO_LEN 20 +#define VALUE_LEN 24 +#define TIME_MAX_LEN 64 +#define FILE_LEN 255 +#define BUF_SIZE (BUFSIZ) +#define CALLSTACK_SIZE 100 +#define FUNC_NAME_MAX_LEN 128 +#define PATH_LEN (FILE_LEN + NAME_MAX) + +#define KB(bytes) ((bytes)/1024) + +/* permission for open file */ +#define DIR_PERMS (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) +/* permission for open file */ +#define FILE_PERMS (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) + +int sig_to_handle[] = { + SIGILL, SIGTRAP, SIGABRT, SIGBUS, + SIGFPE, SIGSEGV, SIGSTKFLT, SIGXCPU, SIGXFSZ, SIGSYS }; + +#define NUM_SIG_TO_HANDLE \ + ((int)(sizeof(sig_to_handle)/sizeof(sig_to_handle[0]))) + +struct sigaction g_oldact[NUM_SIG_TO_HANDLE]; + +extern void dump_registers(int fd, void *context); +extern int dump_callstack(void **callstack_addrs, int size, void *context, int retry); + +/* get function symbol from elf */ +static int trace_symbols(void *const *array, int size, struct addr_node *start, int fd) +{ + Dl_info info_funcs; + Elf32_Ehdr elf_h; + Elf32_Shdr *s_headers; + Elf32_Sym *symtab_entry; + int i, cnt, file, ret; + char *fname; + unsigned int addr, start_addr, offset_addr; + unsigned int strtab_index = 0; + unsigned int symtab_index = 0; + int num_st = 0; + int found_symtab = 0; + + for (cnt = 0; cnt < size; cnt++) { + num_st = 0; + /* FIXME : for walking on stack trace */ + if (dladdr(array[cnt], &info_funcs) == 0) { + fprintf(stderr, "[sys-assert]dladdr returnes error!\n"); + /* print just address */ + fprintf_fd(fd, + "%2d: (%p) %s\n", + cnt, array[cnt], dlerror()); + continue; + } + start_addr = (unsigned int)get_start_addr(array[cnt], start); + addr = (unsigned int)array[cnt]; + /* because of launchpad, + * return value of dladdr when find executable is wrong. + * so fix dli_fname here */ + if (info_funcs.dli_fbase && + info_funcs.dli_fname && + info_funcs.dli_fbase == (void *)BASE_LAUNCHPAD_ADDR && + (strncmp("/opt/apps/", info_funcs.dli_fname, + strlen("/opt/apps/")) == 0)) { + info_funcs.dli_fname = get_fpath(array[cnt], start); + offset_addr = addr; + } else { + offset_addr = addr - start_addr; + } + + /* find symbol from elf file */ + if (info_funcs.dli_sname == NULL) { + + /* Both dli_sname and dli_fname is NULL, sys-assert cannot trace any information. + Thus, sys-assert skips to translate such address entry. + However, if a developer wants raw information, we need to fix the code to print raw data */ + if(info_funcs.dli_fname == NULL) + continue; + + file = open(info_funcs.dli_fname, O_RDONLY); + if (file < 0) { + fname = strchr(info_funcs.dli_fname, '/'); + if (!fname) + continue; + file = open(fname, O_RDONLY); + if (file < 0) { + fprintf_fd(fd, + "%2d: (%p) [%s] + %p\n", + cnt, array[cnt], + info_funcs.dli_fname, offset_addr); + continue; + } + } + ret = read(file, &elf_h, sizeof(Elf32_Ehdr)); + if (ret < sizeof(Elf32_Ehdr) || + elf_h.e_shnum <= 0 || + SHN_LORESERVE < elf_h.e_shnum) { + fprintf_fd(fd, "%2d: (%p) [%s] + %p\n", + cnt, array[cnt], info_funcs.dli_fname, offset_addr); + close(file); + continue; + } + if (elf_h.e_type == ET_EXEC) { + info_funcs.dli_fbase = 0; + offset_addr = addr; + } + s_headers = + (Elf32_Shdr *) mmap(0, elf_h.e_shnum * sizeof(Elf32_Shdr), + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (s_headers == NULL) { + fprintf(stderr, "[sys-assert]malloc failed\n"); + fprintf_fd(fd, "%2d: (%p) [%s] + %p\n", + cnt, array[cnt], info_funcs.dli_fname, offset_addr); + close(file); + continue; + } + ret = lseek(file, elf_h.e_shoff, SEEK_SET); + if (ret < 0 || elf_h.e_shentsize > sizeof(Elf32_Shdr) || + elf_h.e_shentsize <= 0) { + close(file); + munmap(s_headers, elf_h.e_shnum * sizeof(Elf32_Shdr)); + return -1; + } + for (i = 0; i < elf_h.e_shnum; i++) { + ret = read(file, &s_headers[i], elf_h.e_shentsize); + if (ret < elf_h.e_shentsize) { + fprintf(stderr, "[sys-assert]read error\n"); + munmap(s_headers, elf_h.e_shnum * sizeof(Elf32_Shdr)); + close(file); + return -1; + } + } + for (i = 0; i < elf_h.e_shnum; i++) { + if (s_headers[i].sh_type == SHT_SYMTAB) { + symtab_index = i; + if (s_headers[i].sh_entsize != 0 && + s_headers[i].sh_size != 0) { + num_st = + s_headers[i].sh_size / s_headers[i].sh_entsize; + found_symtab = 1; + } + break; + } + } + if (!found_symtab) { + fprintf(stderr, + "[sys-assert] can't find symtab\n"); + munmap(s_headers, elf_h.e_shnum * sizeof(Elf32_Shdr)); + close(file); + } else { + /*.strtab index */ + if (symtab_index < elf_h.e_shnum) + strtab_index = s_headers[symtab_index].sh_link; + if (!strtab_index || elf_h.e_shnum <= strtab_index) { + fprintf_fd(fd, "%2d: (%p) [%s] + %p\n", + cnt, array[cnt], info_funcs.dli_fname, offset_addr); + munmap(s_headers, elf_h.e_shnum * sizeof(Elf32_Shdr)); + close(file); + continue; + } + symtab_entry = + (Elf32_Sym *)mmap(0, sizeof(Elf32_Sym) * num_st, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (symtab_entry == NULL) { + fprintf(stderr, "[sys-assert]malloc failed\n"); + munmap(s_headers, elf_h.e_shnum * sizeof(Elf32_Shdr)); + close(file); + return -1; + } + ret = lseek(file, s_headers[symtab_index].sh_offset, SEEK_SET); + if (ret < 0) { + fprintf_fd(fd, "%2d: (%p) [%s] + %p\n", + cnt, array[cnt], info_funcs.dli_fname, offset_addr); + munmap(symtab_entry, sizeof(Elf32_Sym) * num_st); + munmap(s_headers, elf_h.e_shnum * sizeof(Elf32_Shdr)); + close(file); + continue; + } + for (i = 0; i < num_st; i++) { + ret = read(file, &symtab_entry[i], sizeof(Elf32_Sym)); + if (ret < sizeof(Elf32_Sym)) { + fprintf_fd(fd, + "[sys-assert]symtab_entry[%d], num_st=%d, readnum = %d\n", + i, num_st, ret); + break; + } + if (((info_funcs.dli_fbase + + symtab_entry[i].st_value) + <= array[cnt]) + && (array[cnt] <= + (info_funcs.dli_fbase + + symtab_entry[i].st_value + + symtab_entry[i].st_size))) { + if (symtab_entry[i].st_shndx != STN_UNDEF) { + ret = lseek(file, + s_headers[strtab_index].sh_offset + + symtab_entry[i].st_name, + SEEK_SET); + if (ret < 0) + break; + info_funcs.dli_sname = + (void *)mmap(0, FUNC_NAME_MAX_LEN, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + ret = read(file, (void *)info_funcs.dli_sname, + FUNC_NAME_MAX_LEN); + if (ret < 0) + break; + info_funcs.dli_saddr = + info_funcs.dli_fbase + + symtab_entry[i].st_value; + } + break; + } + } + munmap(s_headers, elf_h.e_shnum * sizeof(Elf32_Shdr)); + munmap(symtab_entry, sizeof(Elf32_Sym) * num_st); + close(file); + } + } + /* print symbol name and address. */ + if (info_funcs.dli_sname != NULL) { + if (array[cnt] >= info_funcs.dli_saddr) + fprintf_fd(fd, "%2d: %s + 0x%x (%p) [%s] + %p\n", + cnt, info_funcs.dli_sname, + (array[cnt] - info_funcs.dli_saddr), + array[cnt], info_funcs.dli_fname, offset_addr); + else + fprintf_fd(fd, "%2d: %s - 0x%x (%p) [%s] + %p\n", + cnt, info_funcs.dli_sname, + (info_funcs.dli_saddr - array[cnt]), + array[cnt], info_funcs.dli_fname, offset_addr); + } else { + fprintf_fd(fd, "%2d: (%p) [%s] + %p\n", + cnt, array[cnt], info_funcs.dli_fname, offset_addr); + } + } + return 0; +} +/* get address list from maps */ +static struct addr_node *get_addr_list_from_maps(int fd) +{ + int fpath_len, result; + long *saddr; + long *eaddr; + char perm[PERM_LEN]; + char path[PATH_LEN]; + char addr[ADDR_LEN * 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_LEN); + result = sscanf(linebuf, "%s %s %*s %*s %*s %s ", addr, perm, path); + if (result < 0) + continue; + perm[PERM_LEN - 1] = 0; + /* rwxp */ +#ifdef ARM + if ((perm[2] == 'x' && path[0] == '/') || + (perm[1] == 'w' && path[0] != '/')) { +#else + if (strncmp(perm, "r-xp", strlen("r-xp")) == 0) { +#endif + /* add addr node to list */ + addr[ADDR_LEN] = 0; + saddr = (long *)strtoul(addr, NULL, HEXA); + /* ffff0000-ffff1000 */ + eaddr = (long *)strtoul(&addr[ADDR_LEN + 1], 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_ANNOY_LEN, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + memset(t_node->fpath, 0, STR_ANNOY_LEN); + memcpy(t_node->fpath, STR_ANONY, STR_ANNOY_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 print_node_to_file(struct addr_node *start, int fd) +{ + struct addr_node *t_node; + + t_node = start; + fprintf_fd(fd, "\n%s\n", CRASH_MAPSINFO_TITLE); + while (t_node) { + if (!strncmp(STR_ANONY, t_node->fpath, STR_ANNOY_LEN)) { + t_node = t_node->next; + } else { + fprintf_fd(fd, + "%08x %08x %s %s\n", + (unsigned int)t_node->startaddr, + (unsigned int)t_node->endaddr, + t_node->perm, t_node->fpath); + t_node = t_node->next; + } + } + fprintf_fd(fd, "%s\n", CRASH_MAPSINFO_TITLE_E); +} + +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 void print_signal_info(int signum, const siginfo_t *info, int fd) +{ + fprintf_fd(fd, "Signal: %d\n", signum); + switch (signum) { + case SIGILL: + fprintf_fd(fd, " (SIGILL)\n"); + break; + case SIGTRAP: + fprintf_fd(fd, " (SIGTRAP)\n"); + break; + case SIGABRT: + fprintf_fd(fd, " (SIGABRT)\n"); + break; + case SIGBUS: + fprintf_fd(fd, " (SIGBUS)\n"); + break; + case SIGFPE: + fprintf_fd(fd, " (SIGFPE)\n"); + break; + case SIGSEGV: + fprintf_fd(fd, " (SIGSEGV)\n"); + break; + case SIGTERM: + fprintf_fd(fd, " (SIGTERM)\n"); + break; + case SIGSTKFLT: + fprintf_fd(fd, " (SIGSTKFLT)\n"); + break; + case SIGXCPU: + fprintf_fd(fd, " (SIGXCPU)\n"); + break; + case SIGXFSZ: + fprintf_fd(fd, " (SIGXFSZ)\n"); + break; + case SIGSYS: + fprintf_fd(fd, " (SIGSYS)\n"); + break; + default: + fprintf_fd(fd, "\n"); + } + /* print signal si_code info */ + fprintf_fd(fd, " si_code: %d\n", info->si_code); + if (info->si_code <= 0 || info->si_code >= 0x80) { + switch (info->si_code) { +#ifdef SI_TKILL + case SI_TKILL: + fprintf_fd(fd, + " signal sent by tkill (sent by pid %d, uid %d)\n", + info->si_pid, info->si_uid); + break; +#endif +#ifdef SI_USER + case SI_USER: + fprintf_fd(fd, + " signal sent by kill (sent by pid %d, uid %d)\n", + info->si_pid, info->si_uid); + break; +#endif +#ifdef SI_KERNEL + case SI_KERNEL: + fprintf_fd(fd, " signal sent by the kernel\n"); + break; +#endif + } + } else if (signum == SIGILL) { + switch (info->si_code) { + case ILL_ILLOPC: + fprintf_fd(fd, " illegal opcode\n"); + break; + case ILL_ILLOPN: + fprintf_fd(fd, " illegal operand\n"); + break; + case ILL_ILLADR: + fprintf_fd(fd, " illegal addressing mode\n"); + break; + case ILL_ILLTRP: + fprintf_fd(fd, " illegal trap\n"); + break; + case ILL_PRVOPC: + fprintf_fd(fd, " privileged opcode\n"); + break; + case ILL_PRVREG: + fprintf_fd(fd, " privileged register\n"); + break; + case ILL_COPROC: + fprintf_fd(fd, " coprocessor error\n"); + break; + case ILL_BADSTK: + fprintf_fd(fd, " internal stack error\n"); + break; + default: + fprintf_fd(fd, " illegal si_code = %d\n", info->si_code); + break; + } + fprintf_fd(fd, " si_addr: %p\n", info->si_addr); + } else if (signum == SIGFPE) { + switch (info->si_code) { + case FPE_INTDIV: + fprintf_fd(fd, " integer divide by zero\n"); + break; + case FPE_INTOVF: + fprintf_fd(fd, " integer overflow\n"); + break; + case FPE_FLTDIV: + fprintf_fd(fd, " floating-point divide by zero\n"); + break; + case FPE_FLTOVF: + fprintf_fd(fd, " floating-point overflow\n"); + break; + case FPE_FLTUND: + fprintf_fd(fd, " floating-point underflow\n"); + break; + case FPE_FLTRES: + fprintf_fd(fd, " floating-point inexact result\n"); + break; + case FPE_FLTINV: + fprintf_fd(fd, " invalid floating-point operation\n"); + break; + case FPE_FLTSUB: + fprintf_fd(fd, " subscript out of range\n"); + break; + default: + fprintf_fd(fd, " illegal si_code: %d\n", info->si_code); + break; + } + } else if (signum == SIGSEGV) { + switch (info->si_code) { + case SEGV_MAPERR: + fprintf_fd(fd, " address not mapped to object\n"); + break; + case SEGV_ACCERR: + fprintf_fd(fd, + " invalid permissions for mapped object\n"); + break; + default: + fprintf_fd(fd, " illegal si_code: %d\n", info->si_code); + break; + } + fprintf_fd(fd, " si_addr = %p\n", info->si_addr); + } else if (signum == SIGBUS) { + switch (info->si_code) { + case BUS_ADRALN: + fprintf_fd(fd, " invalid address alignment\n"); + break; + case BUS_ADRERR: + fprintf_fd(fd, " nonexistent physical address\n"); + break; + case BUS_OBJERR: + fprintf_fd(fd, " object-specific hardware error\n"); + break; + default: + fprintf_fd(fd, " illegal si_code: %d\n", info->si_code); + break; + } + fprintf_fd(fd, " si_addr: %p\n", info->si_addr); + } +} + +void sighandler(int signum, siginfo_t *info, void *context) +{ + int idx; + int readnum; + int threadnum; + /* file descriptor */ + int fd; + int fd_cs; /* for cs file */ + pid_t pid; + pid_t tid; + DIR *dir; + struct dirent *dentry; + char timestr[TIME_MAX_LEN]; + char processname[NAME_MAX] = {0,}; + char exepath[PATH_LEN] = {0,}; + char filepath[PATH_LEN]; + char crashid[TIME_MAX_LEN] = {0,}; + /* for get time */ + time_t cur_time; + /* for get info */ + char infoname[INFO_LEN]; + char value[VALUE_LEN]; + char linebuf[BUF_SIZE]; + char *p_exepath = NULL; + void *callstack_addrs[CALLSTACK_SIZE]; + int cnt_callstack = 0; + /* for backtrace_symbols() */ + struct addr_node *head = NULL; + /* for preventing recursion */ + static int retry_count = 0; + struct sysinfo si; + + if (retry_count > 1) { + fprintf(stderr, "[sys-assert] recurcive called\n"); + return; + } + + cur_time = time(NULL); + /* get pid */ + pid = getpid(); + tid = (long int)syscall(__NR_gettid); + /* open maps file */ + if ((fd = open(MAPS_PATH, O_RDONLY)) < 0) { + fprintf(stderr, "[sys-assert]can't open %s\n", MAPS_PATH); + } else { + /* parsing the maps to get code segment address*/ + head = get_addr_list_from_maps(fd); + close(fd); + } + if (retry_count) + fprintf(stderr, "retry backtrace in sighandler"); + cnt_callstack = dump_callstack(callstack_addrs, CALLSTACK_SIZE, context, retry_count); + retry_count += 1; + /* get exepath */ + if ((readnum = open_read(CMDLINE_PATH, exepath, sizeof(exepath) - 1)) <= 0) { + fprintf(stderr, "[sys-assert]can't read %s\n", CMDLINE_PATH); + readnum = snprintf(exepath, sizeof(exepath), "unknown_process"); + } + exepath[readnum] = '\0'; + /* get processname */ + if ((p_exepath = remove_path(exepath)) == NULL) + return; + snprintf(processname, NAME_MAX, "%s", p_exepath); + /* added temporary skip when crash-worker is asserted */ + if (!strcmp(processname, "crash-worker") || + !strcmp(processname, "crash-popup")) + return; + /* make crash info file name */ + snprintf(timestr, sizeof(timestr), "%.10ld", cur_time); + snprintf(crashid, sizeof(crashid), "%s_%d",processname, pid); + if (snprintf(filepath, PATH_LEN, + "%s/%s.info", CRASH_INFO_PATH, crashid) == 0) { + fprintf(stderr, + "[sys-assert]can't make crash info file name : %s\n", + crashid); + return; + } + /* check crash info dump directory, make directory if absent */ + if (access(CRASH_INFO_PATH, F_OK) == -1) { + fprintf(stderr, "[sys-assert] No directory (%s)", CRASH_INFO_PATH); + /*TODO: making directory */ + return; + } + /* logging crash information to stderr */ + fprintf(stderr, "crashed [%s] processname=%s, pid=%d, tid=%d, signal=%d", + timestr, processname, pid, tid, signum); + /* complete filepath_cs */ + if (!strlen(filepath)) + return; + /* create cs file */ + if ((fd_cs = creat(filepath, FILE_PERMS)) < 0) { + fprintf(stderr, + "[sys-assert]can't create %s. errno = %s\n", + filepath, strerror(errno)); + return; + } + + /* print exepath info */ + fprintf_fd(fd_cs, "Executable File Path: %s\n", exepath); + + /* print signal info */ + print_signal_info(signum, info, fd_cs); + fsync(fd_cs); + /* print register info */ + dump_registers(fd_cs, context); + + /* print meminfo */ + fprintf_fd(fd_cs, "\n%s\n", CRASH_MEMINFO_TITLE); + if (!sysinfo(&si)) { + fprintf_fd(fd_cs, "MemTotal: %8ld KB\n", KB(si.totalram)); + fprintf_fd(fd_cs, "MemFree: %8ld KB\n", KB(si.freeram)); + fprintf_fd(fd_cs, "Buffers: %8ld KB\n", KB(si.bufferram)); + } else + fprintf(stderr, "[sys-assert]can't get sysinfo\n"); + + if ((fd = open(MEMINFO_PATH, O_RDONLY)) < 0) { + fprintf(stderr, "[sys-assert]can't open %s\n", MEMINFO_PATH); + } else { + while (fgets_fd(linebuf, BUF_SIZE, fd) != NULL) { + sscanf(linebuf, "%s %s %*s", infoname, value); + if (strcmp("Cached:", infoname) == 0) { + fprintf_fd(fd_cs, "%s %8s KB\n", infoname, value); + break; + } + } + close(fd); + } + + threadnum = 0; + if ((fd = open(STATUS_PATH, O_RDONLY)) < 0) { + fprintf(stderr, "[sys-assert]can't open %s\n", STATUS_PATH); + } else { + while (fgets_fd(linebuf, BUF_SIZE, fd) != NULL) { + sscanf(linebuf, "%s %s %*s", infoname, value); + if (strcmp("VmPeak:", infoname) == 0) { + fprintf_fd(fd_cs, "%s %8s KB\n", infoname, + value); + } else if (strcmp("VmSize:", infoname) == 0) { + fprintf_fd(fd_cs, "%s %8s KB\n", infoname, + value); + } else if (strcmp("VmLck:", infoname) == 0) { + fprintf_fd(fd_cs, "%s %8s KB\n", infoname, + value); + } else if (strcmp("VmPin:", infoname) == 0) { + fprintf_fd(fd_cs, "%s %8s KB\n", infoname, + value); + } else if (strcmp("VmHWM:", infoname) == 0) { + fprintf_fd(fd_cs, "%s %8s KB\n", + infoname, value); + } else if (strcmp("VmRSS:", infoname) == 0) { + fprintf_fd(fd_cs, "%s %8s KB\n", + infoname, value); + } else if (strcmp("VmData:", infoname) == 0) { + fprintf_fd(fd_cs, "%s %8s KB\n", + infoname, value); + } else if (strcmp("VmStk:", infoname) == 0) { + fprintf_fd(fd_cs, "%s %8s KB\n", + infoname, value); + } else if (strcmp("VmExe:", infoname) == 0) { + fprintf_fd(fd_cs, "%s %8s KB\n", + infoname, value); + } else if (strcmp("VmLib:", infoname) == 0) { + fprintf_fd(fd_cs, "%s %8s KB\n", + infoname, value); + } else if (strcmp("VmPTE:", infoname) == 0) { + fprintf_fd(fd_cs, "%s %8s KB\n", + infoname, value); + } else if (strcmp("VmSwap:", infoname) == 0) { + fprintf_fd(fd_cs, "%s %8s KB\n", + infoname, value); + } else if (strcmp("Threads:", infoname) == 0) { + threadnum = atoi(value); + break; + } + } + close(fd); + } + /* print thread info */ + if (1 < threadnum) { + fprintf_fd(fd_cs, "\n%s\n", CRASH_THREADINFO_TITLE); + fprintf_fd(fd_cs, + "Threads: %d\nPID = %d TID = %d\n", + threadnum, pid, tid); + /* print thread */ + dir = opendir(TASK_PATH); + if (!dir) { + fprintf(stderr, "[sys-assert]can't open %s\n", TASK_PATH); + } else { + while ((dentry = readdir(dir)) != NULL) { + if( strcmp(dentry->d_name, ".") == 0 + || strcmp(dentry->d_name, "..") == 0) + continue; + fprintf_fd(fd_cs, "%s ",dentry->d_name); + } + closedir(dir); + fprintf_fd(fd_cs, "\n"); + } + } + if (head != NULL) { + /* print maps information */ + print_node_to_file(head, fd_cs); + /* print callstack */ + fprintf_fd(fd_cs, "\n%s (PID:%d)\n", CRASH_CALLSTACKINFO_TITLE, pid); + fprintf_fd(fd_cs, "Call Stack Count: %d\n", cnt_callstack); + if (trace_symbols(&callstack_addrs[CALLSTACK_BASE], + cnt_callstack, head, fd_cs) < 0) + fprintf(stderr, "[sys-assert] trace_symbols failed\n"); + fprintf_fd(fd_cs, "%s\n", CRASH_CALLSTACKINFO_TITLE_E); + free_all_nodes(head); + } + /* cs file sync */ + fsync(fd_cs); + /* clean up */ + if (close(fd_cs) == -1) + fprintf(stderr, "[sys-assert] fd_cs close error!!\n"); + /* core dump set */ + if (prctl(PR_GET_DUMPABLE) == 0) + prctl(PR_SET_DUMPABLE, 1); + + for (idx = 0; idx < NUM_SIG_TO_HANDLE; idx++) { + if (sig_to_handle[idx] == signum) { + sigaction(signum, &g_oldact[idx], NULL); + break; + } + } + raise(signum); +} + +__attribute__ ((constructor)) +void init() +{ + int idx; + + for (idx = 0; idx < NUM_SIG_TO_HANDLE; idx++) { + struct sigaction act; + act.sa_sigaction = (void *)sighandler; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_SIGINFO; + act.sa_flags |= SA_RESETHAND; + if (sigaction(sig_to_handle[idx], &act, &g_oldact[idx]) < 0) { + perror("[sys-assert]could not set signal handler "); + continue; + } + } +} diff --git a/src/sys-assert/sys-assert.conf.in b/src/sys-assert/sys-assert.conf.in new file mode 100644 index 0000000..29dff1d --- /dev/null +++ b/src/sys-assert/sys-assert.conf.in @@ -0,0 +1,2 @@ +d /tmp/crash_stack 1777 root root +t /tmp/crash_stack - - - - security.SMACK64=* diff --git a/src/sys-assert/sys-assert.h b/src/sys-assert/sys-assert.h new file mode 100755 index 0000000..7412f3c --- /dev/null +++ b/src/sys-assert/sys-assert.h @@ -0,0 +1,61 @@ +/* + * SYS-ASSERT + * Copyright (c) 2012-2013 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. + */ + + +#ifndef _DEBUG_ASSERT_H_ +#define _DEBUG_ASSERT_H_ + +#include + +#ifdef ARM +#define BASE_LAUNCHPAD_ADDR 0x8000 +#else +#define BASE_LAUNCHPAD_ADDR 0x8048000 +#endif +#define CALLSTACK_BASE 3 + +#ifdef __cplusplus +extern "C" { +#endif + + struct addr_node { + long *startaddr; + long *endaddr; + char perm[5]; + char *fpath; + struct addr_node *next; + }; + +#ifdef ARM + typedef struct layout { + struct layout *fp; + void *ret; + } layout; + +#else + typedef struct layout { + struct layout *ebp; + void *ret; + } layout; +#endif + + extern void *__libc_stack_end; + +#ifdef __cplusplus +} +#endif +#endif /* _DEBUG_ASSERT_H_ */ diff --git a/src/sys-assert/util.c b/src/sys-assert/util.c new file mode 100644 index 0000000..30200ba --- /dev/null +++ b/src/sys-assert/util.c @@ -0,0 +1,134 @@ +/* + * SYS-ASSERT + * Copyright (c) 2012-2013 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. + */ + +#include +#include +#include +#include +#include +#include "util.h" + +int open_read(const char *path, char *buf, int size) +{ + int fd; + int ret; + + if (buf == NULL || path == NULL) + return -1; + + fd = open(path, O_RDONLY); + if (fd < 0) + return -1; + + ret = read(fd, buf, size - 1); + if (ret <= 0) { + close(fd); + return -1; + } else + buf[ret] = '\0'; + + close(fd); + + return ret; +} + +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; +} + +/* WARNING : formatted string buffer is limited to 1024 byte */ +int fprintf_fd(int fd, const char *fmt, ...) +{ + int n, ret; + char buff[1024]; + va_list args; + + va_start(args, fmt); + n = vsnprintf(buff, 1024 - 1, fmt, args); + ret = write(fd, buff, n); + if (ret < 0) + fprintf(stderr, "write failed\n"); + va_end(args); + return n; +} + +char *remove_path(const char *cmd) +{ + char *cp; + char *np; + + cp = np = (char *)cmd; + while (*cp && *cp != ' ') { + if (*cp == '/') + np = cp + 1; + cp++; + } + return np; +} + +char *get_fpath(long *value, struct addr_node *start) +{ + struct addr_node *t_node; + struct addr_node *n_node; + + if (value == 0 || start == NULL) + return NULL; + t_node = start; + n_node = t_node->next; + while (n_node) { + if (t_node->endaddr <= value) { + t_node = n_node; + n_node = n_node->next; + } else if (t_node->startaddr <= value) { + return t_node->fpath; + } else + break; + } + return NULL; +} + +long *get_start_addr(long *value, struct addr_node *start) +{ + struct addr_node *t_node; + struct addr_node *n_node; + + if (value == 0 || start == NULL) + return NULL; + t_node = start; + n_node = t_node->next; + while (n_node) { + if (t_node->endaddr <= value) { + t_node = n_node; + n_node = n_node->next; + } else if (t_node->startaddr <= value) { + return t_node->startaddr; + } else + break; + } + return NULL; +} diff --git a/src/sys-assert/util.h b/src/sys-assert/util.h new file mode 100644 index 0000000..a06077e --- /dev/null +++ b/src/sys-assert/util.h @@ -0,0 +1,31 @@ +/* + * SYS-ASSERT + * Copyright (c) 2012-2013 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. + */ + +#include "sys-assert.h" + +int open_read(const char *path, char *buf, int size); + +char *fgets_fd(char *str, int len, int fd); + +/* WARNING : formatted string buffer is limited to 1024 byte */ +int fprintf_fd(int fd, const char *fmt, ...); + +char *remove_path(const char *cmd); + +char *get_fpath(long *value, struct addr_node *start); + +long *get_start_addr(long *value, struct addr_node *start); diff --git a/src/sys-assert/x86/backtrace.c b/src/sys-assert/x86/backtrace.c new file mode 100644 index 0000000..c2ab833 --- /dev/null +++ b/src/sys-assert/x86/backtrace.c @@ -0,0 +1,55 @@ +/* + * SYS-ASSERT + * Copyright (c) 2012-2013 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. + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include "sys-assert.h" +#include "util.h" + +int dump_callstack(void **callstack_addrs, int size, void *context, int retry) +{ + ucontext_t *ucontext = context; + int count = CALLSTACK_BASE; + + if (!callstack_addrs) + return 0; + + if (context) { + layout *ebp = (layout *)ucontext->uc_mcontext.gregs[REG_EBP]; + callstack_addrs[count++] = + (long *)ucontext->uc_mcontext.gregs[REG_EIP]; + while (ebp && (count < size)) { + callstack_addrs[count++] = ebp->ret; + ebp = ebp->ebp; + } + } else { + count = backtrace(callstack_addrs, size); + } + + if (count > CALLSTACK_BASE) { + count -= CALLSTACK_BASE; + } else if (context) { + callstack_addrs[CALLSTACK_BASE] = (long *)ucontext->uc_mcontext.gregs[REG_EIP]; + callstack_addrs[CALLSTACK_BASE + 1] = (long *)ucontext->uc_mcontext.gregs[REG_ESP]; + count = 2; + } else { + count = 0; + } + return count; +}; diff --git a/src/sys-assert/x86/context.c b/src/sys-assert/x86/context.c new file mode 100644 index 0000000..20d37bc --- /dev/null +++ b/src/sys-assert/x86/context.c @@ -0,0 +1,55 @@ +/* + * SYS-ASSERT + * Copyright (c) 2012-2013 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. + */ +#define _GNU_SOURCE +#include +#include +#include +#include "sys-assert.h" +#include "util.h" + +#define CRASH_REGISTERINFO_TITLE "Register Information" + +void dump_registers(int fd, void *context) +{ + ucontext_t *ucontext = context; + /* for context info */ + if (!context) + return; + + fprintf_fd(fd, "\n%s\n", CRASH_REGISTERINFO_TITLE); + fprintf_fd(fd, + "gs = 0x%08x, fs = 0x%08x\nes = 0x%08x, ds = 0x%08x\n", + ucontext->uc_mcontext.gregs[REG_GS], + ucontext->uc_mcontext.gregs[REG_FS], + ucontext->uc_mcontext.gregs[REG_ES], + ucontext->uc_mcontext.gregs[REG_DS]); + fprintf_fd(fd, + "edi = 0x%08x, esi = 0x%08x\nebp = 0x%08x, esp = 0x%08x\n", + ucontext->uc_mcontext.gregs[REG_EDI], + ucontext->uc_mcontext.gregs[REG_ESI], + ucontext->uc_mcontext.gregs[REG_EBP], + ucontext->uc_mcontext.gregs[REG_ESP]); + fprintf_fd(fd, + "eax = 0x%08x, ebx = 0x%08x\necx = 0x%08x, edx = 0x%08x\n", + ucontext->uc_mcontext.gregs[REG_EAX], + ucontext->uc_mcontext.gregs[REG_EBX], + ucontext->uc_mcontext.gregs[REG_ECX], + ucontext->uc_mcontext.gregs[REG_EDX]); + fprintf_fd(fd, + "eip = 0x%08x\n", + ucontext->uc_mcontext.gregs[REG_EIP]); +}; -- 2.7.4 From ccca6a831cd742b83471134a1b620f97238a2546 Mon Sep 17 00:00:00 2001 From: taeyoung Date: Thu, 30 Jun 2016 10:44:00 +0900 Subject: [PATCH 03/16] sys-assert: apply registers for 64bit architecture - The registers of 64 bit architecture are little bit different with 32 bit architecture. Thus the operations to print register information are separated according to the architectures. Change-Id: I44077fa88f18c97e1ae84caa4998feef6408b9dc Signed-off-by: taeyoung --- packaging/crash-worker.spec | 18 ++++--- src/sys-assert/CMakeLists.txt | 41 ++++++++++----- src/sys-assert/arm_64/backtrace.c | 48 +++++++++++++++++ src/sys-assert/arm_64/context.c | 94 ++++++++++++++++++++++++++++++++++ src/sys-assert/sys-assert.c | 18 ++++--- src/sys-assert/sys-assert.h | 4 +- src/sys-assert/x86/backtrace.c | 1 + src/sys-assert/x86/context.c | 1 + src/sys-assert/x86/sys-assert-regs.h | 99 ++++++++++++++++++++++++++++++++++++ 9 files changed, 297 insertions(+), 27 deletions(-) create mode 100644 src/sys-assert/arm_64/backtrace.c create mode 100644 src/sys-assert/arm_64/context.c create mode 100644 src/sys-assert/x86/sys-assert-regs.h diff --git a/packaging/crash-worker.spec b/packaging/crash-worker.spec index dc39f47..e7a05a8 100644 --- a/packaging/crash-worker.spec +++ b/packaging/crash-worker.spec @@ -40,17 +40,23 @@ cp %{SOURCE1001} . export CFLAGS+=" -Werror" -%ifarch %{arm} -export CFLAGS+=" -DARM" +%ifarch %{arm} aarch64 + %define ARCH arm %else -%ifarch %{ix86} -export CFLAGS+=" -DX86" -%endif + %define ARCH x86 %endif +%ifarch %{arm} %ix86 + %define ARCH_BIT 32 +%else + %define ARCH_BIT 64 +%endif %cmake . \ -DCMAKE_INSTALL_PREFIX=%{_prefix} \ + -DTMP_FILES_DIR=%{_tmpfilesdir} \ + -DARCH=%{ARCH} \ + -DARCH_BIT=%{ARCH_BIT} \ -DTZ_SYS_BIN=%{TZ_SYS_BIN} \ -DCRASH_PATH=%{crash_path} \ -DCRASH_TEMP=%{crash_temp} \ @@ -106,7 +112,7 @@ sed -i "/${pattern}/D" %{_sysconfdir}/ld.so.preload %if "%{?sys_assert}" == "on" %{_libdir}/libsys-assert.so -%{_libdir}/tmpfiles.d/sys-assert.conf +%{_tmpfilesdir}/sys-assert.conf %endif %{_libexecdir}/crash-pipe diff --git a/src/sys-assert/CMakeLists.txt b/src/sys-assert/CMakeLists.txt index 42f1471..9656d52 100644 --- a/src/sys-assert/CMakeLists.txt +++ b/src/sys-assert/CMakeLists.txt @@ -6,17 +6,34 @@ SET(SRCS util.c ) -IF("$ENV{CFLAGS}" MATCHES "-DARM") -SET(SRCS ${SRCS} - arm/context.c - arm/backtrace.c -) -ELSE("$ENV{CFLAGS}" MATCHES "-DARM") -SET(SRCS ${SRCS} - x86/context.c - x86/backtrace.c -) -ENDIF("$ENV{CFLAGS}" MATCHES "-DARM") +#arm +IF("${ARCH}" STREQUAL "arm") +IF("${ARCH_BIT}" STREQUAL "32") + SET(SRCS ${SRCS} + arm/context.c + arm/backtrace.c + ) +ENDIF("${ARCH_BIT}" STREQUAL "32") +IF("${ARCH_BIT}" STREQUAL "64") + SET(SRCS ${SRCS} + arm_64/context.c + arm_64/backtrace.c + ) +ENDIF("${ARCH_BIT}" STREQUAL "64") +ADD_DEFINITIONS("-DARCH_ARM") +ENDIF("${ARCH}" STREQUAL "arm") + +#x86 +IF("${ARCH}" STREQUAL "x86") + SET(SRCS ${SRCS} + x86/context.c + x86/backtrace.c + ) +ENDIF("${ARCH}" STREQUAL "x86") + +IF("${ARCH_BIT}" STREQUAL "64") +ADD_DEFINITIONS("-DARCH_64") +ENDIF("${ARCH_BIT}" STREQUAL "64") INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) @@ -44,4 +61,4 @@ TARGET_LINK_LIBRARIES(${LIBNAME} ${ppkgs_LDFLAGS} -ldl) INSTALL(TARGETS ${LIBNAME} LIBRARY DESTINATION ${LIB_INSTALL_DIR}) CONFIGURE_FILE(sys-assert.conf.in sys-assert.conf) -INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/sys-assert.conf DESTINATION /usr/lib/tmpfiles.d) +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/sys-assert.conf DESTINATION ${TMP_FILES_DIR}) diff --git a/src/sys-assert/arm_64/backtrace.c b/src/sys-assert/arm_64/backtrace.c new file mode 100644 index 0000000..3c8f560 --- /dev/null +++ b/src/sys-assert/arm_64/backtrace.c @@ -0,0 +1,48 @@ +/* + * SYS-ASSERT + * Copyright (c) 2012-2013 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. + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include "util.h" + +int dump_callstack(void **callstack_addrs, int size, void *context, int retry) +{ + ucontext_t *ucontext = context; + int count; + + if (!callstack_addrs) + return 0; + + if (!retry && (context && ((int)ucontext->uc_mcontext.pc != 0))) + count = unw_backtrace(callstack_addrs, size); + else + count = backtrace(callstack_addrs, size); + + if (count > CALLSTACK_BASE) { + count -= CALLSTACK_BASE; + } else if (context) { + callstack_addrs[CALLSTACK_BASE] = (long *)ucontext->uc_mcontext.pc; + callstack_addrs[CALLSTACK_BASE] = (long *)ucontext->uc_mcontext.regs[30]; /* LR (link register) */ + count = 2; + } else { + count = 0; + } + return count; +}; diff --git a/src/sys-assert/arm_64/context.c b/src/sys-assert/arm_64/context.c new file mode 100644 index 0000000..9416eb8 --- /dev/null +++ b/src/sys-assert/arm_64/context.c @@ -0,0 +1,94 @@ +/* + * SYS-ASSERT + * Copyright (c) 2012-2013 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. + */ + +#include +#include +#include +#include "sys-assert.h" +#include "util.h" + +#define CRASH_REGISTERINFO_TITLE "Register Information" + +void dump_registers(int fd, void *context) +{ + ucontext_t *ucontext = context; + + /* for context info */ + if (!context) + return; + + fprintf_fd(fd, "\n%s\n", CRASH_REGISTERINFO_TITLE); + fprintf_fd(fd, + "x0 = 0x%08x, x1 = 0x%08x\nx2 = 0x%08x, x3 = 0x%08x\n", + ucontext->uc_mcontext.regs[0], + ucontext->uc_mcontext.regs[1], + ucontext->uc_mcontext.regs[2], + ucontext->uc_mcontext.regs[3]); + fprintf_fd(fd, + "x4 = 0x%08x, x5 = 0x%08x\nx6 = 0x%08x, x7 = 0x%08x\n", + ucontext->uc_mcontext.regs[4], + ucontext->uc_mcontext.regs[5], + ucontext->uc_mcontext.regs[6], + ucontext->uc_mcontext.regs[7]); + fprintf_fd(fd, + "x8 = 0x%08x, x9 = 0x%08x\nx10 = 0x%08x, x11 = 0x%08x\n", + ucontext->uc_mcontext.regs[8], + ucontext->uc_mcontext.regs[9], + ucontext->uc_mcontext.regs[10], + ucontext->uc_mcontext.regs[11]); + fprintf_fd(fd, + "x12 = 0x%08x, x13 = 0x%08x\nx14 = 0x%08x, x15 = 0x%08x\n", + ucontext->uc_mcontext.regs[12], + ucontext->uc_mcontext.regs[13], + ucontext->uc_mcontext.regs[14], + ucontext->uc_mcontext.regs[15]); + fprintf_fd(fd, + "x16 = 0x%08x, x17 = 0x%08x\nx18 = 0x%08x, x19 = 0x%08x\n", + ucontext->uc_mcontext.regs[16], + ucontext->uc_mcontext.regs[17], + ucontext->uc_mcontext.regs[18], + ucontext->uc_mcontext.regs[19]); + fprintf_fd(fd, + "x20 = 0x%08x, x21 = 0x%08x\nx22 = 0x%08x, x23 = 0x%08x\n", + ucontext->uc_mcontext.regs[20], + ucontext->uc_mcontext.regs[21], + ucontext->uc_mcontext.regs[22], + ucontext->uc_mcontext.regs[23]); + fprintf_fd(fd, + "x24 = 0x%08x, x25 = 0x%08x\nx26 = 0x%08x, x27 = 0x%08x\n", + ucontext->uc_mcontext.regs[24], + ucontext->uc_mcontext.regs[25], + ucontext->uc_mcontext.regs[26], + ucontext->uc_mcontext.regs[27]); + fprintf_fd(fd, + "x28 = 0x%08x, x29 = 0x%08x\nx30 = 0x%08x\n", + ucontext->uc_mcontext.regs[28], + ucontext->uc_mcontext.regs[29], + ucontext->uc_mcontext.regs[30]); + fprintf_fd(fd, + "xr = 0x%08x, ip0 = 0x%08x\nip1 = 0x%08x, pr = 0x%08x\n", + ucontext->uc_mcontext.regs[8], /* Indirect result location register */ + ucontext->uc_mcontext.regs[16], /* Intra-procedure call scratch register 0 */ + ucontext->uc_mcontext.regs[17], /* Intra-procedure call scratch register 1 */ + ucontext->uc_mcontext.regs[18]); /* Platform register */ + fprintf_fd(fd, + "fp = 0x%08x, lr = 0x%08x\npc = 0x%08x, sp = 0x%08x\n", + ucontext->uc_mcontext.regs[29], /* Frame register */ + ucontext->uc_mcontext.regs[30], /* Procedure link register */ + ucontext->uc_mcontext.pc, /* Program counter */ + ucontext->uc_mcontext.sp); /* Stack pointer */ +}; diff --git a/src/sys-assert/sys-assert.c b/src/sys-assert/sys-assert.c index 0fb70de..e68c946 100644 --- a/src/sys-assert/sys-assert.c +++ b/src/sys-assert/sys-assert.c @@ -65,7 +65,11 @@ #define HEXA 16 #define PERM_LEN 5 +#ifdef ARCH_64 +#define ADDR_LEN 10 +#else #define ADDR_LEN 8 +#endif #define INFO_LEN 20 #define VALUE_LEN 24 #define TIME_MAX_LEN 64 @@ -103,7 +107,7 @@ static int trace_symbols(void *const *array, int size, struct addr_node *start, Elf32_Sym *symtab_entry; int i, cnt, file, ret; char *fname; - unsigned int addr, start_addr, offset_addr; + unsigned long addr, start_addr, offset_addr; unsigned int strtab_index = 0; unsigned int symtab_index = 0; int num_st = 0; @@ -120,8 +124,8 @@ static int trace_symbols(void *const *array, int size, struct addr_node *start, cnt, array[cnt], dlerror()); continue; } - start_addr = (unsigned int)get_start_addr(array[cnt], start); - addr = (unsigned int)array[cnt]; + start_addr = (unsigned long)get_start_addr(array[cnt], start); + addr = (unsigned long)array[cnt]; /* because of launchpad, * return value of dladdr when find executable is wrong. * so fix dli_fname here */ @@ -329,7 +333,7 @@ static struct addr_node *get_addr_list_from_maps(int fd) continue; perm[PERM_LEN - 1] = 0; /* rwxp */ -#ifdef ARM +#ifdef ARCH_ARM if ((perm[2] == 'x' && path[0] == '/') || (perm[1] == 'w' && path[0] != '/')) { #else @@ -390,9 +394,9 @@ static void print_node_to_file(struct addr_node *start, int fd) t_node = t_node->next; } else { fprintf_fd(fd, - "%08x %08x %s %s\n", - (unsigned int)t_node->startaddr, - (unsigned int)t_node->endaddr, + "%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; } diff --git a/src/sys-assert/sys-assert.h b/src/sys-assert/sys-assert.h index 7412f3c..f24feac 100755 --- a/src/sys-assert/sys-assert.h +++ b/src/sys-assert/sys-assert.h @@ -21,7 +21,7 @@ #include -#ifdef ARM +#ifdef ARCH_ARM #define BASE_LAUNCHPAD_ADDR 0x8000 #else #define BASE_LAUNCHPAD_ADDR 0x8048000 @@ -40,7 +40,7 @@ extern "C" { struct addr_node *next; }; -#ifdef ARM +#ifdef ARCH_ARM typedef struct layout { struct layout *fp; void *ret; diff --git a/src/sys-assert/x86/backtrace.c b/src/sys-assert/x86/backtrace.c index c2ab833..0453bbb 100644 --- a/src/sys-assert/x86/backtrace.c +++ b/src/sys-assert/x86/backtrace.c @@ -21,6 +21,7 @@ #include #include "sys-assert.h" #include "util.h" +#include "sys-assert-regs.h" int dump_callstack(void **callstack_addrs, int size, void *context, int retry) { diff --git a/src/sys-assert/x86/context.c b/src/sys-assert/x86/context.c index 20d37bc..5644d15 100644 --- a/src/sys-assert/x86/context.c +++ b/src/sys-assert/x86/context.c @@ -20,6 +20,7 @@ #include #include "sys-assert.h" #include "util.h" +#include "sys-assert-regs.h" #define CRASH_REGISTERINFO_TITLE "Register Information" diff --git a/src/sys-assert/x86/sys-assert-regs.h b/src/sys-assert/x86/sys-assert-regs.h new file mode 100644 index 0000000..f68baec --- /dev/null +++ b/src/sys-assert/x86/sys-assert-regs.h @@ -0,0 +1,99 @@ +/* + * SYS-ASSERT + * 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. + */ + +#ifndef __SYS_ASSERT_REGS_H__ +#define __SYS_ASSERT_REGS_H__ + +#include + +#ifndef REG_GS +#define REG_GS 0 +#endif + +#ifndef REG_FS +#define REG_FS 1 +#endif + +#ifndef REG_ES +#define REG_ES 2 +#endif + +#ifndef REG_DS +#define REG_DS 3 +#endif + +#ifndef REG_EDI +#define REG_EDI 4 +#endif + +#ifndef REG_ESI +#define REG_ESI 5 +#endif + +#ifndef REG_EBP +#define REG_EBP 6 +#endif + +#ifndef REG_ESP +#define REG_ESP 7 +#endif + +#ifndef REG_EBX +#define REG_EBX 8 +#endif + +#ifndef REG_EDX +#define REG_EDX 9 +#endif + +#ifndef REG_ECX +#define REG_ECX 10 +#endif + +#ifndef REG_EAX +#define REG_EAX 11 +#endif + +#ifndef REG_TRAPNO +#define REG_TRAPNO 12 +#endif + +#ifndef REG_ERR +#define REG_ERR 13 +#endif + +#ifndef REG_EIP +#define REG_EIP 14 +#endif + +#ifndef REG_CS +#define REG_CS 15 +#endif + +#ifndef REG_EFL +#define REG_EFL 16 +#endif + +#ifndef REG_UESP +#define REG_UESP 17 +#endif + +#ifndef REG_SS +#define REG_SS 18 +#endif + +#endif /* __SYS_ASSERT_REGS_H__ */ -- 2.7.4 From f31e04285b9a3e6938032969cf51e01dead6a9b6 Mon Sep 17 00:00:00 2001 From: taeyoung Date: Thu, 30 Jun 2016 19:13:45 +0900 Subject: [PATCH 04/16] common: set PATH env - PATH env need to be added since system PATH env can have weird paths. Change-Id: I68f82421cfef8d217d7ce7d999b9101496cd2b3e Signed-off-by: taeyoung --- src/crash-manager/crash-manager.sh.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/crash-manager/crash-manager.sh.in b/src/crash-manager/crash-manager.sh.in index 4ab6b58..e36c2b9 100644 --- a/src/crash-manager/crash-manager.sh.in +++ b/src/crash-manager/crash-manager.sh.in @@ -1,5 +1,7 @@ #!/bin/sh +PATH=/bin:/usr/bin:/sbin:/usr/sbin + exec >/dev/null 2>&1 PATH=/bin:/usr/bin -- 2.7.4 From 2abf2c6f8677459b482080271c8c12346b7e82c4 Mon Sep 17 00:00:00 2001 From: Kunhoon Baik Date: Mon, 4 Jul 2016 20:01:31 +0900 Subject: [PATCH 05/16] Remove SIGSEGV handling SIGSEGV (signal number - 11) may occur double crash when sys-assert tries to unwind backtrace. like that If the double crash is generated, it causes useless backtrace of corefile (double crashed memory dump) Thus, sys-assert does not handle SIGSEGV. Change-Id: I826ee2bab796fc87b2b4a003683315514af96339 --- src/sys-assert/sys-assert.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sys-assert/sys-assert.c b/src/sys-assert/sys-assert.c index e68c946..382e56e 100644 --- a/src/sys-assert/sys-assert.c +++ b/src/sys-assert/sys-assert.c @@ -88,7 +88,7 @@ int sig_to_handle[] = { SIGILL, SIGTRAP, SIGABRT, SIGBUS, - SIGFPE, SIGSEGV, SIGSTKFLT, SIGXCPU, SIGXFSZ, SIGSYS }; + SIGFPE, SIGSTKFLT, SIGXCPU, SIGXFSZ, SIGSYS }; #define NUM_SIG_TO_HANDLE \ ((int)(sizeof(sig_to_handle)/sizeof(sig_to_handle[0]))) -- 2.7.4 From 2c3b3b9d7e170de8e7da9fd8e9179933b6b41fc7 Mon Sep 17 00:00:00 2001 From: taeyoung Date: Tue, 5 Jul 2016 09:04:46 +0900 Subject: [PATCH 06/16] common: fix thread safe issues and uninitialized issues Change-Id: Iefa413c6505ea909e20a8220278c46a353ec5c9b Signed-off-by: taeyoung --- src/sys-assert/sys-assert.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sys-assert/sys-assert.c b/src/sys-assert/sys-assert.c index e68c946..dc76d64 100644 --- a/src/sys-assert/sys-assert.c +++ b/src/sys-assert/sys-assert.c @@ -102,7 +102,7 @@ extern int dump_callstack(void **callstack_addrs, int size, void *context, int r static int trace_symbols(void *const *array, int size, struct addr_node *start, int fd) { Dl_info info_funcs; - Elf32_Ehdr elf_h; + Elf32_Ehdr elf_h = {{0,},0,}; Elf32_Shdr *s_headers; Elf32_Sym *symtab_entry; int i, cnt, file, ret; @@ -595,7 +595,7 @@ void sighandler(int signum, siginfo_t *info, void *context) pid_t pid; pid_t tid; DIR *dir; - struct dirent *dentry; + struct dirent entry, *dentry; char timestr[TIME_MAX_LEN]; char processname[NAME_MAX] = {0,}; char exepath[PATH_LEN] = {0,}; @@ -614,7 +614,7 @@ void sighandler(int signum, siginfo_t *info, void *context) struct addr_node *head = NULL; /* for preventing recursion */ static int retry_count = 0; - struct sysinfo si; + struct sysinfo si = {0,}; if (retry_count > 1) { fprintf(stderr, "[sys-assert] recurcive called\n"); @@ -676,8 +676,8 @@ void sighandler(int signum, siginfo_t *info, void *context) /* create cs file */ if ((fd_cs = creat(filepath, FILE_PERMS)) < 0) { fprintf(stderr, - "[sys-assert]can't create %s. errno = %s\n", - filepath, strerror(errno)); + "[sys-assert]can't create %s. errno = %d\n", + filepath, errno); return; } @@ -772,7 +772,7 @@ void sighandler(int signum, siginfo_t *info, void *context) if (!dir) { fprintf(stderr, "[sys-assert]can't open %s\n", TASK_PATH); } else { - while ((dentry = readdir(dir)) != NULL) { + while (readdir_r(dir, &entry, &dentry) == 0) { if( strcmp(dentry->d_name, ".") == 0 || strcmp(dentry->d_name, "..") == 0) continue; -- 2.7.4 From a3198627f96ef31e3a85e3ea920eb22ee774ea7c Mon Sep 17 00:00:00 2001 From: taeyoung Date: Tue, 5 Jul 2016 19:38:41 +0900 Subject: [PATCH 07/16] crash: launch crash popup when crash is occurred - Crash popup is launched by the dbus method. The popup requires the full path of executable to show the appid to the user Change-Id: Ibeadfe792faabc61706738f24806f9d7386e6fb3 Signed-off-by: taeyoung --- packaging/crash-worker.spec | 14 ++++++++++++++ src/crash-manager/crash-manager.sh.in | 26 ++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/packaging/crash-worker.spec b/packaging/crash-worker.spec index e7a05a8..f4c0c46 100644 --- a/packaging/crash-worker.spec +++ b/packaging/crash-worker.spec @@ -1,4 +1,14 @@ %define sys_assert on +%define crash_popup off + +%if "%{?profile}" == "mobile" +%define crash_popup on +%endif + +%if "%{?profile}" == "wearable" +%define crash_popup on +%endif + Name: crash-worker Summary: Crash-manager @@ -23,6 +33,9 @@ Requires(post): tar Requires(post): gzip Requires: libebl Requires: libunwind +%if %{?crash_popup} == on +Requires: /usr/bin/dbus-send +%endif %description crash-manager @@ -62,6 +75,7 @@ export CFLAGS+=" -Werror" -DCRASH_TEMP=%{crash_temp} \ -DCRASH_PIPE_PATH=%{_libexecdir}/crash-pipe \ -DCRASH_STACK_PATH=%{_libexecdir}/crash-stack \ + -DCRASH_POPUP=%{crash_popup} \ -DSYS_ASSERT=%{sys_assert} make %{?jobs:-j%jobs} diff --git a/src/crash-manager/crash-manager.sh.in b/src/crash-manager/crash-manager.sh.in index e36c2b9..540f446 100644 --- a/src/crash-manager/crash-manager.sh.in +++ b/src/crash-manager/crash-manager.sh.in @@ -44,6 +44,32 @@ else @CRASH_PIPE_PATH@ --report "$@" > "$info_path" @CRASH_STACK_PATH@ --pid "$pid" >> "$info_path" fi + +if [ "@CRASH_POPUP@" = "on" ] +then +#Find the full path of executable. The path is used to find appid in the crash-popup + exepath=" " + found=0 + while read line + do + if [ $found -eq 1 ] + then + exepath=$(echo $line | sed "s/0: //") + break + fi + + if [ "$line" = "Cmdline:" ] + then + found=1 + fi + + done < $info_path + +#Call dbus method to launch the crash-popup + /usr/bin/dbus-send --system --type=method_call --print-reply --reply-timeout=120000 --dest=org.tizen.system.popup /Org/Tizen/System/Popup/Crash org.tizen.system.popup.Crash.PopupLaunch dict:string:string:"_SYSPOPUP_CONTENT_","crash","_PROCESS_NAME_","${cmd}","_EXEPATH_","${exepath}" + +fi + dump_systemstate -d -k -f "$log_path" || true tar czf "${temp_dir}/report.tar.gz" -C "$temp_dir" "$name" -- 2.7.4 From 069a4d7b6a1638b15b5dda6ed9925ab503f75467 Mon Sep 17 00:00:00 2001 From: Kunhoon Baik Date: Sat, 9 Jul 2016 11:23:55 +0900 Subject: [PATCH 08/16] Applying Tab indentation in crash-stack source code Change-Id: If20003e278ec7171a9a7720059b2d3552c3155e1 --- src/crash-stack/crash-stack-arm.c | 376 ++++++------ src/crash-stack/crash-stack-libelf.c | 20 +- src/crash-stack/crash-stack.c | 1076 +++++++++++++++++----------------- src/crash-stack/crash-stack.h | 20 +- 4 files changed, 746 insertions(+), 746 deletions(-) diff --git a/src/crash-stack/crash-stack-arm.c b/src/crash-stack/crash-stack-arm.c index 4d21661..4edf54f 100644 --- a/src/crash-stack/crash-stack-arm.c +++ b/src/crash-stack/crash-stack-arm.c @@ -11,11 +11,11 @@ static pid_t g_pid = 0; struct Regs { - Dwarf_Addr regs[REGS_REGULAR_NUM]; - Dwarf_Addr sp; - Dwarf_Addr lr; - Dwarf_Addr pc; - Dwarf_Addr spsr; + Dwarf_Addr regs[REGS_REGULAR_NUM]; + Dwarf_Addr sp; + Dwarf_Addr lr; + Dwarf_Addr pc; + Dwarf_Addr spsr; }; typedef struct Regs Regs; @@ -23,219 +23,219 @@ static Regs g_regs; void *get_place_for_register_value (const char *regname, int regnum) { - if (strcmp (regname, "pc") == 0 || REG_PC == regnum) - { - return &g_regs.pc; - } - else if (strcmp (regname, "sp") == 0 || REG_SP == regnum) - { - return &g_regs.sp; - } - else if (strcmp (regname, "lr") == 0 || REG_LR == regnum) - { - return &g_regs.lr; - } - else if (strcmp (regname, "spsr") == 0 || REG_SPSR == regnum) - { - return &g_regs.spsr; - } - else if (regnum < REGS_REGULAR_NUM) - { - return &g_regs.regs[regnum]; - } - return NULL; + if (strcmp (regname, "pc") == 0 || REG_PC == regnum) + { + return &g_regs.pc; + } + else if (strcmp (regname, "sp") == 0 || REG_SP == regnum) + { + return &g_regs.sp; + } + else if (strcmp (regname, "lr") == 0 || REG_LR == regnum) + { + return &g_regs.lr; + } + else if (strcmp (regname, "spsr") == 0 || REG_SPSR == regnum) + { + return &g_regs.spsr; + } + else if (regnum < REGS_REGULAR_NUM) + { + return &g_regs.regs[regnum]; + } + return NULL; } static Boolean report (void *data, Int32 address) { - Callstack *callstack = (Callstack *)(data); - callstack->tab[callstack->elems++] = address; + Callstack *callstack = (Callstack *)(data); + callstack->tab[callstack->elems++] = address; - return callstack->elems < MAX_CALLSTACK_LEN ? TRUE : FALSE; + return callstack->elems < MAX_CALLSTACK_LEN ? TRUE : FALSE; } Boolean readT (Int32 a, void *v, size_t size) { - Dwfl_Module *module = 0; - Elf_Data *data = NULL; - - int segment = dwfl_addrsegment (g_dwfl, a, &module); - - if (module != NULL) - { - Dwarf_Addr start; - dwfl_module_info (module, NULL, &start, NULL, NULL, NULL, NULL, NULL); - - GElf_Addr bias; - Elf *elf = dwfl_module_getelf (module, &bias); - - data = elf_getdata_rawchunk (elf, a-start, size, ELF_T_BYTE); - } - if (NULL == data && segment != -1) - { - // get data from segment - GElf_Phdr mem; - GElf_Phdr *phdr = gelf_getphdr (g_core, segment, &mem); - Dwarf_Addr offset_in_segment = a - phdr->p_vaddr; - if (offset_in_segment < phdr->p_filesz) - { - Dwarf_Addr offset_in_file = phdr->p_offset + offset_in_segment; - - data = elf_getdata_rawchunk (g_core, offset_in_file, size, ELF_T_BYTE); - } - } - - if (NULL == data && module != NULL) - { - const char *name = dwfl_module_info (module, NULL, NULL, NULL, NULL, NULL, NULL, NULL); - if (name != NULL && name[0] == '[') - { - int i; - // get module from mappings - for (i = 0; i < g_mappings->elems; i++) - { - if (g_mappings->tab[i].m_start <= a && a < g_mappings->tab[i].m_end) - { - // compute offset relative to the start of the mapping - Int32 offset = a - g_mappings->tab[i].m_start; - // read from the file, but also account file offset - data = elf_getdata_rawchunk (g_mappings->tab[i].m_elf, - offset + g_mappings->tab[i].m_offset, size, ELF_T_BYTE); - break; - } - } - } - } - - if (data != NULL) - { - memcpy (v, data->d_buf, size); - return TRUE; - } - - /* Still no data, but we have a process - read memory with ptrace */ - if (NULL == data && g_pid > 1) - { - long val = ptrace (PTRACE_PEEKDATA, g_pid, a, NULL); - memcpy (v, &val, size); - return TRUE; - } - - return FALSE; + Dwfl_Module *module = 0; + Elf_Data *data = NULL; + + int segment = dwfl_addrsegment (g_dwfl, a, &module); + + if (module != NULL) + { + Dwarf_Addr start; + dwfl_module_info (module, NULL, &start, NULL, NULL, NULL, NULL, NULL); + + GElf_Addr bias; + Elf *elf = dwfl_module_getelf (module, &bias); + + data = elf_getdata_rawchunk (elf, a-start, size, ELF_T_BYTE); + } + if (NULL == data && segment != -1) + { + // get data from segment + GElf_Phdr mem; + GElf_Phdr *phdr = gelf_getphdr (g_core, segment, &mem); + Dwarf_Addr offset_in_segment = a - phdr->p_vaddr; + if (offset_in_segment < phdr->p_filesz) + { + Dwarf_Addr offset_in_file = phdr->p_offset + offset_in_segment; + + data = elf_getdata_rawchunk (g_core, offset_in_file, size, ELF_T_BYTE); + } + } + + if (NULL == data && module != NULL) + { + const char *name = dwfl_module_info (module, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + if (name != NULL && name[0] == '[') + { + int i; + // get module from mappings + for (i = 0; i < g_mappings->elems; i++) + { + if (g_mappings->tab[i].m_start <= a && a < g_mappings->tab[i].m_end) + { + // compute offset relative to the start of the mapping + Int32 offset = a - g_mappings->tab[i].m_start; + // read from the file, but also account file offset + data = elf_getdata_rawchunk (g_mappings->tab[i].m_elf, + offset + g_mappings->tab[i].m_offset, size, ELF_T_BYTE); + break; + } + } + } + } + + if (data != NULL) + { + memcpy (v, data->d_buf, size); + return TRUE; + } + + /* Still no data, but we have a process - read memory with ptrace */ + if (NULL == data && g_pid > 1) + { + long val = ptrace (PTRACE_PEEKDATA, g_pid, a, NULL); + memcpy (v, &val, size); + return TRUE; + } + + return FALSE; } static Boolean readW (Int32 a, Int32 *v) { - return readT(a,v,sizeof(*v)); + return readT(a,v,sizeof(*v)); } static Boolean readH (Int32 a, Int16 *v) { - return readT(a,v,sizeof(*v)); + return readT(a,v,sizeof(*v)); } static Boolean readB (Int32 a, Int8 *v) { - return readT(a,v,sizeof(*v)); + return readT(a,v,sizeof(*v)); } static Int32 getProloguePC (Int32 current_pc) { - Int32 result = 0; - Dwfl_Module *module = dwfl_addrmodule (g_dwfl, current_pc); - if (module) - { -// GElf_Off offset; - GElf_Sym sym; -// dwfl_module_addrinfo (module, current_pc, &offset, &sym, NULL, NULL, NULL); - dwfl_module_addrsym (module, current_pc, &sym, NULL); -// result = current_pc - offset; - result = sym.st_value; - } - if (0 == result) - { - int i; - for (i=0; i < g_mappings->elems; i++) - { - if (g_mappings->tab[i].m_start <= current_pc && current_pc < g_mappings->tab[i].m_end) - { - /* go through symbols to find the nearest */ - Elf_Scn *scn = NULL; - Elf *elf = g_mappings->tab[i].m_elf; - 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 = current_pc; - if (shdr->sh_type == SHT_DYNSYM) - address_offset -= g_mappings->tab[i].m_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) - { - return sym->st_value; - } - } - } - } - } - } - } - } - return result; + Int32 result = 0; + Dwfl_Module *module = dwfl_addrmodule (g_dwfl, current_pc); + if (module) + { + // GElf_Off offset; + GElf_Sym sym; + // dwfl_module_addrinfo (module, current_pc, &offset, &sym, NULL, NULL, NULL); + dwfl_module_addrsym (module, current_pc, &sym, NULL); + // result = current_pc - offset; + result = sym.st_value; + } + if (0 == result) + { + int i; + for (i=0; i < g_mappings->elems; i++) + { + if (g_mappings->tab[i].m_start <= current_pc && current_pc < g_mappings->tab[i].m_end) + { + /* go through symbols to find the nearest */ + Elf_Scn *scn = NULL; + Elf *elf = g_mappings->tab[i].m_elf; + 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 = current_pc; + if (shdr->sh_type == SHT_DYNSYM) + address_offset -= g_mappings->tab[i].m_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) + { + return sym->st_value; + } + } + } + } + } + } + } + } + return result; } void create_crash_stack (Dwfl *dwfl, Elf *core, pid_t pid, Mappings *mappings, Callstack *callstack) { - UnwindCallbacks callbacks = - { - report, - readW, - readH, - readB, - getProloguePC + UnwindCallbacks callbacks = + { + report, + readW, + readH, + readB, + getProloguePC #ifdef UNW_DEBUG - , - printf + , + printf #endif - }; - UnwState state; - - g_dwfl = dwfl; - g_core = core; - g_mappings = mappings; - g_pid = pid; - - callstack->tab[0] = g_regs.pc; - callstack->elems = 1; - - UnwInitState (&state, &callbacks, callstack, g_regs.pc, g_regs.sp); - int i; - for (i = 0; i < REGS_REGULAR_NUM; i++) - { - state.regData[i].v = g_regs.regs[i]; - state.regData[i].o = REG_VAL_FROM_CONST; - } - state.regData[REG_LR].v = g_regs.lr; - state.regData[REG_LR].o = REG_VAL_FROM_STACK; - state.regData[REG_SPSR].v = g_regs.spsr; - state.regData[REG_SPSR].o = REG_VAL_FROM_CONST; - - if (UnwIsAddrThumb (g_regs.pc, g_regs.spsr)) - UnwStartThumb (&state); - else - UnwStartArm (&state); + }; + UnwState state; + + g_dwfl = dwfl; + g_core = core; + g_mappings = mappings; + g_pid = pid; + + callstack->tab[0] = g_regs.pc; + callstack->elems = 1; + + UnwInitState (&state, &callbacks, callstack, g_regs.pc, g_regs.sp); + int i; + for (i = 0; i < REGS_REGULAR_NUM; i++) + { + state.regData[i].v = g_regs.regs[i]; + state.regData[i].o = REG_VAL_FROM_CONST; + } + state.regData[REG_LR].v = g_regs.lr; + state.regData[REG_LR].o = REG_VAL_FROM_STACK; + state.regData[REG_SPSR].v = g_regs.spsr; + state.regData[REG_SPSR].o = REG_VAL_FROM_CONST; + + if (UnwIsAddrThumb (g_regs.pc, g_regs.spsr)) + UnwStartThumb (&state); + else + UnwStartArm (&state); } diff --git a/src/crash-stack/crash-stack-libelf.c b/src/crash-stack/crash-stack-libelf.c index c8c8773..44fec1c 100644 --- a/src/crash-stack/crash-stack-libelf.c +++ b/src/crash-stack/crash-stack-libelf.c @@ -5,30 +5,30 @@ #if _ELFUTILS_PREREQ(0,158) 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; - return callstack->elems < MAX_CALLSTACK_LEN ? DWARF_CB_OK : DWARF_CB_ABORT; + Callstack *callstack = (Callstack*)arg; + Dwarf_Addr address; + dwfl_frame_pc (state, &address, NULL); + callstack->tab[callstack->elems++] = address; + return callstack->elems < MAX_CALLSTACK_LEN ? DWARF_CB_OK : DWARF_CB_ABORT; } static int thread_callback (Dwfl_Thread *thread, void *thread_arg) { - dwfl_thread_getframes (thread, frame_callback, thread_arg); - return DWARF_CB_ABORT; + dwfl_thread_getframes (thread, frame_callback, thread_arg); + return DWARF_CB_ABORT; } #endif void *get_place_for_register_value (const char *regname, int regnum) { - return 0; + return 0; } void create_crash_stack (Dwfl *dwfl, Elf *core, pid_t pid, Mappings *mappings, Callstack *callstack) { - callstack->elems = 0; + callstack->elems = 0; #if _ELFUTILS_PREREQ(0,158) - dwfl_getthreads (dwfl, thread_callback, callstack); + dwfl_getthreads (dwfl, thread_callback, callstack); #endif } diff --git a/src/crash-stack/crash-stack.c b/src/crash-stack/crash-stack.c index a9e5b2d..cbea4f7 100644 --- a/src/crash-stack/crash-stack.c +++ b/src/crash-stack/crash-stack.c @@ -22,605 +22,605 @@ static FILE *outputfile = NULL; static FILE *errfile = NULL; enum { - OPT_PID, - OPT_OUTPUTFILE, - OPT_ERRFILE + 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 } + { "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); + size_t *length, int *status); static int module_callback (Dwfl_Module *module, void **userdata, - const char *name, Dwarf_Addr address, - void *arg) + const char *name, Dwarf_Addr address, + void *arg) { - if (name != NULL && name[0] == '[') - { - /* libdwfl couldn't get the module file - we will get it later from notes */ - Mappings *mappings = arg; - if (mappings->elems < MAX_MAPPINGS_NUM) - { - size_t elems = mappings->elems; - mappings->tab[elems].m_start = address; - mappings->tab[elems].m_end = 0; - mappings->tab[elems].m_offset = 0; - mappings->tab[elems].m_name = NULL; - mappings->tab[elems].m_fd = -1; - mappings->tab[elems].m_elf = 0; - mappings->elems++; - } - } -/* fprintf(errfile, "Got module %s @0x%llx\n", name, (long long)address);*/ - return DWARF_CB_OK; + if (name != NULL && name[0] == '[') + { + /* libdwfl couldn't get the module file - we will get it later from notes */ + Mappings *mappings = arg; + if (mappings->elems < MAX_MAPPINGS_NUM) + { + size_t elems = mappings->elems; + mappings->tab[elems].m_start = address; + mappings->tab[elems].m_end = 0; + mappings->tab[elems].m_offset = 0; + mappings->tab[elems].m_name = NULL; + mappings->tab[elems].m_fd = -1; + mappings->tab[elems].m_elf = 0; + mappings->elems++; + } + } + /* fprintf(errfile, "Got module %s @0x%llx\n", name, (long long)address);*/ + return DWARF_CB_OK; } static void getvalue (Elf *core, const void *from, size_t size, void *to) { - Elf_Data out = - { - .d_buf = to, - .d_type = size == 32 ? ELF_T_WORD : ELF_T_XWORD, - .d_version = EV_CURRENT, - .d_size = size/8, - .d_off = 0, - .d_align = 0 - }; - Elf_Data in = - { - .d_buf = (void*)(from), - .d_type = out.d_type, - .d_version = out.d_version, - .d_size = out.d_size, - .d_off = 0, - .d_align = 0 - }; - Elf_Data *data; - if (gelf_getclass (core) == ELFCLASS32) - data = elf32_xlatetom (&out, &in, elf_getident (core, NULL)[EI_DATA]); - else - data = elf64_xlatetom (&out, &in, elf_getident (core, NULL)[EI_DATA]); - if (data == NULL) - fprintf (errfile, "failed to get value from core file\n"); + Elf_Data out = + { + .d_buf = to, + .d_type = size == 32 ? ELF_T_WORD : ELF_T_XWORD, + .d_version = EV_CURRENT, + .d_size = size/8, + .d_off = 0, + .d_align = 0 + }; + Elf_Data in = + { + .d_buf = (void*)(from), + .d_type = out.d_type, + .d_version = out.d_version, + .d_size = out.d_size, + .d_off = 0, + .d_align = 0 + }; + Elf_Data *data; + if (gelf_getclass (core) == ELFCLASS32) + data = elf32_xlatetom (&out, &in, elf_getident (core, NULL)[EI_DATA]); + else + data = elf64_xlatetom (&out, &in, elf_getident (core, NULL)[EI_DATA]); + if (data == NULL) + fprintf (errfile, "failed to get value from core file\n"); } static void updateMapping (Mappings *mappings, uint64_t mapping_start, uint64_t mapping_end, - uint64_t offset, const char *name) + uint64_t offset, const char *name) { - int i; - for (i = 0; i < mappings->elems; i++) - { - if (mappings->tab[i].m_start == mapping_start) - { - mappings->tab[i].m_end = mapping_end; - mappings->tab[i].m_name = name; - mappings->tab[i].m_offset = offset; - mappings->tab[i].m_fd = open(name, O_RDONLY); - mappings->tab[i].m_elf = elf_begin(mappings->tab[i].m_fd, ELF_C_READ_MMAP, NULL); - return; - } - } + int i; + for (i = 0; i < mappings->elems; i++) + { + if (mappings->tab[i].m_start == mapping_start) + { + mappings->tab[i].m_end = mapping_end; + mappings->tab[i].m_name = name; + mappings->tab[i].m_offset = offset; + mappings->tab[i].m_fd = open(name, O_RDONLY); + mappings->tab[i].m_elf = elf_begin(mappings->tab[i].m_fd, ELF_C_READ_MMAP, NULL); + return; + } + } } static void parse_note_file (Elf *elf, const char *desc, uint64_t *values_cnt, uint64_t *page_size, - size_t *addr_size, const char **values, const char **filenames) + size_t *addr_size, const char **values, const char **filenames) { - *addr_size = gelf_fsize (elf, ELF_T_ADDR, 1, EV_CURRENT); - getvalue(elf, desc, *addr_size*8, values_cnt); - getvalue(elf, desc + *addr_size, *addr_size*8, page_size); - /* First: triplets of - * count = values_cnt - * Then the names of files. - */ - *values = desc + 2 * *addr_size; - *filenames = *values + 3 * *addr_size * *values_cnt; + *addr_size = gelf_fsize (elf, ELF_T_ADDR, 1, EV_CURRENT); + getvalue(elf, desc, *addr_size*8, values_cnt); + getvalue(elf, desc + *addr_size, *addr_size*8, page_size); + /* First: triplets of + * count = values_cnt + * Then the names of files. + */ + *values = desc + 2 * *addr_size; + *filenames = *values + 3 * *addr_size * *values_cnt; } static void get_mapping_item(Elf *elf, size_t addr_size, const void *item, - uint64_t *mapping_start, uint64_t *mapping_end, uint64_t *offset_in_pages) + uint64_t *mapping_start, uint64_t *mapping_end, uint64_t *offset_in_pages) { - getvalue(elf, item, addr_size*8, mapping_start); - getvalue(elf, item + addr_size, addr_size*8, mapping_end); - getvalue(elf, item + 2 * addr_size, addr_size*8, offset_in_pages); + getvalue(elf, item, addr_size*8, mapping_start); + getvalue(elf, item + addr_size, addr_size*8, mapping_end); + getvalue(elf, item + 2 * addr_size, addr_size*8, offset_in_pages); } static char *try_symbol_from_elfs (Elf *core, Elf_Data *notes, uintptr_t address, - const char **module_name) + const char **module_name) { - 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; - - 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; - - elf = elf_begin (fd, ELF_C_READ_MMAP, NULL); - - if (NULL == elf) { - close(fd); - return NULL; - } - - 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_end(elf); - close(fd); - return symbol; - } - - filenames += strlen(filenames)+1; - } - } - pos = new_pos; - } - - return NULL; + 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; + + 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; + + elf = elf_begin (fd, ELF_C_READ_MMAP, NULL); + + if (NULL == elf) { + close(fd); + return NULL; + } + + 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_end(elf); + close(fd); + return symbol; + } + + filenames += strlen(filenames)+1; + } + } + pos = new_pos; + } + + return NULL; } static Dwfl *open_dwfl_with_pid (pid_t pid) { - 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); - return NULL; - } - - ptrace (PTRACE_INTERRUPT, pid, 0, 0); - - stopped_pid = waitpid(pid, &status, 0); - if (stopped_pid == -1 || stopped_pid != pid || !WIFSTOPPED(status)) - { - fprintf(errfile, "waitpid failed: %m, stopped_pid=%d, status=%d\n", stopped_pid, status); - return NULL; - } - - 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; - } + 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); + return NULL; + } + + ptrace (PTRACE_INTERRUPT, pid, 0, 0); + + stopped_pid = waitpid(pid, &status, 0); + if (stopped_pid == -1 || stopped_pid != pid || !WIFSTOPPED(status)) + { + fprintf(errfile, "waitpid failed: %m, stopped_pid=%d, status=%d\n", stopped_pid, status); + return NULL; + } + + 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; + } #if _ELFUTILS_PREREQ(0,158) - if (dwfl_linux_proc_attach (dwfl, pid, true) < 0) - { - fprintf (errfile, "process %d : dwfl attach failed (%s)\n", pid, dwfl_errmsg(-1)); - dwfl_end (dwfl); - return NULL; - } + if (dwfl_linux_proc_attach (dwfl, pid, true) < 0) + { + fprintf (errfile, "process %d : dwfl attach failed (%s)\n", pid, dwfl_errmsg(-1)); + dwfl_end (dwfl); + return NULL; + } #endif - return dwfl; + return dwfl; } 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, - .section_address = NULL, - .debuginfo_path = NULL - }; - - Dwfl *dwfl = dwfl_begin (&core_callbacks); - if (dwfl == NULL) - { - fprintf (errfile, "%s : Can't start dwfl (%s)\n", core_file_name, dwfl_errmsg(-1)); - return NULL; - } + static const Dwfl_Callbacks core_callbacks = + { + .find_elf = dwfl_build_id_find_elf, + .find_debuginfo = dwfl_standard_find_debuginfo, + .section_address = NULL, + .debuginfo_path = NULL + }; + + Dwfl *dwfl = dwfl_begin (&core_callbacks); + if (dwfl == NULL) + { + 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, NULL) < 0) + if (dwfl_core_file_report (dwfl, core, NULL) < 0) #else - if (dwfl_core_file_report (dwfl, core) < 0) + if (dwfl_core_file_report (dwfl, core) < 0) #endif - { - fprintf (errfile, "%s : dwfl report failed (%s)\n", core_file_name, dwfl_errmsg(-1)); - dwfl_end (dwfl); - return NULL; - } + { + 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 (errfile, "%s : dwfl attach failed (%s)\n", core_file_name, dwfl_errmsg(-1)); - dwfl_end (dwfl); - return NULL; - } + if (dwfl_core_file_attach (dwfl, core) < 0) + { + fprintf (errfile, "%s : dwfl attach failed (%s)\n", core_file_name, dwfl_errmsg(-1)); + dwfl_end (dwfl); + return NULL; + } #endif - return dwfl; + return dwfl; } static int get_registers_ptrace (pid_t pid) { - struct iovec data; - uintptr_t regbuf[20]; - - data.iov_base = regbuf; - data.iov_len = sizeof (regbuf); - - 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; + struct iovec data; + uintptr_t regbuf[20]; + + data.iov_base = regbuf; + data.iov_len = sizeof (regbuf); + + 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 (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 (errfile, "%s : error getting notes (%s)\n", core_file_name, dwfl_errmsg(-1)); - return NULL; - } - - Ebl *ebl = ebl_openbackend (core); - if (ebl == NULL) - { - fprintf (errfile, "%s : Can't initialize ebl\n", core_file_name); - return NULL; - } - - GElf_Nhdr nhdr; - size_t name_pos; - size_t desc_pos; - size_t pos = 0; - size_t new_pos = 0; - int got_regs = 0; - /* registers should be in the first note! */ - while ((new_pos = gelf_getnote (notes, pos, &nhdr, &name_pos, &desc_pos)) > 0) - { - if (nhdr.n_type == NT_PRSTATUS && !got_regs) - { - GElf_Word regs_offset; - size_t nregloc; - const Ebl_Register_Location *reglocs; - size_t nitems; - const Ebl_Core_Item *items; - - got_regs = 1; - - if (0 == ebl_core_note (ebl, &nhdr, "CORE", ®s_offset, &nregloc, - ®locs, &nitems, &items)) - { - 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; - 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++) - { - 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); - if (ret < 0) - { - 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); - - if (place_for_reg_value != NULL) - getvalue (core, register_location, bits, place_for_reg_value); - - register_location += bits / 8 + reglocs[i].pad; - } - } - } - else 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; - /* First: triplets of - * count = values_cnt - * Then the names of files. - */ - 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); - updateMapping (mappings, mapping_start, mapping_end, - offset_in_pages*page_size, filenames); - filenames += strlen (filenames)+1; - } - } - pos = new_pos; - } - ebl_closebackend (ebl); - return notes; + GElf_Phdr mem; + GElf_Phdr *phdr = gelf_getphdr (core, 0, &mem); + + if (phdr == NULL || phdr->p_type != PT_NOTE) + { + 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 (errfile, "%s : error getting notes (%s)\n", core_file_name, dwfl_errmsg(-1)); + return NULL; + } + + Ebl *ebl = ebl_openbackend (core); + if (ebl == NULL) + { + fprintf (errfile, "%s : Can't initialize ebl\n", core_file_name); + return NULL; + } + + GElf_Nhdr nhdr; + size_t name_pos; + size_t desc_pos; + size_t pos = 0; + size_t new_pos = 0; + int got_regs = 0; + /* registers should be in the first note! */ + while ((new_pos = gelf_getnote (notes, pos, &nhdr, &name_pos, &desc_pos)) > 0) + { + if (nhdr.n_type == NT_PRSTATUS && !got_regs) + { + GElf_Word regs_offset; + size_t nregloc; + const Ebl_Register_Location *reglocs; + size_t nitems; + const Ebl_Core_Item *items; + + got_regs = 1; + + if (0 == ebl_core_note (ebl, &nhdr, "CORE", ®s_offset, &nregloc, + ®locs, &nitems, &items)) + { + 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; + 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++) + { + 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); + if (ret < 0) + { + 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); + + if (place_for_reg_value != NULL) + getvalue (core, register_location, bits, place_for_reg_value); + + register_location += bits / 8 + reglocs[i].pad; + } + } + } + else 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; + /* First: triplets of + * count = values_cnt + * Then the names of files. + */ + 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); + updateMapping (mappings, mapping_start, mapping_end, + offset_in_pages*page_size, filenames); + filenames += strlen (filenames)+1; + } + } + pos = new_pos; + } + ebl_closebackend (ebl); + return notes; } static void printCallstack (Callstack *callstack, Dwfl *dwfl, Elf *core, pid_t pid, - Elf_Data *notes) + 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; - for (it = 0; it != callstack->elems; ++it) - { - if (sizeof (callstack->tab[0]) > 4) - fprintf (outputfile, "0x%016llx: ", (long long)callstack->tab[it]); - else - 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 *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); - } - 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, ""); - - if (demangled_symbol != 0) - free (demangled_symbol); - - if (symbol_from_elf != 0) - free (symbol_from_elf); - - fprintf (outputfile, " from %s\n", fname != NULL ? fname : module_name); - } - else - { - fprintf (outputfile, "unknown function\n"); - } - } + fprintf (outputfile, "Call stack"); + if (pid > 1) fprintf (outputfile, " for PID %d", pid); + fprintf (outputfile, ":\n"); + + 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]); + else + 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 *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); + } + 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, ""); + + if (demangled_symbol != 0) + free (demangled_symbol); + + if (symbol_from_elf != 0) + free (symbol_from_elf); + + fprintf (outputfile, " from %s\n", fname != NULL ? fname : module_name); + } + else + { + 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 | ]\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); - if (NULL != core) elf_end (core); - if (-1 != core_fd) close (core_fd); - - return 0; + 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 | ]\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); + if (NULL != core) elf_end (core); + if (-1 != core_fd) close (core_fd); + + return 0; } diff --git a/src/crash-stack/crash-stack.h b/src/crash-stack/crash-stack.h index 251ca37..57198ab 100644 --- a/src/crash-stack/crash-stack.h +++ b/src/crash-stack/crash-stack.h @@ -9,26 +9,26 @@ typedef struct Callstack { - uintptr_t tab[MAX_CALLSTACK_LEN]; - size_t elems; + uintptr_t tab[MAX_CALLSTACK_LEN]; + size_t elems; } Callstack; typedef struct Mapping { - uintptr_t m_start; - uintptr_t m_end; - uintptr_t m_offset; - const char *m_name; - int m_fd; - Elf *m_elf; + uintptr_t m_start; + uintptr_t m_end; + uintptr_t m_offset; + const char *m_name; + int m_fd; + Elf *m_elf; } Mapping; #define MAX_MAPPINGS_NUM 1000 typedef struct Mappings { - Mapping tab[MAX_MAPPINGS_NUM]; - size_t elems; + Mapping tab[MAX_MAPPINGS_NUM]; + size_t elems; } Mappings; void *get_place_for_register_value (const char *regname, int regnum); -- 2.7.4 From 8abe6f64a90d33e2289762e4001f38a58791e46e Mon Sep 17 00:00:00 2001 From: Kunhoon Baik Date: Sat, 9 Jul 2016 11:30:19 +0900 Subject: [PATCH 09/16] Check phdr for Referencing phdr Change-Id: I63f07a7506d556de3d4c576fd141a007a34ceb0d --- src/crash-stack/crash-stack-arm.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/crash-stack/crash-stack-arm.c b/src/crash-stack/crash-stack-arm.c index 4edf54f..e1d6904 100644 --- a/src/crash-stack/crash-stack-arm.c +++ b/src/crash-stack/crash-stack-arm.c @@ -75,13 +75,19 @@ Boolean readT (Int32 a, void *v, size_t size) { // get data from segment GElf_Phdr mem; - GElf_Phdr *phdr = gelf_getphdr (g_core, segment, &mem); - Dwarf_Addr offset_in_segment = a - phdr->p_vaddr; - if (offset_in_segment < phdr->p_filesz) + GElf_Phdr *phdr; + Dwarf_Addr offset_in_segment; + + phdr = gelf_getphdr (g_core, segment, &mem); + if (phdr != NULL) { - Dwarf_Addr offset_in_file = phdr->p_offset + offset_in_segment; + offset_in_segment = a - phdr->p_vaddr; + if (offset_in_segment < phdr->p_filesz) + { + Dwarf_Addr offset_in_file = phdr->p_offset + offset_in_segment; - data = elf_getdata_rawchunk (g_core, offset_in_file, size, ELF_T_BYTE); + data = elf_getdata_rawchunk (g_core, offset_in_file, size, ELF_T_BYTE); + } } } -- 2.7.4 From 514f5a2c5892b1bb5973d638557d027d0387cf65 Mon Sep 17 00:00:00 2001 From: taeyoung Date: Tue, 12 Jul 2016 17:01:51 +0900 Subject: [PATCH 10/16] crash-pipe: add oom_score_adj information for the report - oom_score_adj information is added to the crash report - oom_score_adj is used in resourced as a criteria of selecting victims to increase free memory space Change-Id: I749c0bfb789d3f08cdb7f11288cb9988ddb99e92 Signed-off-by: taeyoung --- src/crash-pipe/crash-pipe.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/crash-pipe/crash-pipe.c b/src/crash-pipe/crash-pipe.c index e0016b7..e85ce32 100644 --- a/src/crash-pipe/crash-pipe.c +++ b/src/crash-pipe/crash-pipe.c @@ -131,6 +131,7 @@ static void report(int argc, char *argv[]) { "cgroup", "CGroup", 0 }, { "attr/current", "MAC Label", 0 }, { "oom_score", "OOM Score", 0 }, + { "oom_score_adj", "OOM Score Adj", 0 }, { "cmdline", "Cmdline", 1 }, { "environ", "Environment", 1 } }; -- 2.7.4 From 0b5f35d0b25269d92163bec2b44fecd5ab894fab Mon Sep 17 00:00:00 2001 From: taeyoung Date: Wed, 13 Jul 2016 11:37:28 +0900 Subject: [PATCH 11/16] popup: disable crash popup - For the Mobile and Wearable profile, crash popup is disabled Change-Id: I547aa1e975e0b4083414d661de2ddb705e45baf9 Signed-off-by: taeyoung --- packaging/crash-worker.spec | 8 -------- 1 file changed, 8 deletions(-) diff --git a/packaging/crash-worker.spec b/packaging/crash-worker.spec index f4c0c46..90be22e 100644 --- a/packaging/crash-worker.spec +++ b/packaging/crash-worker.spec @@ -1,14 +1,6 @@ %define sys_assert on %define crash_popup off -%if "%{?profile}" == "mobile" -%define crash_popup on -%endif - -%if "%{?profile}" == "wearable" -%define crash_popup on -%endif - Name: crash-worker Summary: Crash-manager -- 2.7.4 From 70cd339a94c42bee1d23d89a44081611a1fbd65c Mon Sep 17 00:00:00 2001 From: taeyoung Date: Wed, 13 Jul 2016 13:23:31 +0900 Subject: [PATCH 12/16] Revert "popup: disable crash popup" This reverts commit 0b5f35d0b25269d92163bec2b44fecd5ab894fab. Change-Id: I230b83937b455731031073bda1cff9102c5233c7 Signed-off-by: taeyoung --- packaging/crash-worker.spec | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packaging/crash-worker.spec b/packaging/crash-worker.spec index 90be22e..f4c0c46 100644 --- a/packaging/crash-worker.spec +++ b/packaging/crash-worker.spec @@ -1,6 +1,14 @@ %define sys_assert on %define crash_popup off +%if "%{?profile}" == "mobile" +%define crash_popup on +%endif + +%if "%{?profile}" == "wearable" +%define crash_popup on +%endif + Name: crash-worker Summary: Crash-manager -- 2.7.4 From c8d1f7b1c303835e9da34320caafbe0e49018d16 Mon Sep 17 00:00:00 2001 From: Lukasz Skalski Date: Tue, 26 Jul 2016 14:08:57 +0200 Subject: [PATCH 13/16] crash-worker refactoring to meet Tizen coding style Change-Id: I8a03903fad20656b61f753689041e478a4db8a5e --- src/crash-pipe/crash-pipe.c | 319 ++++++++++++++-------------- src/crash-stack/crash-stack-arm.c | 147 +++++-------- src/crash-stack/crash-stack-libelf.c | 18 +- src/crash-stack/crash-stack.c | 366 ++++++++++++++------------------ src/crash-stack/crash-stack.h | 13 +- src/dump_systemstate/dump_systemstate.c | 8 +- src/shared/util.c | 20 +- src/sys-assert/sys-assert.c | 54 ++--- 8 files changed, 425 insertions(+), 520 deletions(-) diff --git a/src/crash-pipe/crash-pipe.c b/src/crash-pipe/crash-pipe.c index e85ce32..d0177fa 100644 --- a/src/crash-pipe/crash-pipe.c +++ b/src/crash-pipe/crash-pipe.c @@ -34,24 +34,24 @@ #define NELEMS(arr) (sizeof(arr)/sizeof(arr[0])) enum { - OPT_HELP, - OPT_REPORT, - OPT_SAVE_CORE, + OPT_HELP, + OPT_REPORT, + OPT_SAVE_CORE, }; const struct option opts[] = { - { "help", no_argument, 0, OPT_HELP }, - { "report", no_argument, 0, OPT_REPORT }, - { "save-core", required_argument, 0, OPT_SAVE_CORE }, - { 0, 0, 0, 0 } + { "help", no_argument, 0, OPT_HELP }, + { "report", no_argument, 0, OPT_REPORT }, + { "save-core", required_argument, 0, OPT_SAVE_CORE }, + { 0, 0, 0, 0 } }; static char *argv0 = ""; static void usage(void) { - fprintf(stderr, "usage: %s [--help] [--save-core FILE_NAME] [--report] PID UID GID SIGNAL DUMPTIME EXE\n", - argv0); + fprintf(stderr, "usage: %s [--help] [--save-core FILE_NAME] [--report] PID UID GID SIGNAL DUMPTIME EXE\n", + argv0); } /* read file to buffer @@ -61,189 +61,186 @@ static void usage(void) */ static int procfs_read_fileline(const char *pid, const char *filename, char *outbuf, int outsize) { - char *path = NULL; - int fd; - int n; - int ret = 0; - - if (!(outsize > 0)) - return 0; - - if (asprintf(&path, "/proc/%s/%s", pid, filename) == -1) - return -ENOMEM; - - fd = open(path, O_RDONLY); - if (fd == -1) { - ret = -errno; - goto err; - } - - /* XXX we are really assuming here that one read is enough */ - ret = read(fd, outbuf, outsize); - if (ret == -1 || ret == outsize /* no place for \0 */) { - ret = -errno; - goto err; - } - - n = ret; - outbuf[n] = 0; - for (; n > 0; --n) { - if (outbuf[n] == '\n') - outbuf[n] = 0; - } - - close(fd); - - free(path); - return ret; + char *path = NULL; + int fd; + int n; + int ret = 0; + + if (!(outsize > 0)) + return 0; + + if (asprintf(&path, "/proc/%s/%s", pid, filename) == -1) + return -ENOMEM; + + fd = open(path, O_RDONLY); + if (fd == -1) { + ret = -errno; + goto err; + } + + /* XXX we are really assuming here that one read is enough */ + ret = read(fd, outbuf, outsize); + if (ret == -1 || ret == outsize /* no place for \0 */) { + ret = -errno; + goto err; + } + + n = ret; + outbuf[n] = 0; + for (; n > 0; --n) { + if (outbuf[n] == '\n') + outbuf[n] = 0; + } + + close(fd); + + free(path); + return ret; err: - if (fd >= 0) - close(fd); - free(path); - *outbuf = 0; - return ret; + if (fd >= 0) + close(fd); + free(path); + *outbuf = 0; + return ret; } void print_multiline(char *buf, int buf_size) { - int i; - int pos; + int i; + int pos; - for (pos = i = 0; buf[pos] && pos < buf_size; ++ i, pos += strlen(buf + pos) + 1) - printf("%21d: %s\n", i, buf + pos); + for (pos = i = 0; buf[pos] && pos < buf_size; ++i, pos += strlen(buf + pos) + 1) + printf("%21d: %s\n", i, buf + pos); } static void report(int argc, char *argv[]) { - const char *pidstr = argv[0]; - const char *uidstr = argv[1]; - const char *gidstr = argv[2]; - const char *sigstr = argv[3]; - const char *timestr = argv[4]; - const char *exestr = argv[5]; - static const struct { - char *file; - char *desc; - int is_multiline; - } proc_filedesc[] = { - { "comm", "Comm", 0}, - { "cgroup", "CGroup", 0 }, - { "attr/current", "MAC Label", 0 }, - { "oom_score", "OOM Score", 0 }, - { "oom_score_adj", "OOM Score Adj", 0 }, - { "cmdline", "Cmdline", 1 }, - { "environ", "Environment", 1 } - }; - - int i; - int n; + const char *pidstr = argv[0]; + const char *uidstr = argv[1]; + const char *gidstr = argv[2]; + const char *sigstr = argv[3]; + const char *timestr = argv[4]; + const char *exestr = argv[5]; + static const struct { + char *file; + char *desc; + int is_multiline; + } proc_filedesc[] = { + { "comm", "Comm", 0}, + { "cgroup", "CGroup", 0 }, + { "attr/current", "MAC Label", 0 }, + { "oom_score", "OOM Score", 0 }, + { "oom_score_adj", "OOM Score Adj", 0 }, + { "cmdline", "Cmdline", 1 }, + { "environ", "Environment", 1 } + }; + + int i; + int n; #define PROC_READ_MAX 16384 /* 4 pages should be enough for any process */ - static char proc_readbuf[PROC_READ_MAX]; - - printf("Crash report for: %s\n\n", exestr); - - printf(" - passed from kernel -\n" - "%16s: %s\n" - "%16s: %s\n" - "%16s: %s\n" - "%16s: %s\n" - "%16s: %s\n" - "%16s: %s\n\n", - "PID", pidstr, - "UID", uidstr, - "GID", gidstr, - "Signal number", sigstr, - "Timestamp", timestr, - "Executable", exestr); - - printf(" - procfs information -\n"); - - for (i = 0; i < NELEMS(proc_filedesc); ++ i) { - n = procfs_read_fileline(pidstr, proc_filedesc[i].file, proc_readbuf, sizeof(proc_readbuf)); - if (n < 0) - snprintf(proc_readbuf, sizeof(proc_readbuf), "Error (%d)", -n); - - if (n < 0 || proc_filedesc[i].is_multiline == 0) - printf("%16s: %s\n", proc_filedesc[i].desc, proc_readbuf); - else { - printf("%16s:\n", proc_filedesc[i].desc); - print_multiline(proc_readbuf, n); - } - } + static char proc_readbuf[PROC_READ_MAX]; + + printf("Crash report for: %s\n\n", exestr); + + printf(" - passed from kernel -\n" + "%16s: %s\n" + "%16s: %s\n" + "%16s: %s\n" + "%16s: %s\n" + "%16s: %s\n" + "%16s: %s\n\n", + "PID", pidstr, + "UID", uidstr, + "GID", gidstr, + "Signal number", sigstr, + "Timestamp", timestr, + "Executable", exestr); + + printf(" - procfs information -\n"); + + for (i = 0; i < NELEMS(proc_filedesc); ++i) { + n = procfs_read_fileline(pidstr, proc_filedesc[i].file, proc_readbuf, sizeof(proc_readbuf)); + if (n < 0) + snprintf(proc_readbuf, sizeof(proc_readbuf), "Error (%d)", -n); + + if (n < 0 || proc_filedesc[i].is_multiline == 0) + printf("%16s: %s\n", proc_filedesc[i].desc, proc_readbuf); + else { + printf("%16s:\n", proc_filedesc[i].desc); + print_multiline(proc_readbuf, n); + } + } } static int save_core(const char *core_path) { - int fd; - static char buf[4096]; - int readb, remaining; - - fd = open(core_path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); - if (fd == -1) { - syslog(LOG_ERR, "crash-pipe: Unable to save core file to %s: %m\n", core_path); - return -1; - } - - while ((readb = read(STDIN_FILENO, buf, sizeof(buf))) > 0) { - int n; - - for (n = 0, remaining = readb ; remaining > 0; remaining -= n) { - n = write(fd, buf, remaining); - if (n == -1) { - syslog(LOG_ERR, "crash-pipe: Error while saving core file %s: %m. Removing core.\n", core_path); - (void)unlink(core_path); // XXX check errors here too - goto out; - } - } - } + int fd; + static char buf[4096]; + int readb, remaining; + + fd = open(core_path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); + if (fd == -1) { + syslog(LOG_ERR, "crash-pipe: Unable to save core file to %s: %m\n", core_path); + return -1; + } + + while ((readb = read(STDIN_FILENO, buf, sizeof(buf))) > 0) { + int n; + + for (n = 0, remaining = readb ; remaining > 0; remaining -= n) { + n = write(fd, buf, remaining); + if (n == -1) { + syslog(LOG_ERR, "crash-pipe: Error while saving core file %s: %m. Removing core.\n", core_path); + (void)unlink(core_path); // XXX check errors here too + goto out; + } + } + } out: - close(fd); + close(fd); - return 0; + return 0; } int main(int argc, char *argv[]) { - int c; - int opt_report = 0; - char *opt_save_core = NULL; - int ret = 1; + int c; + int opt_report = 0; + char *opt_save_core = NULL; + int ret = 1; - prctl(PR_SET_DUMPABLE, 0); + prctl(PR_SET_DUMPABLE, 0); - argv0 = argv[0]; + argv0 = argv[0]; + while ((c = getopt_long_only(argc, argv, "", opts, NULL)) != -1) { - while ((c = getopt_long_only(argc, argv, "", opts, NULL)) != -1) { + if (c == OPT_HELP) { + usage(); + exit(EXIT_SUCCESS); + } else if (c == OPT_REPORT) { + opt_report = 1; + } else if (c == OPT_SAVE_CORE) { + opt_save_core = strdup(optarg); + if (!opt_save_core) { + syslog(LOG_CRIT, "Out of memory. Exiting."); + exit(EXIT_FAILURE); + } + } + } - if (c == OPT_HELP) { - usage(); - exit(EXIT_SUCCESS); - } - else if (c == OPT_REPORT) { - opt_report = 1; - } - else if (c == OPT_SAVE_CORE) { - opt_save_core = strdup(optarg); - if (!opt_save_core) { - syslog(LOG_CRIT, "Out of memory. Exiting."); - exit(EXIT_FAILURE); - } - } - } + argc -= optind; + argv += optind; - argc -= optind; - argv += optind; + if (opt_report) + report(argc, argv); - if (opt_report) - report(argc, argv); + if (opt_save_core) + ret = save_core(opt_save_core); - if (opt_save_core) - ret = save_core(opt_save_core); - - return ret >= 0 ? EXIT_SUCCESS : EXIT_FAILURE; + return ret >= 0 ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/src/crash-stack/crash-stack-arm.c b/src/crash-stack/crash-stack-arm.c index e1d6904..c1d2628 100644 --- a/src/crash-stack/crash-stack-arm.c +++ b/src/crash-stack/crash-stack-arm.c @@ -9,8 +9,7 @@ static Dwfl *g_dwfl = NULL; static Mappings *g_mappings = NULL; static pid_t g_pid = 0; -struct Regs -{ +struct Regs { Dwarf_Addr regs[REGS_REGULAR_NUM]; Dwarf_Addr sp; Dwarf_Addr lr; @@ -21,32 +20,22 @@ struct Regs typedef struct Regs Regs; static Regs g_regs; -void *get_place_for_register_value (const char *regname, int regnum) +void *get_place_for_register_value(const char *regname, int regnum) { - if (strcmp (regname, "pc") == 0 || REG_PC == regnum) - { + if (strcmp(regname, "pc") == 0 || REG_PC == regnum) return &g_regs.pc; - } - else if (strcmp (regname, "sp") == 0 || REG_SP == regnum) - { + else if (strcmp(regname, "sp") == 0 || REG_SP == regnum) return &g_regs.sp; - } - else if (strcmp (regname, "lr") == 0 || REG_LR == regnum) - { + else if (strcmp(regname, "lr") == 0 || REG_LR == regnum) return &g_regs.lr; - } - else if (strcmp (regname, "spsr") == 0 || REG_SPSR == regnum) - { + else if (strcmp(regname, "spsr") == 0 || REG_SPSR == regnum) return &g_regs.spsr; - } else if (regnum < REGS_REGULAR_NUM) - { return &g_regs.regs[regnum]; - } return NULL; } -static Boolean report (void *data, Int32 address) +static Boolean report(void *data, Int32 address) { Callstack *callstack = (Callstack *)(data); callstack->tab[callstack->elems++] = address; @@ -54,58 +43,50 @@ static Boolean report (void *data, Int32 address) return callstack->elems < MAX_CALLSTACK_LEN ? TRUE : FALSE; } -Boolean readT (Int32 a, void *v, size_t size) +Boolean readT(Int32 a, void *v, size_t size) { Dwfl_Module *module = 0; Elf_Data *data = NULL; - int segment = dwfl_addrsegment (g_dwfl, a, &module); + int segment = dwfl_addrsegment(g_dwfl, a, &module); - if (module != NULL) - { + if (module != NULL) { Dwarf_Addr start; - dwfl_module_info (module, NULL, &start, NULL, NULL, NULL, NULL, NULL); + dwfl_module_info(module, NULL, &start, NULL, NULL, NULL, NULL, NULL); GElf_Addr bias; - Elf *elf = dwfl_module_getelf (module, &bias); + Elf *elf = dwfl_module_getelf(module, &bias); - data = elf_getdata_rawchunk (elf, a-start, size, ELF_T_BYTE); + data = elf_getdata_rawchunk(elf, a-start, size, ELF_T_BYTE); } - if (NULL == data && segment != -1) - { + if (NULL == data && segment != -1) { // get data from segment GElf_Phdr mem; GElf_Phdr *phdr; Dwarf_Addr offset_in_segment; - phdr = gelf_getphdr (g_core, segment, &mem); - if (phdr != NULL) - { + phdr = gelf_getphdr(g_core, segment, &mem); + if (phdr != NULL) { offset_in_segment = a - phdr->p_vaddr; - if (offset_in_segment < phdr->p_filesz) - { + if (offset_in_segment < phdr->p_filesz) { Dwarf_Addr offset_in_file = phdr->p_offset + offset_in_segment; - data = elf_getdata_rawchunk (g_core, offset_in_file, size, ELF_T_BYTE); + data = elf_getdata_rawchunk(g_core, offset_in_file, size, ELF_T_BYTE); } } } - if (NULL == data && module != NULL) - { - const char *name = dwfl_module_info (module, NULL, NULL, NULL, NULL, NULL, NULL, NULL); - if (name != NULL && name[0] == '[') - { + if (NULL == data && module != NULL) { + const char *name = dwfl_module_info(module, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + if (name != NULL && name[0] == '[') { int i; // get module from mappings - for (i = 0; i < g_mappings->elems; i++) - { - if (g_mappings->tab[i].m_start <= a && a < g_mappings->tab[i].m_end) - { + for (i = 0; i < g_mappings->elems; i++) { + if (g_mappings->tab[i].m_start <= a && a < g_mappings->tab[i].m_end) { // compute offset relative to the start of the mapping Int32 offset = a - g_mappings->tab[i].m_start; // read from the file, but also account file offset - data = elf_getdata_rawchunk (g_mappings->tab[i].m_elf, + data = elf_getdata_rawchunk(g_mappings->tab[i].m_elf, offset + g_mappings->tab[i].m_offset, size, ELF_T_BYTE); break; } @@ -113,86 +94,74 @@ Boolean readT (Int32 a, void *v, size_t size) } } - if (data != NULL) - { - memcpy (v, data->d_buf, size); + if (data != NULL) { + memcpy(v, data->d_buf, size); return TRUE; } /* Still no data, but we have a process - read memory with ptrace */ - if (NULL == data && g_pid > 1) - { - long val = ptrace (PTRACE_PEEKDATA, g_pid, a, NULL); - memcpy (v, &val, size); + if (NULL == data && g_pid > 1) { + long val = ptrace(PTRACE_PEEKDATA, g_pid, a, NULL); + memcpy(v, &val, size); return TRUE; } return FALSE; } -static Boolean readW (Int32 a, Int32 *v) +static Boolean readW(Int32 a, Int32 *v) { - return readT(a,v,sizeof(*v)); + return readT(a, v, sizeof(*v)); } -static Boolean readH (Int32 a, Int16 *v) +static Boolean readH(Int32 a, Int16 *v) { - return readT(a,v,sizeof(*v)); + return readT(a, v, sizeof(*v)); } -static Boolean readB (Int32 a, Int8 *v) +static Boolean readB(Int32 a, Int8 *v) { - return readT(a,v,sizeof(*v)); + return readT(a, v, sizeof(*v)); } -static Int32 getProloguePC (Int32 current_pc) +static Int32 getProloguePC(Int32 current_pc) { Int32 result = 0; - Dwfl_Module *module = dwfl_addrmodule (g_dwfl, current_pc); - if (module) - { + Dwfl_Module *module = dwfl_addrmodule(g_dwfl, current_pc); + if (module) { // GElf_Off offset; GElf_Sym sym; // dwfl_module_addrinfo (module, current_pc, &offset, &sym, NULL, NULL, NULL); - dwfl_module_addrsym (module, current_pc, &sym, NULL); + dwfl_module_addrsym(module, current_pc, &sym, NULL); // result = current_pc - offset; result = sym.st_value; } - if (0 == result) - { + if (0 == result) { int i; - for (i=0; i < g_mappings->elems; i++) - { - if (g_mappings->tab[i].m_start <= current_pc && current_pc < g_mappings->tab[i].m_end) - { + for (i = 0; i < g_mappings->elems; i++) { + if (g_mappings->tab[i].m_start <= current_pc && current_pc < g_mappings->tab[i].m_end) { /* go through symbols to find the nearest */ Elf_Scn *scn = NULL; Elf *elf = g_mappings->tab[i].m_elf; - while ((scn = elf_nextscn (elf, scn)) != NULL) - { + 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); + 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)); + sizeof(Elf32_Sym) : + sizeof(Elf64_Sym)); unsigned int cnt; uintptr_t address_offset = current_pc; if (shdr->sh_type == SHT_DYNSYM) address_offset -= g_mappings->tab[i].m_start; - for (cnt = 0; cnt < nsyms; ++cnt) - { + 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 != NULL && sym->st_shndx != SHN_UNDEF) { if (sym->st_value <= address_offset && address_offset < sym->st_value + sym->st_size) - { return sym->st_value; - } } } } @@ -203,10 +172,9 @@ static Int32 getProloguePC (Int32 current_pc) return result; } -void create_crash_stack (Dwfl *dwfl, Elf *core, pid_t pid, Mappings *mappings, Callstack *callstack) +void create_crash_stack(Dwfl *dwfl, Elf *core, pid_t pid, Mappings *mappings, Callstack *callstack) { - UnwindCallbacks callbacks = - { + UnwindCallbacks callbacks = { report, readW, readH, @@ -227,10 +195,9 @@ void create_crash_stack (Dwfl *dwfl, Elf *core, pid_t pid, Mappings *mappings, C callstack->tab[0] = g_regs.pc; callstack->elems = 1; - UnwInitState (&state, &callbacks, callstack, g_regs.pc, g_regs.sp); + UnwInitState(&state, &callbacks, callstack, g_regs.pc, g_regs.sp); int i; - for (i = 0; i < REGS_REGULAR_NUM; i++) - { + for (i = 0; i < REGS_REGULAR_NUM; i++) { state.regData[i].v = g_regs.regs[i]; state.regData[i].o = REG_VAL_FROM_CONST; } @@ -239,9 +206,9 @@ void create_crash_stack (Dwfl *dwfl, Elf *core, pid_t pid, Mappings *mappings, C state.regData[REG_SPSR].v = g_regs.spsr; state.regData[REG_SPSR].o = REG_VAL_FROM_CONST; - if (UnwIsAddrThumb (g_regs.pc, g_regs.spsr)) - UnwStartThumb (&state); + if (UnwIsAddrThumb(g_regs.pc, g_regs.spsr)) + UnwStartThumb(&state); else - UnwStartArm (&state); + UnwStartArm(&state); } diff --git a/src/crash-stack/crash-stack-libelf.c b/src/crash-stack/crash-stack-libelf.c index 44fec1c..f4c10bc 100644 --- a/src/crash-stack/crash-stack-libelf.c +++ b/src/crash-stack/crash-stack-libelf.c @@ -2,33 +2,33 @@ #include #include -#if _ELFUTILS_PREREQ(0,158) -static int frame_callback (Dwfl_Frame *state, void *arg) +#if _ELFUTILS_PREREQ(0, 158) +static int frame_callback(Dwfl_Frame *state, void *arg) { Callstack *callstack = (Callstack*)arg; Dwarf_Addr address; - dwfl_frame_pc (state, &address, NULL); + dwfl_frame_pc(state, &address, NULL); callstack->tab[callstack->elems++] = address; return callstack->elems < MAX_CALLSTACK_LEN ? DWARF_CB_OK : DWARF_CB_ABORT; } -static int thread_callback (Dwfl_Thread *thread, void *thread_arg) +static int thread_callback(Dwfl_Thread *thread, void *thread_arg) { - dwfl_thread_getframes (thread, frame_callback, thread_arg); + dwfl_thread_getframes(thread, frame_callback, thread_arg); return DWARF_CB_ABORT; } #endif -void *get_place_for_register_value (const char *regname, int regnum) +void *get_place_for_register_value(const char *regname, int regnum) { return 0; } -void create_crash_stack (Dwfl *dwfl, Elf *core, pid_t pid, Mappings *mappings, Callstack *callstack) +void create_crash_stack(Dwfl *dwfl, Elf *core, pid_t pid, Mappings *mappings, Callstack *callstack) { callstack->elems = 0; -#if _ELFUTILS_PREREQ(0,158) - dwfl_getthreads (dwfl, thread_callback, callstack); +#if _ELFUTILS_PREREQ(0, 158) + dwfl_getthreads(dwfl, thread_callback, callstack); #endif } diff --git a/src/crash-stack/crash-stack.c b/src/crash-stack/crash-stack.c index cbea4f7..321132c 100644 --- a/src/crash-stack/crash-stack.c +++ b/src/crash-stack/crash-stack.c @@ -34,19 +34,17 @@ const struct option opts[] = { { 0, 0, 0, 0 } }; -extern char *__cxa_demangle (const char *mangled_name, char *output_buffer, +extern char *__cxa_demangle(const char *mangled_name, char *output_buffer, size_t *length, int *status); -static int module_callback (Dwfl_Module *module, void **userdata, +static int module_callback(Dwfl_Module *module, void **userdata, const char *name, Dwarf_Addr address, void *arg) { - if (name != NULL && name[0] == '[') - { + if (name != NULL && name[0] == '[') { /* libdwfl couldn't get the module file - we will get it later from notes */ Mappings *mappings = arg; - if (mappings->elems < MAX_MAPPINGS_NUM) - { + if (mappings->elems < MAX_MAPPINGS_NUM) { size_t elems = mappings->elems; mappings->tab[elems].m_start = address; mappings->tab[elems].m_end = 0; @@ -61,10 +59,9 @@ static int module_callback (Dwfl_Module *module, void **userdata, return DWARF_CB_OK; } -static void getvalue (Elf *core, const void *from, size_t size, void *to) +static void getvalue(Elf *core, const void *from, size_t size, void *to) { - Elf_Data out = - { + Elf_Data out = { .d_buf = to, .d_type = size == 32 ? ELF_T_WORD : ELF_T_XWORD, .d_version = EV_CURRENT, @@ -72,8 +69,7 @@ static void getvalue (Elf *core, const void *from, size_t size, void *to) .d_off = 0, .d_align = 0 }; - Elf_Data in = - { + Elf_Data in = { .d_buf = (void*)(from), .d_type = out.d_type, .d_version = out.d_version, @@ -82,22 +78,20 @@ static void getvalue (Elf *core, const void *from, size_t size, void *to) .d_align = 0 }; Elf_Data *data; - if (gelf_getclass (core) == ELFCLASS32) - data = elf32_xlatetom (&out, &in, elf_getident (core, NULL)[EI_DATA]); + if (gelf_getclass(core) == ELFCLASS32) + data = elf32_xlatetom(&out, &in, elf_getident(core, NULL)[EI_DATA]); else - data = elf64_xlatetom (&out, &in, elf_getident (core, NULL)[EI_DATA]); + data = elf64_xlatetom(&out, &in, elf_getident(core, NULL)[EI_DATA]); if (data == NULL) - fprintf (errfile, "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, +static void updateMapping(Mappings *mappings, uint64_t mapping_start, uint64_t mapping_end, uint64_t offset, const char *name) { int i; - for (i = 0; i < mappings->elems; i++) - { - if (mappings->tab[i].m_start == mapping_start) - { + for (i = 0; i < mappings->elems; i++) { + if (mappings->tab[i].m_start == mapping_start) { mappings->tab[i].m_end = mapping_end; mappings->tab[i].m_name = name; mappings->tab[i].m_offset = offset; @@ -108,10 +102,10 @@ static void updateMapping (Mappings *mappings, uint64_t mapping_start, uint64_t } } -static void parse_note_file (Elf *elf, const char *desc, uint64_t *values_cnt, uint64_t *page_size, +static void parse_note_file(Elf *elf, const char *desc, uint64_t *values_cnt, uint64_t *page_size, size_t *addr_size, const char **values, const char **filenames) { - *addr_size = gelf_fsize (elf, ELF_T_ADDR, 1, EV_CURRENT); + *addr_size = gelf_fsize(elf, ELF_T_ADDR, 1, EV_CURRENT); getvalue(elf, desc, *addr_size*8, values_cnt); getvalue(elf, desc + *addr_size, *addr_size*8, page_size); /* First: triplets of @@ -130,7 +124,7 @@ static void get_mapping_item(Elf *elf, size_t addr_size, const void *item, getvalue(elf, item + 2 * addr_size, addr_size*8, offset_in_pages); } -static char *try_symbol_from_elfs (Elf *core, Elf_Data *notes, uintptr_t address, +static char *try_symbol_from_elfs(Elf *core, Elf_Data *notes, uintptr_t address, const char **module_name) { GElf_Nhdr nhdr; @@ -140,10 +134,8 @@ static char *try_symbol_from_elfs (Elf *core, Elf_Data *notes, uintptr_t address 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) - { + 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; @@ -152,22 +144,20 @@ static char *try_symbol_from_elfs (Elf *core, Elf_Data *notes, uintptr_t address 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++) - { + 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); + get_mapping_item(core, addr_size, item, &mapping_start, &mapping_end, &offset_in_pages); - if (mapping_start <= address && address < mapping_end) - { + if (mapping_start <= address && address < mapping_end) { Elf *elf; int fd; fd = open(filenames, O_RDONLY); if (-1 == fd) return NULL; - elf = elf_begin (fd, ELF_C_READ_MMAP, NULL); + elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); if (NULL == elf) { close(fd); @@ -177,30 +167,25 @@ static char *try_symbol_from_elfs (Elf *core, Elf_Data *notes, uintptr_t address Elf_Scn *scn = NULL; *module_name = filenames; - while ((scn = elf_nextscn (elf, scn)) != NULL) - { + 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); + 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)); + 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) - { + 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)); + 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; } } @@ -222,148 +207,134 @@ static char *try_symbol_from_elfs (Elf *core, Elf_Data *notes, uintptr_t address return NULL; } -static Dwfl *open_dwfl_with_pid (pid_t pid) +static Dwfl *open_dwfl_with_pid(pid_t pid) { int status; pid_t stopped_pid; - if (ptrace (PTRACE_SEIZE, pid, NULL, PTRACE_O_TRACEEXIT) != 0) - { + 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, pid, 0, 0); stopped_pid = waitpid(pid, &status, 0); - if (stopped_pid == -1 || stopped_pid != pid || !WIFSTOPPED(status)) - { + if (stopped_pid == -1 || stopped_pid != pid || !WIFSTOPPED(status)) { fprintf(errfile, "waitpid failed: %m, stopped_pid=%d, status=%d\n", stopped_pid, status); return NULL; } - static const Dwfl_Callbacks proc_callbacks = - { + 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)); + 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); + 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; } -#if _ELFUTILS_PREREQ(0,158) - if (dwfl_linux_proc_attach (dwfl, pid, true) < 0) - { - fprintf (errfile, "process %d : dwfl attach failed (%s)\n", pid, dwfl_errmsg(-1)); - dwfl_end (dwfl); +#if _ELFUTILS_PREREQ(0, 158) + if (dwfl_linux_proc_attach(dwfl, pid, true) < 0) { + fprintf(errfile, "process %d : dwfl attach failed (%s)\n", pid, dwfl_errmsg(-1)); + dwfl_end(dwfl); return NULL; } #endif return dwfl; } -static Dwfl *open_dwfl_with_core (Elf *core, const char *core_file_name) +static Dwfl *open_dwfl_with_core(Elf *core, const char *core_file_name) { - static const Dwfl_Callbacks core_callbacks = - { + static const Dwfl_Callbacks core_callbacks = { .find_elf = dwfl_build_id_find_elf, .find_debuginfo = dwfl_standard_find_debuginfo, .section_address = NULL, .debuginfo_path = NULL }; - Dwfl *dwfl = dwfl_begin (&core_callbacks); - if (dwfl == NULL) - { - fprintf (errfile, "%s : Can't start dwfl (%s)\n", core_file_name, dwfl_errmsg(-1)); + Dwfl *dwfl = dwfl_begin(&core_callbacks); + if (dwfl == NULL) { + 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, NULL) < 0) +#if _ELFUTILS_PREREQ(0, 158) + if (dwfl_core_file_report(dwfl, core, NULL) < 0) #else - if (dwfl_core_file_report (dwfl, core) < 0) + if (dwfl_core_file_report(dwfl, core) < 0) #endif { - fprintf (errfile, "%s : dwfl report failed (%s)\n", core_file_name, dwfl_errmsg(-1)); - dwfl_end (dwfl); + 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 (errfile, "%s : dwfl attach failed (%s)\n", core_file_name, dwfl_errmsg(-1)); - dwfl_end (dwfl); +#if _ELFUTILS_PREREQ(0, 158) + if (dwfl_core_file_attach(dwfl, core) < 0) { + fprintf(errfile, "%s : dwfl attach failed (%s)\n", core_file_name, dwfl_errmsg(-1)); + dwfl_end(dwfl); return NULL; } #endif return dwfl; } -static int get_registers_ptrace (pid_t pid) +static int get_registers_ptrace(pid_t pid) { struct iovec data; uintptr_t regbuf[20]; data.iov_base = regbuf; - data.iov_len = sizeof (regbuf); + data.iov_len = sizeof(regbuf); - if (ptrace (PTRACE_GETREGSET, pid, NT_PRSTATUS, &data) != 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); + 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])); + memcpy(reg, ®buf[i], sizeof(regbuf[i])); } return 0; } -static Elf_Data *get_registers_core (Elf *core, const char *core_file_name, Mappings *mappings) +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); + GElf_Phdr *phdr = gelf_getphdr(core, 0, &mem); - if (phdr == NULL || phdr->p_type != PT_NOTE) - { - fprintf (errfile, "%s : Missing note section at the first position in core file\n", + if (phdr == NULL || phdr->p_type != PT_NOTE) { + 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 (errfile, "%s : error getting notes (%s)\n", core_file_name, dwfl_errmsg(-1)); + Elf_Data *notes = elf_getdata_rawchunk(core, phdr->p_offset, phdr->p_filesz, ELF_T_NHDR); + if (notes == NULL) { + 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 (errfile, "%s : Can't initialize ebl\n", core_file_name); + Ebl *ebl = ebl_openbackend(core); + if (ebl == NULL) { + fprintf(errfile, "%s : Can't initialize ebl\n", core_file_name); return NULL; } @@ -374,10 +345,8 @@ static Elf_Data *get_registers_core (Elf *core, const char *core_file_name, Mapp size_t new_pos = 0; int got_regs = 0; /* registers should be in the first note! */ - while ((new_pos = gelf_getnote (notes, pos, &nhdr, &name_pos, &desc_pos)) > 0) - { - if (nhdr.n_type == NT_PRSTATUS && !got_regs) - { + while ((new_pos = gelf_getnote(notes, pos, &nhdr, &name_pos, &desc_pos)) > 0) { + if (nhdr.n_type == NT_PRSTATUS && !got_regs) { GElf_Word regs_offset; size_t nregloc; const Ebl_Register_Location *reglocs; @@ -386,10 +355,9 @@ static Elf_Data *get_registers_core (Elf *core, const char *core_file_name, Mapp got_regs = 1; - if (0 == ebl_core_note (ebl, &nhdr, "CORE", ®s_offset, &nregloc, - ®locs, &nitems, &items)) - { - fprintf (errfile, + if (0 == ebl_core_note(ebl, &nhdr, "CORE", ®s_offset, &nregloc, + ®locs, &nitems, &items)) { + fprintf(errfile, "%s : error parsing notes (built with different build of libebl?)\n", core_file_name); return NULL; @@ -399,38 +367,33 @@ static Elf_Data *get_registers_core (Elf *core, const char *core_file_name, Mapp + regs_offset; unsigned i; - for (i = 0; i < nregloc; 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++) - { + regnum++) { char regname[5]; int bits, type; const char *prefix = 0; const char *setname = 0; - ssize_t ret = ebl_register_info (ebl, regnum, regname, + ssize_t ret = ebl_register_info(ebl, regnum, regname, sizeof(regname), &prefix, &setname, &bits, &type); - if (ret < 0) - { - fprintf (errfile, "%s : can't get register info\n", core_file_name); + if (ret < 0) { + 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); + void *place_for_reg_value = get_place_for_register_value(regname, regnum); if (place_for_reg_value != NULL) - getvalue (core, register_location, bits, place_for_reg_value); + getvalue(core, register_location, bits, place_for_reg_value); register_location += bits / 8 + reglocs[i].pad; } } - } - else if (nhdr.n_type == NT_FILE) - { + } else if (nhdr.n_type == NT_FILE) { uint64_t values_cnt = 0, page_size = 0; const char *values; const char *filenames; @@ -444,75 +407,67 @@ static Elf_Data *get_registers_core (Elf *core, const char *core_file_name, Mapp * count = values_cnt * Then the names of files. */ - for (ii = 0; ii < values_cnt; 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, + get_mapping_item(core, addr_size, item, &mapping_start, &mapping_end, &offset_in_pages); - updateMapping (mappings, mapping_start, mapping_end, + updateMapping(mappings, mapping_start, mapping_end, offset_in_pages*page_size, filenames); - filenames += strlen (filenames)+1; + filenames += strlen(filenames)+1; } } pos = new_pos; } - ebl_closebackend (ebl); + ebl_closebackend(ebl); return notes; } -static void printCallstack (Callstack *callstack, Dwfl *dwfl, Elf *core, pid_t pid, +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"); + fprintf(outputfile, "Call stack"); + if (pid > 1) fprintf(outputfile, " for PID %d", pid); + fprintf(outputfile, ":\n"); 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]); + for (it = 0; it != callstack->elems; ++it) { + if (sizeof(callstack->tab[0]) > 4) + fprintf(outputfile, "0x%016llx: ", (long long)callstack->tab[it]); else - fprintf (outputfile, "0x%08x: ", (int32_t)callstack->tab[it]); - Dwfl_Module *module = dwfl_addrmodule (dwfl, callstack->tab[it]); - if (module) - { + 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); + 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); - } - if (symbol != 0 && symbol[0] == '_' && symbol[1] == 'Z') - { + 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); + demangled_symbol = __cxa_demangle(symbol, dem_buffer, NULL, &status); if (status == 0) symbol = demangled_symbol; } if (symbol != 0) - fprintf (outputfile, "%s()", symbol); + fprintf(outputfile, "%s()", symbol); else - fprintf (outputfile, ""); + fprintf(outputfile, ""); if (demangled_symbol != 0) - free (demangled_symbol); + free(demangled_symbol); if (symbol_from_elf != 0) - free (symbol_from_elf); + free(symbol_from_elf); - fprintf (outputfile, " from %s\n", fname != NULL ? fname : module_name); - } - else - { - fprintf (outputfile, "unknown function\n"); + fprintf(outputfile, " from %s\n", fname != NULL ? fname : module_name); + } else { + fprintf(outputfile, "unknown function\n"); } } } @@ -524,21 +479,19 @@ int main(int argc, char **argv) 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; + 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; } } @@ -548,7 +501,7 @@ int main(int argc, char **argv) core_file_name = argv[optind]; argc -= optind; - elf_version (EV_CURRENT); + elf_version(EV_CURRENT); /* First, prepare dwfl and modules */ Elf *core = NULL; @@ -556,34 +509,28 @@ int main(int argc, char **argv) Dwfl *dwfl = NULL; if (pid > 1) - { - dwfl = open_dwfl_with_pid (pid); - } - else - { - if (argc != 1) - { - fprintf (errfile, + dwfl = open_dwfl_with_pid(pid); + else { + if (argc != 1) { + fprintf(errfile, "Usage: %s [--output file] [--erroutput file] [--pid | ]\n", argv[0]); return 1; } - core_fd = open (core_file_name, O_RDONLY); - if (core_fd < 0) - { - perror (core_file_name); + 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)); + 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); + dwfl = open_dwfl_with_core(core, core_file_name); } if (NULL == dwfl) @@ -592,18 +539,15 @@ int main(int argc, char **argv) Mappings mappings; mappings.elems = 0; - dwfl_getmodules (dwfl, module_callback, &mappings, 0); + dwfl_getmodules(dwfl, module_callback, &mappings, 0); Elf_Data *notes = 0; /* Now, get registers */ - if (pid > 1) - { - if (-1 == get_registers_ptrace (pid)) + if (pid > 1) { + if (-1 == get_registers_ptrace(pid)) return 3333; - } - else - { - notes = get_registers_core (core, core_file_name, &mappings); + } else { + notes = get_registers_core(core, core_file_name, &mappings); if (NULL == notes) return 2222; } @@ -611,16 +555,16 @@ int main(int argc, char **argv) /* Unwind call stack */ Callstack callstack; - create_crash_stack (dwfl, core, pid, &mappings, &callstack); + create_crash_stack(dwfl, core, pid, &mappings, &callstack); /* Print the results */ - printCallstack (&callstack, dwfl, core, pid, notes); + printCallstack(&callstack, dwfl, core, pid, notes); /* Clean up */ - dwfl_report_end (dwfl, NULL, NULL); - dwfl_end (dwfl); - if (NULL != core) elf_end (core); - if (-1 != core_fd) close (core_fd); + dwfl_report_end(dwfl, NULL, NULL); + dwfl_end(dwfl); + if (NULL != core) elf_end(core); + if (-1 != core_fd) close(core_fd); return 0; } diff --git a/src/crash-stack/crash-stack.h b/src/crash-stack/crash-stack.h index 57198ab..bf712c0 100644 --- a/src/crash-stack/crash-stack.h +++ b/src/crash-stack/crash-stack.h @@ -7,14 +7,12 @@ #define MAX_CALLSTACK_LEN 1000 -typedef struct Callstack -{ +typedef struct Callstack { uintptr_t tab[MAX_CALLSTACK_LEN]; size_t elems; } Callstack; -typedef struct Mapping -{ +typedef struct Mapping { uintptr_t m_start; uintptr_t m_end; uintptr_t m_offset; @@ -25,13 +23,12 @@ typedef struct Mapping #define MAX_MAPPINGS_NUM 1000 -typedef struct Mappings -{ +typedef struct Mappings { Mapping tab[MAX_MAPPINGS_NUM]; size_t elems; } Mappings; -void *get_place_for_register_value (const char *regname, int regnum); -void create_crash_stack (Dwfl *dwfl, Elf *core, pid_t pid, Mappings *mappings, Callstack *callstack); +void *get_place_for_register_value(const char *regname, int regnum); +void create_crash_stack(Dwfl *dwfl, Elf *core, pid_t pid, Mappings *mappings, Callstack *callstack); #endif /* CRASH_STACK_H */ diff --git a/src/dump_systemstate/dump_systemstate.c b/src/dump_systemstate/dump_systemstate.c index b3a6245..aed09b6 100644 --- a/src/dump_systemstate/dump_systemstate.c +++ b/src/dump_systemstate/dump_systemstate.c @@ -53,7 +53,8 @@ static struct dump_item { {"==== System disk I/O satistics " , "/proc/diskstats"}, }; -static void usage() { +static void usage() +{ fprintf(stderr, "usage: dump_systemstate [-k] [-d] [-f file]\n" " -f: write to file (instead of stdout)\n" " -k: dump kernel messages (only root)\n" @@ -77,7 +78,8 @@ static int get_disk_used_percent(const char *path) return percent; } -int main(int argc, char *argv[]) { +int main(int argc, char *argv[]) +{ int c, ret, i, is_root, dpercent; const char *arg_file = NULL; int out_fd = -1; @@ -118,7 +120,7 @@ int main(int argc, char *argv[]) { } else { out_fd = open(arg_file, O_WRONLY | O_TRUNC | O_CREAT, FILE_PERM); if (out_fd < 0) { - perror ("couldn't open output file"); + perror("couldn't open output file"); ret = out_fd; goto exit; } diff --git a/src/shared/util.c b/src/shared/util.c index 776ab92..1b3412f 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -61,13 +61,12 @@ int system_command(char *command) if (errno != EINTR) return -1; } else { - if (WIFEXITED(status)) { + if (WIFEXITED(status)) return WEXITSTATUS(status); - } else if (WIFSIGNALED(status)) { + else if (WIFSIGNALED(status)) return WTERMSIG(status); - } else if (WIFSTOPPED(status)) { + else if (WIFSTOPPED(status)) return WSTOPSIG(status); - } } } while (!WIFEXITED(status) && !WIFSIGNALED(status)); @@ -173,7 +172,7 @@ int copy_file(char *src, char *dst) int dfd; char buf[PIPE_BUF]; - if(!src || !dst) { + if (!src || !dst) { _E("Invalid argument\n"); return -1; } @@ -206,7 +205,7 @@ int cat_file(char *src, char *dst) int dfd; char buf[PIPE_BUF]; - if(!src || !dst) { + if (!src || !dst) { _E("Invalid argument\n"); return -1; } @@ -247,7 +246,7 @@ int dump_file_write_fd(char *src, int dfd) int sfd; char buf[PIPE_BUF]; - if(!src) { + if (!src) { _E("Invalid argument\n"); return -1; } @@ -283,9 +282,9 @@ int run_command_write_fd(char *cmd, int dfd) _E("Failed to popen\n"); return -1; } - while(fgets(buff, PIPE_BUF, fp) != NULL) { + while (fgets(buff, PIPE_BUF, fp) != NULL) write_fd(dfd, buff, strlen(buff)); - } + ret = pclose(fp); return ret; } @@ -313,9 +312,8 @@ static int remove_dir_internal(int fd) ret = -1; continue; } - if (remove_dir_internal(subfd)) { + if (remove_dir_internal(subfd)) ret = -1; - } close(subfd); if (unlinkat(fd, de->d_name, AT_REMOVEDIR) < 0) { _SE("Couldn't unlinkat %s: %d\n", de->d_name, errno); diff --git a/src/sys-assert/sys-assert.c b/src/sys-assert/sys-assert.c index eaecd97..d7e9493 100644 --- a/src/sys-assert/sys-assert.c +++ b/src/sys-assert/sys-assert.c @@ -102,7 +102,7 @@ extern int dump_callstack(void **callstack_addrs, int size, void *context, int r static int trace_symbols(void *const *array, int size, struct addr_node *start, int fd) { Dl_info info_funcs; - Elf32_Ehdr elf_h = {{0,},0,}; + Elf32_Ehdr elf_h = {{0, }, 0, }; Elf32_Shdr *s_headers; Elf32_Sym *symtab_entry; int i, cnt, file, ret; @@ -146,7 +146,7 @@ static int trace_symbols(void *const *array, int size, struct addr_node *start, /* Both dli_sname and dli_fname is NULL, sys-assert cannot trace any information. Thus, sys-assert skips to translate such address entry. However, if a developer wants raw information, we need to fix the code to print raw data */ - if(info_funcs.dli_fname == NULL) + if (info_funcs.dli_fname == NULL) continue; file = open(info_funcs.dli_fname, O_RDONLY); @@ -553,32 +553,32 @@ static void print_signal_info(int signum, const siginfo_t *info, int fd) } } else if (signum == SIGSEGV) { switch (info->si_code) { - case SEGV_MAPERR: - fprintf_fd(fd, " address not mapped to object\n"); - break; - case SEGV_ACCERR: - fprintf_fd(fd, - " invalid permissions for mapped object\n"); - break; - default: - fprintf_fd(fd, " illegal si_code: %d\n", info->si_code); - break; + case SEGV_MAPERR: + fprintf_fd(fd, " address not mapped to object\n"); + break; + case SEGV_ACCERR: + fprintf_fd(fd, + " invalid permissions for mapped object\n"); + break; + default: + fprintf_fd(fd, " illegal si_code: %d\n", info->si_code); + break; } fprintf_fd(fd, " si_addr = %p\n", info->si_addr); } else if (signum == SIGBUS) { switch (info->si_code) { - case BUS_ADRALN: - fprintf_fd(fd, " invalid address alignment\n"); - break; - case BUS_ADRERR: - fprintf_fd(fd, " nonexistent physical address\n"); - break; - case BUS_OBJERR: - fprintf_fd(fd, " object-specific hardware error\n"); - break; - default: - fprintf_fd(fd, " illegal si_code: %d\n", info->si_code); - break; + case BUS_ADRALN: + fprintf_fd(fd, " invalid address alignment\n"); + break; + case BUS_ADRERR: + fprintf_fd(fd, " nonexistent physical address\n"); + break; + case BUS_OBJERR: + fprintf_fd(fd, " object-specific hardware error\n"); + break; + default: + fprintf_fd(fd, " illegal si_code: %d\n", info->si_code); + break; } fprintf_fd(fd, " si_addr: %p\n", info->si_addr); } @@ -653,7 +653,7 @@ void sighandler(int signum, siginfo_t *info, void *context) return; /* make crash info file name */ snprintf(timestr, sizeof(timestr), "%.10ld", cur_time); - snprintf(crashid, sizeof(crashid), "%s_%d",processname, pid); + snprintf(crashid, sizeof(crashid), "%s_%d", processname, pid); if (snprintf(filepath, PATH_LEN, "%s/%s.info", CRASH_INFO_PATH, crashid) == 0) { fprintf(stderr, @@ -773,10 +773,10 @@ void sighandler(int signum, siginfo_t *info, void *context) fprintf(stderr, "[sys-assert]can't open %s\n", TASK_PATH); } else { while (readdir_r(dir, &entry, &dentry) == 0) { - if( strcmp(dentry->d_name, ".") == 0 + if (strcmp(dentry->d_name, ".") == 0 || strcmp(dentry->d_name, "..") == 0) continue; - fprintf_fd(fd_cs, "%s ",dentry->d_name); + fprintf_fd(fd_cs, "%s ", dentry->d_name); } closedir(dir); fprintf_fd(fd_cs, "\n"); -- 2.7.4 From 77ffa5b7bba156d6e546e629af76fd9d18b77ea3 Mon Sep 17 00:00:00 2001 From: taeyoung Date: Thu, 28 Jul 2016 08:00:45 +0900 Subject: [PATCH 14/16] Revert "Revert "popup: disable crash popup"" This reverts commit 70cd339a94c42bee1d23d89a44081611a1fbd65c. Change-Id: I99b8b57a63f8bca3c88ba91c0752856fae9c839d Signed-off-by: taeyoung --- packaging/crash-worker.spec | 8 -------- 1 file changed, 8 deletions(-) diff --git a/packaging/crash-worker.spec b/packaging/crash-worker.spec index f4c0c46..90be22e 100644 --- a/packaging/crash-worker.spec +++ b/packaging/crash-worker.spec @@ -1,14 +1,6 @@ %define sys_assert on %define crash_popup off -%if "%{?profile}" == "mobile" -%define crash_popup on -%endif - -%if "%{?profile}" == "wearable" -%define crash_popup on -%endif - Name: crash-worker Summary: Crash-manager -- 2.7.4 From 2a4d9812907d7f88f12313bc2baadf4cb8d62385 Mon Sep 17 00:00:00 2001 From: Adrian Szyndela Date: Thu, 23 Jun 2016 14:56:54 +0200 Subject: [PATCH 15/16] crash-stack: Made default configuration without core dumps Crash-manager does not use crash-stack core dump configuration now. Core dump support needs libebl, which is not included in elfutils license exception. Thus, with core dump support, we would need to change license to GPL2. This patch disables core dumps support. It can be enabled by giving -DWITH_CORE_DUMP=ON to cmake (see crash-worker.spec for an example). Change-Id: Ic8ed970217c52b6dcbca8934d0d4ee4010245d77 --- packaging/crash-worker.spec | 7 +++++- src/crash-stack/CMakeLists.txt | 13 +++++++++-- src/crash-stack/crash-stack.c | 52 ++++++++++++++++++++++++++---------------- 3 files changed, 49 insertions(+), 23 deletions(-) diff --git a/packaging/crash-worker.spec b/packaging/crash-worker.spec index 90be22e..706308d 100644 --- a/packaging/crash-worker.spec +++ b/packaging/crash-worker.spec @@ -23,11 +23,13 @@ BuildRequires: libdw-devel libdw Requires(post): coreutils Requires(post): tar Requires(post): gzip -Requires: libebl Requires: libunwind %if %{?crash_popup} == on Requires: /usr/bin/dbus-send %endif +# If you need support for core dump files (see building below), +# you should add this dependency +# Requires: libebl %description crash-manager @@ -69,6 +71,9 @@ export CFLAGS+=" -Werror" -DCRASH_STACK_PATH=%{_libexecdir}/crash-stack \ -DCRASH_POPUP=%{crash_popup} \ -DSYS_ASSERT=%{sys_assert} +# to add support for core dump files add backslash at the end of above line +# and uncomment below line: +# -DWITH_CORE_DUMP=ON make %{?jobs:-j%jobs} diff --git a/src/crash-stack/CMakeLists.txt b/src/crash-stack/CMakeLists.txt index a95940f..b11c4d0 100644 --- a/src/crash-stack/CMakeLists.txt +++ b/src/crash-stack/CMakeLists.txt @@ -1,3 +1,4 @@ +option(WITH_CORE_DUMP "builds with support for core dump files (with GPL2 license)") set(CRASH_STACK_BIN "crash-stack") set(CRASH_STACK_SRCS crash-stack.c) @@ -8,7 +9,15 @@ else() endif() add_executable(${CRASH_STACK_BIN} ${CRASH_STACK_SRCS}) -set_property(TARGET ${CRASH_STACK_BIN} APPEND PROPERTY COMPILE_FLAGS "-DUPGRADE_ARM_STACK_UNWIND") -#set_property(TARGET ${CRASH_STACK_BIN} APPEND PROPERTY COMPILE_FLAGS "-DUPGRADE_ARM_STACK_UNWIND -DUNW_DEBUG") + +if (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "armv7l") + set_property(TARGET ${CRASH_STACK_BIN} APPEND_STRING PROPERTY COMPILE_FLAGS " -DUPGRADE_ARM_STACK_UNWIND") +# set_property(TARGET ${CRASH_STACK_BIN} APPEND_STRING PROPERTY COMPILE_FLAGS "-DUPGRADE_ARM_STACK_UNWIND -DUNW_DEBUG") +endif() + +if (${WITH_CORE_DUMP} STREQUAL "ON") + set_property(TARGET ${CRASH_STACK_BIN} APPEND_STRING PROPERTY COMPILE_FLAGS " -DWITH_CORE_DUMP") +endif() + target_link_libraries(${CRASH_STACK_BIN} dw elf ebl dl stdc++) install(TARGETS ${CRASH_STACK_BIN} DESTINATION libexec) diff --git a/src/crash-stack/crash-stack.c b/src/crash-stack/crash-stack.c index 321132c..609ac2f 100644 --- a/src/crash-stack/crash-stack.c +++ b/src/crash-stack/crash-stack.c @@ -2,7 +2,9 @@ #include #include #include +#ifdef WITH_CORE_DUMP #include +#endif #include #include #include @@ -55,7 +57,6 @@ static int module_callback(Dwfl_Module *module, void **userdata, mappings->elems++; } } - /* fprintf(errfile, "Got module %s @0x%llx\n", name, (long long)address);*/ return DWARF_CB_OK; } @@ -86,22 +87,6 @@ static void getvalue(Elf *core, const void *from, size_t size, void *to) fprintf(errfile, "failed to get value from core file\n"); } -static void updateMapping(Mappings *mappings, uint64_t mapping_start, uint64_t mapping_end, - uint64_t offset, const char *name) -{ - int i; - for (i = 0; i < mappings->elems; i++) { - if (mappings->tab[i].m_start == mapping_start) { - mappings->tab[i].m_end = mapping_end; - mappings->tab[i].m_name = name; - mappings->tab[i].m_offset = offset; - mappings->tab[i].m_fd = open(name, O_RDONLY); - mappings->tab[i].m_elf = elf_begin(mappings->tab[i].m_fd, ELF_C_READ_MMAP, NULL); - return; - } - } -} - static void parse_note_file(Elf *elf, const char *desc, uint64_t *values_cnt, uint64_t *page_size, size_t *addr_size, const char **values, const char **filenames) { @@ -244,7 +229,7 @@ static Dwfl *open_dwfl_with_pid(pid_t pid) return NULL; } -#if _ELFUTILS_PREREQ(0, 158) +#if _ELFUTILS_PREREQ(0,158) if (dwfl_linux_proc_attach(dwfl, pid, true) < 0) { fprintf(errfile, "process %d : dwfl attach failed (%s)\n", pid, dwfl_errmsg(-1)); dwfl_end(dwfl); @@ -254,6 +239,10 @@ static Dwfl *open_dwfl_with_pid(pid_t pid) return dwfl; } +/* + * This function will open core file regardless of WITH_CORE_DUMP setting. + * It may help with detecting issues with using dwfl even without support for dumps. + */ static Dwfl *open_dwfl_with_core(Elf *core, const char *core_file_name) { static const Dwfl_Callbacks core_callbacks = { @@ -269,7 +258,7 @@ static Dwfl *open_dwfl_with_core(Elf *core, const char *core_file_name) return NULL; } -#if _ELFUTILS_PREREQ(0, 158) +#if _ELFUTILS_PREREQ(0,158) if (dwfl_core_file_report(dwfl, core, NULL) < 0) #else if (dwfl_core_file_report(dwfl, core) < 0) @@ -280,7 +269,7 @@ static Dwfl *open_dwfl_with_core(Elf *core, const char *core_file_name) return NULL; } -#if _ELFUTILS_PREREQ(0, 158) +#if _ELFUTILS_PREREQ(0,158) if (dwfl_core_file_attach(dwfl, core) < 0) { fprintf(errfile, "%s : dwfl attach failed (%s)\n", core_file_name, dwfl_errmsg(-1)); dwfl_end(dwfl); @@ -315,8 +304,28 @@ static int get_registers_ptrace(pid_t pid) return 0; } +#ifdef WITH_CORE_DUMP +static void updateMapping(Mappings *mappings, uint64_t mapping_start, uint64_t mapping_end, + uint64_t offset, const char *name) +{ + int i; + for (i = 0; i < mappings->elems; i++) { + if (mappings->tab[i].m_start == mapping_start) { + mappings->tab[i].m_end = mapping_end; + mappings->tab[i].m_name = name; + mappings->tab[i].m_offset = offset; + mappings->tab[i].m_fd = open(name, O_RDONLY); + mappings->tab[i].m_elf = elf_begin(mappings->tab[i].m_fd, ELF_C_READ_MMAP, NULL); + return; + } + } +} +#endif + static Elf_Data *get_registers_core(Elf *core, const char *core_file_name, Mappings *mappings) { + Elf_Data *notes = NULL; +#ifdef WITH_CORE_DUMP GElf_Phdr mem; GElf_Phdr *phdr = gelf_getphdr(core, 0, &mem); @@ -421,6 +430,9 @@ static Elf_Data *get_registers_core(Elf *core, const char *core_file_name, Mappi pos = new_pos; } ebl_closebackend(ebl); +#else + fprintf(errfile, "Configured without support for core dump files\n"); +#endif return notes; } -- 2.7.4 From 269790304eea1bde27644962efa7803c7ab611df Mon Sep 17 00:00:00 2001 From: Adrian Szyndela Date: Thu, 23 Jun 2016 15:00:28 +0200 Subject: [PATCH 16/16] crash-stack: unwinding by frame pointer on aarch64 To unwind call stack on aarch64 we need to use external method, as libelf 0.153 does not support unwinding yet. Possible methods are: - using libunwind; - manual walk with frame pointers; - heuristic unwind by inspecting data stack. This patch adds support for unwinding on aarch64 with frame pointers, along with changes needed to modularize unwinding. Change-Id: Ib2cee21277f6bc500046bf6e9d70cf19a733dca8 --- src/crash-stack/CMakeLists.txt | 9 +- src/crash-stack/crash-stack-aarch64.c | 74 +++++++++++++++ src/crash-stack/crash-stack-arm.c | 129 +++++---------------------- src/crash-stack/crash-stack-libelf-helpers.c | 117 ++++++++++++++++++++++++ src/crash-stack/crash-stack-libelf.c | 35 +++++++- src/crash-stack/crash-stack-x86_64.c | 23 +++++ src/crash-stack/crash-stack.c | 26 +++--- src/crash-stack/crash-stack.h | 8 ++ 8 files changed, 299 insertions(+), 122 deletions(-) create mode 100644 src/crash-stack/crash-stack-aarch64.c create mode 100644 src/crash-stack/crash-stack-libelf-helpers.c create 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 b11c4d0..cd30bc3 100644 --- a/src/crash-stack/CMakeLists.txt +++ b/src/crash-stack/CMakeLists.txt @@ -1,11 +1,16 @@ option(WITH_CORE_DUMP "builds with support for core dump files (with GPL2 license)") set(CRASH_STACK_BIN "crash-stack") -set(CRASH_STACK_SRCS crash-stack.c) +set(CRASH_STACK_SRCS crash-stack.c crash-stack-libelf-helpers.c) if (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "armv7l") set(CRASH_STACK_SRCS ${CRASH_STACK_SRCS} crash-stack-arm.c wind/unwarm.c wind/unwarm_thumb.c wind/unwarm_arm.c wind/unwarmmem.c) else() - set(CRASH_STACK_SRCS ${CRASH_STACK_SRCS} crash-stack-libelf.c) + if (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64") + 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) + endif() endif() add_executable(${CRASH_STACK_BIN} ${CRASH_STACK_SRCS}) diff --git a/src/crash-stack/crash-stack-aarch64.c b/src/crash-stack/crash-stack-aarch64.c new file mode 100644 index 0000000..f9cac96 --- /dev/null +++ b/src/crash-stack/crash-stack-aarch64.c @@ -0,0 +1,74 @@ +#include "crash-stack.h" +#include +#include + +static struct user_regs_struct g_registers; + +struct Regs { + Dwarf_Addr x29; + Dwarf_Addr x30; + Dwarf_Addr pc; + Dwarf_Addr sp; +}; + +#define REG_SP 32 +#define REG_PC 33 +#define REG_X29 29 +#define REG_X30 30 + +typedef struct Regs Regs; +static Regs g_regs; + +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) +{ + struct user_regs_struct *regs = regbuf; + + memcpy(get_place_for_register_value("sp", 0), ®s->sp, sizeof(regs->sp)); + memcpy(get_place_for_register_value("pc", 0), ®s->pc, sizeof(regs->pc)); + memcpy(get_place_for_register_value("x29", 0), ®s->regs[29], sizeof(regs->regs[29])); + memcpy(get_place_for_register_value("x30", 0), ®s->regs[30], sizeof(regs->regs[30])); +} + +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; + + bool end = false; + + do { + uint64_t newx29, newx30; + bool read29 = crash_stack_libelf_read_value(dwfl, core, pid, + g_regs.x29, + &newx29, sizeof(newx29), mappings); + bool read30 = crash_stack_libelf_read_value(dwfl, core, pid, + g_regs.x29 + sizeof(newx29), + &newx30, sizeof(newx30), mappings); + if (read29 && read30) { + callstack->tab[callstack->elems++] = newx30; + g_regs.x29 = newx29; + } + else end = true; + } while (!end); +} + +void *get_place_for_register_value(const char *regname, int regnum) +{ + if (strcmp(regname, "pc") == 0 || REG_PC == regnum) + return &g_regs.pc; + else if (strcmp(regname, "sp") == 0 || REG_SP == regnum) + return &g_regs.sp; + else if (strcmp(regname, "x29") == 0 || REG_X29 == regnum) + return &g_regs.x29; + else if (strcmp(regname, "x30") == 0 || REG_X30 == regnum) + return &g_regs.x30; + return NULL; +} diff --git a/src/crash-stack/crash-stack-arm.c b/src/crash-stack/crash-stack-arm.c index c1d2628..acb3ead 100644 --- a/src/crash-stack/crash-stack-arm.c +++ b/src/crash-stack/crash-stack-arm.c @@ -3,6 +3,7 @@ #include #include +#include static Elf *g_core = NULL; static Dwfl *g_dwfl = NULL; @@ -20,6 +21,15 @@ struct Regs { typedef struct Regs Regs; static Regs g_regs; +static struct user_regs g_ptrace_registers; + +void *crash_stack_get_memory_for_ptrace_registers(size_t *size) +{ + if (NULL != size) + *size = sizeof(g_ptrace_registers); + return &g_ptrace_registers; +} + void *get_place_for_register_value(const char *regname, int regnum) { if (strcmp(regname, "pc") == 0 || REG_PC == regnum) @@ -35,6 +45,17 @@ void *get_place_for_register_value(const char *regname, int regnum) return NULL; } +void crash_stack_set_ptrace_registers(void *regbuf) +{ + struct user_regs *registers = regbuf; + int i; + for (i = 0; i < sizeof(registers->uregs)/sizeof(registers->uregs[0]); i++) { + void *regmem = get_place_for_register_value("", i); + if (NULL != regmem) + memcpy(regmem, ®isters->uregs[i], sizeof(registers->uregs[i])); + } +} + static Boolean report(void *data, Int32 address) { Callstack *callstack = (Callstack *)(data); @@ -45,68 +66,7 @@ static Boolean report(void *data, Int32 address) Boolean readT(Int32 a, void *v, size_t size) { - Dwfl_Module *module = 0; - Elf_Data *data = NULL; - - int segment = dwfl_addrsegment(g_dwfl, a, &module); - - if (module != NULL) { - Dwarf_Addr start; - dwfl_module_info(module, NULL, &start, NULL, NULL, NULL, NULL, NULL); - - GElf_Addr bias; - Elf *elf = dwfl_module_getelf(module, &bias); - - data = elf_getdata_rawchunk(elf, a-start, size, ELF_T_BYTE); - } - if (NULL == data && segment != -1) { - // get data from segment - GElf_Phdr mem; - GElf_Phdr *phdr; - Dwarf_Addr offset_in_segment; - - phdr = gelf_getphdr(g_core, segment, &mem); - if (phdr != NULL) { - offset_in_segment = a - phdr->p_vaddr; - if (offset_in_segment < phdr->p_filesz) { - Dwarf_Addr offset_in_file = phdr->p_offset + offset_in_segment; - - data = elf_getdata_rawchunk(g_core, offset_in_file, size, ELF_T_BYTE); - } - } - } - - if (NULL == data && module != NULL) { - const char *name = dwfl_module_info(module, NULL, NULL, NULL, NULL, NULL, NULL, NULL); - if (name != NULL && name[0] == '[') { - int i; - // get module from mappings - for (i = 0; i < g_mappings->elems; i++) { - if (g_mappings->tab[i].m_start <= a && a < g_mappings->tab[i].m_end) { - // compute offset relative to the start of the mapping - Int32 offset = a - g_mappings->tab[i].m_start; - // read from the file, but also account file offset - data = elf_getdata_rawchunk(g_mappings->tab[i].m_elf, - offset + g_mappings->tab[i].m_offset, size, ELF_T_BYTE); - break; - } - } - } - } - - if (data != NULL) { - memcpy(v, data->d_buf, size); - return TRUE; - } - - /* Still no data, but we have a process - read memory with ptrace */ - if (NULL == data && g_pid > 1) { - long val = ptrace(PTRACE_PEEKDATA, g_pid, a, NULL); - memcpy(v, &val, size); - return TRUE; - } - - return FALSE; + return crash_stack_libelf_read_value(g_dwfl, g_core, g_pid, a, v, size, g_mappings); } static Boolean readW(Int32 a, Int32 *v) @@ -126,50 +86,7 @@ static Boolean readB(Int32 a, Int8 *v) static Int32 getProloguePC(Int32 current_pc) { - Int32 result = 0; - Dwfl_Module *module = dwfl_addrmodule(g_dwfl, current_pc); - if (module) { - // GElf_Off offset; - GElf_Sym sym; - // dwfl_module_addrinfo (module, current_pc, &offset, &sym, NULL, NULL, NULL); - dwfl_module_addrsym(module, current_pc, &sym, NULL); - // result = current_pc - offset; - result = sym.st_value; - } - if (0 == result) { - int i; - for (i = 0; i < g_mappings->elems; i++) { - if (g_mappings->tab[i].m_start <= current_pc && current_pc < g_mappings->tab[i].m_end) { - /* go through symbols to find the nearest */ - Elf_Scn *scn = NULL; - Elf *elf = g_mappings->tab[i].m_elf; - 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 = current_pc; - if (shdr->sh_type == SHT_DYNSYM) - address_offset -= g_mappings->tab[i].m_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) - return sym->st_value; - } - } - } - } - } - } - } - return result; + return crash_stack_libelf_get_prologue_pc(g_dwfl, current_pc, g_mappings); } void create_crash_stack(Dwfl *dwfl, Elf *core, pid_t pid, Mappings *mappings, Callstack *callstack) diff --git a/src/crash-stack/crash-stack-libelf-helpers.c b/src/crash-stack/crash-stack-libelf-helpers.c new file mode 100644 index 0000000..7dab540 --- /dev/null +++ b/src/crash-stack/crash-stack-libelf-helpers.c @@ -0,0 +1,117 @@ +#include "crash-stack.h" +#include +#include +#include + +bool crash_stack_libelf_read_value(Dwfl *dwfl, Elf *core, pid_t pid, + Dwarf_Addr a, void *v, size_t size, + Mappings *mappings) +{ + Dwfl_Module *module = 0; + Elf_Data *data = NULL; + + int segment = dwfl_addrsegment(dwfl, a, &module); + + if (module != NULL) { + Dwarf_Addr start; + dwfl_module_info(module, NULL, &start, NULL, NULL, NULL, NULL, NULL); + + GElf_Addr bias; + Elf *elf = dwfl_module_getelf(module, &bias); + + data = elf_getdata_rawchunk(elf, a-start, size, ELF_T_BYTE); + } + if (NULL == data && segment != -1) { + // get data from segment + GElf_Phdr mem; + GElf_Phdr *phdr = gelf_getphdr(core, segment, &mem); + Dwarf_Addr offset_in_segment = a - phdr->p_vaddr; + if (offset_in_segment < phdr->p_filesz) { + Dwarf_Addr offset_in_file = phdr->p_offset + offset_in_segment; + + data = elf_getdata_rawchunk(core, offset_in_file, size, ELF_T_BYTE); + } + } + + if (NULL == data && module != NULL) { + const char *name = dwfl_module_info(module, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + if (name != NULL && name[0] == '[') { + int i; + // get module from mappings + for (i = 0; i < mappings->elems; i++) { + if (mappings->tab[i].m_start <= a && a < mappings->tab[i].m_end) { + // compute offset relative to the start of the mapping + long offset = a - mappings->tab[i].m_start; + // read from the file, but also account file offset + data = elf_getdata_rawchunk(mappings->tab[i].m_elf, + offset + mappings->tab[i].m_offset, size, ELF_T_BYTE); + break; + } + } + } + } + + if (data != NULL) { + memcpy(v, data->d_buf, size); + return true; + } + + /* Still no data, but we have a process - read memory with ptrace */ + /* FIXME need to know if we are still in the mapped area */ + /* Bigger issue is that dwfl does not have modules */ + if (pid > 1) { + long val = ptrace(PTRACE_PEEKDATA, pid, a, NULL); + if (-1 == val && errno) + return false; + memcpy(v, &val, size); + return true; + } + + return false; +} + +Dwarf_Addr crash_stack_libelf_get_prologue_pc(Dwfl *dwfl, Dwarf_Addr current_pc, Mappings *mappings) +{ + Dwarf_Addr result = 0; + Dwfl_Module *module = dwfl_addrmodule(dwfl, current_pc); + if (module) { + GElf_Sym sym; + dwfl_module_addrsym(module, current_pc, &sym, NULL); + result = sym.st_value; + } + if (0 == result) { + int i; + for (i=0; i < mappings->elems; i++) { + if (mappings->tab[i].m_start <= current_pc && current_pc < mappings->tab[i].m_end) { + /* go through symbols to find the nearest */ + Elf_Scn *scn = NULL; + Elf *elf = mappings->tab[i].m_elf; + 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 = current_pc; + if (shdr->sh_type == SHT_DYNSYM) + address_offset -= mappings->tab[i].m_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) { + return sym->st_value; + } + } + } + } + } + } + } + } + return result; +} diff --git a/src/crash-stack/crash-stack-libelf.c b/src/crash-stack/crash-stack-libelf.c index f4c10bc..b152bea 100644 --- a/src/crash-stack/crash-stack-libelf.c +++ b/src/crash-stack/crash-stack-libelf.c @@ -1,6 +1,16 @@ #include "crash-stack.h" #include #include +#include + +typedef union { + uint16_t reg16; + uint32_t reg32; + uint64_t reg64; +} Register; + +static Register g_pc; +static Register g_sp; #if _ELFUTILS_PREREQ(0, 158) static int frame_callback(Dwfl_Frame *state, void *arg) @@ -19,9 +29,32 @@ static int thread_callback(Dwfl_Thread *thread, void *thread_arg) } #endif +static const char *pc_names[] = { + "pc", "rip", "eip", "ip" +}; + +static const char *sp_names[] = { + "sp", "rsp", "esp" +}; + +static bool is_in(const char *name, const char **names, int elems) +{ + int nit; + for (nit = 0; nit < elems; ++nit) { + if (strcmp(name, names[nit]) == 0) + return true; + } + return false; +} + +#define IS_IN(name,names) is_in((name), (names), sizeof(names)/sizeof(names[0])) + void *get_place_for_register_value(const char *regname, int regnum) { - return 0; + if (IS_IN(regname, pc_names)) return &g_pc; + else if (IS_IN(regname, sp_names)) return &g_sp; + + return 0; } void create_crash_stack(Dwfl *dwfl, Elf *core, pid_t pid, Mappings *mappings, Callstack *callstack) diff --git a/src/crash-stack/crash-stack-x86_64.c b/src/crash-stack/crash-stack-x86_64.c new file mode 100644 index 0000000..934ee72 --- /dev/null +++ b/src/crash-stack/crash-stack-x86_64.c @@ -0,0 +1,23 @@ +#include "crash-stack.h" +#include +#include + +struct user_regs_struct g_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)); +} diff --git a/src/crash-stack/crash-stack.c b/src/crash-stack/crash-stack.c index 609ac2f..916f645 100644 --- a/src/crash-stack/crash-stack.c +++ b/src/crash-stack/crash-stack.c @@ -62,9 +62,19 @@ static int module_callback(Dwfl_Module *module, void **userdata, static void getvalue(Elf *core, const void *from, size_t size, void *to) { + Elf_Type type = ELF_T_BYTE; + switch (size) { + case 8: type = ELF_T_BYTE; break; + case 16: type = ELF_T_HALF; break; + case 32: type = ELF_T_WORD; break; + case 64: type = ELF_T_XWORD; break; + default: + fprintf(stderr, "getvalue for strange size: %llu\n", (unsigned long long)size); + break; + } Elf_Data out = { .d_buf = to, - .d_type = size == 32 ? ELF_T_WORD : ELF_T_XWORD, + .d_type = type, .d_version = EV_CURRENT, .d_size = size/8, .d_off = 0, @@ -282,25 +292,15 @@ static Dwfl *open_dwfl_with_core(Elf *core, const char *core_file_name) static int get_registers_ptrace(pid_t pid) { struct iovec data; - uintptr_t regbuf[20]; - - data.iov_base = regbuf; - data.iov_len = sizeof(regbuf); + data.iov_base = crash_stack_get_memory_for_ptrace_registers( &data.iov_len ); 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); + crash_stack_set_ptrace_registers(data.iov_base); - if (NULL != reg) - memcpy(reg, ®buf[i], sizeof(regbuf[i])); - } return 0; } diff --git a/src/crash-stack/crash-stack.h b/src/crash-stack/crash-stack.h index bf712c0..195bce5 100644 --- a/src/crash-stack/crash-stack.h +++ b/src/crash-stack/crash-stack.h @@ -31,4 +31,12 @@ typedef struct Mappings { void *get_place_for_register_value(const char *regname, int regnum); void create_crash_stack(Dwfl *dwfl, Elf *core, pid_t pid, Mappings *mappings, Callstack *callstack); +Dwarf_Addr crash_stack_libelf_get_prologue_pc(Dwfl *dwfl, Dwarf_Addr current_pc, Mappings *mappings); +bool crash_stack_libelf_read_value(Dwfl *dwfl, Elf *core, pid_t pid, + Dwarf_Addr a, void *v, size_t size, + Mappings *mappings); + +void *crash_stack_get_memory_for_ptrace_registers(size_t *size); +void crash_stack_set_ptrace_registers(void *regbuf); + #endif /* CRASH_STACK_H */ -- 2.7.4