From: HyungKyu Song Date: Fri, 15 Feb 2013 15:16:47 +0000 (+0900) Subject: Tizen 2.0 Release X-Git-Tag: submit/tizen_2.0/20130215.191808^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fheads%2Ftizen_2.0;p=platform%2Fcore%2Fsystem%2Fsys-assert.git Tizen 2.0 Release --- diff --git a/AUTHORS b/AUTHORS new file mode 100755 index 0000000..2190840 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,3 @@ +juho son +Suchang Woo +kyungmin Park diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..d79cf8d --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,8 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) + +ADD_SUBDIRECTORY(sys-assert) +ADD_SUBDIRECTORY(core-launcher) + +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/coredumpctrl.sh DESTINATION /usr/bin + PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE + GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) diff --git a/LICENSE.APLv2 b/LICENSE.APLv2 new file mode 100755 index 0000000..8aa906c --- /dev/null +++ b/LICENSE.APLv2 @@ -0,0 +1,205 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. + + + diff --git a/NOTICE b/NOTICE new file mode 100755 index 0000000..0e0f016 --- /dev/null +++ b/NOTICE @@ -0,0 +1,3 @@ +Copyright (c) Samsung Electronics Co., Ltd. All rights reserved. +Except as noted, this software is licensed under Apache License, Version 2. +Please, see the LICENSE.APLv2 file for Apache License terms and conditions. diff --git a/core-launcher/CMakeLists.txt b/core-launcher/CMakeLists.txt new file mode 100644 index 0000000..e285bac --- /dev/null +++ b/core-launcher/CMakeLists.txt @@ -0,0 +1,37 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(core-launcher C) + +SET(PROJECT_NAME "core-launcher") +SET(SRCS core-launcher.c) + +IF("${CMAKE_BUILD_TYPE}" STREQUAL "") + SET(CMAKE_BUILD_TYPE "Release") +ENDIF("${CMAKE_BUILD_TYPE}" STREQUAL "") +MESSAGE("Build type: ${CMAKE_BUILD_TYPE}") + +FOREACH(flag ${pkgs-common_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fpie") + +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_DEFINITIONS("-DPREFIX=\"${CMAKE_INSTALL_PREFIX}\"") +ADD_DEFINITIONS("-DEAPI") +ADD_DEFINITIONS("-DDEBUG_ON") + +SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -pie") + +ADD_EXECUTABLE(${PROJECT_NAME} ${SRCS}) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs-common_LDFLAGS}) + +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION bin) diff --git a/core-launcher/core-launcher.c b/core-launcher/core-launcher.c new file mode 100644 index 0000000..c1d468e --- /dev/null +++ b/core-launcher/core-launcher.c @@ -0,0 +1,276 @@ +/* + * CORE-LAUNCHER + * 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 +#include +#include +#include +#include +#include +#include +#include + +#define CRASH_NOTI_DIR "/opt/share/crash" +#define CRASH_NOTI_FILE "curbs.log" +#define CRASH_NOTI_PATH CRASH_NOTI_DIR"/"CRASH_NOTI_FILE + +#define CRASH_CHECK_COREDUMP_NUM (10) +#define CRASH_CHECK_SIZE (1024 * 512) +#define CRASH_CHECK_DISK_PATH "/opt/usr" +#define CRASH_INFO_PATH "/opt/share/crash/info" +#define CRASH_CORE_PATH "/opt/usr/share/crash/core" +#define CRASH_SAVE_PATH "/opt/usr/share/crash" +#define CRASH_DUMP_PATH "/opt/usr/share/crash/dump" +#define CRASH_REPORT_PATH "/opt/usr/share/crash/report" + +#define TIZEN_OPT_USR_MOUNT "/dev/mmcblk0p7" +#define TIZEN_OPT_USR_TYPE "ext4" + +#define CRASH_TIME_MAX 65 +#define CRASH_INFO_EXPAND_SIZE 5 +#define CRASH_CORE_INFO_MATCH_TIMEGAP 10 +#define BUF_SIZE 1024 +#define PATH_MAX 4096 + +#define DEBUG_CORE_LAUNCHER + +static ssize_t safewrite(int fd, const void *buf, size_t count) +{ + ssize_t n; + do { + n = write(fd, buf, count); + } while (n < 0 && errno == EINTR); + return n; +} + +static bool _check_previous_coredump_num(char *check_dir, int check_num) +{ + DIR *dp; + struct dirent *de; + int count = 0; + + if (check_dir == NULL) + return false; + if (check_num == 0) + return true; + dp = opendir(check_dir); + if (dp == NULL) { + fprintf(stderr, "error opendir %s\n", check_dir); + return false; + } + while (de = readdir(dp)) { + if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) + continue; + if (de->d_ino != 0 ) + count++; + } + closedir(dp); + if (check_num < count) + return false; + else + return true; +} +/* check disk available size */ +static bool _check_disk_available(char *mount_dir, int check_size) +{ + struct statfs lstatfs; + + if (mount_dir == NULL) + return false; + if (check_size == 0) + return true; + if (statfs(mount_dir, &lstatfs) < 0) { + fprintf(stderr, "can't get statfs %s\n", mount_dir); + return false; + } else { + if (check_size <= + lstatfs.f_bavail * (lstatfs.f_bsize/1024)) { + return true; + } else { + fprintf(stderr, "NO %d < %d\n", check_size, + (int)(lstatfs.f_bavail * (lstatfs.f_bsize/1024))); + return false; + } + } +} +static bool _check_crash_name_timesec(char *filename, + char *pid, char *timesec) +{ + if (filename == NULL || pid == NULL || timesec == NULL) + return false; + int pid_len = 0; + int times_len = 0; + long infotime = 0; + long coretime = 0; + long timegap = 0; + char tbuf[CRASH_TIME_MAX] = {0, }; + int len = strlen(filename); + int i = 0; + for (i = 0; i < len; i++) { + if (filename[i] == '_') { + pid_len = i; + times_len = len - i - CRASH_INFO_EXPAND_SIZE; + break; + } + } + if (!strncmp(pid, filename, i)) { + strncpy(tbuf, &(filename[i+1]), times_len); + infotime = atol(tbuf); + coretime = atol(timesec); + timegap = labs(infotime - coretime); + if (timegap < CRASH_CORE_INFO_MATCH_TIMEGAP) + return true; + return false; + } + return false; +} +static bool check_crash_libsysinfo(char *pid, char *timesec) +{ + DIR *dp; + struct dirent *de; + dp = opendir(CRASH_INFO_PATH); + if (dp == NULL) { + fprintf(stderr, "error opendir %s\n", CRASH_INFO_PATH); + return false; + } + while (de = readdir(dp)) { + if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) + continue; + if (_check_crash_name_timesec(de->d_name, + pid, timesec) == 1) { + closedir(dp); + return true; + } + } + closedir(dp); + return false; +} +/* + * 1 2 3 4 + * %e %t %p %s + */ +int main(int argc, char *argv[]) +{ + int fd_curbs; /* for inotify */ + int fd_coredump; /* for core dump */ + char buf[BUF_SIZE]; + int i; + bool haveinfo = false; + bool filesaveon = false; + int corefilesize = 0; + char corefile[PATH_MAX] = {0, }; /* corefile buf */ + char notimsg[BUF_SIZE] = {0, }; /* crash noti message */ + ssize_t nread; + const unsigned long mntflags = 0; +#ifdef DEBUG_CORE_LAUNCHER + FILE *tfp; + char cwd[PATH_MAX]; + snprintf(cwd, PATH_MAX, + "/tmp/%s_%s_%s_%s.info", + argv[1], argv[2], argv[3], argv[4]); + tfp = fopen(cwd, "w+"); + if (tfp == NULL) + exit(EXIT_FAILURE); + fprintf(tfp, "argc=%d\n", argc); + for (i = 0; i < argc; i++) + fprintf(tfp, "argc[%d]=<%s>\n", i, argv[i]); +#endif + /* check that process name is crash-worker or crash-popup, because prevent infinite called */ + if (!strcmp(argv[1], "crash-worker") || !strcmp(argv[1], "crash-popup")) { +#ifdef DEBUG_CORE_LAUNCHER + fclose(tfp); +#endif + exit(EXIT_SUCCESS); + } + /* check already know crash is reported and triggerd by libsys-assert lib */ + haveinfo = check_crash_libsysinfo(argv[3], argv[2]); + /* check core dump path for saving */ + if (access(CRASH_CORE_PATH, F_OK) != 0) { + /* if can't access core dump path, try mount that */ + if (mount(TIZEN_OPT_USR_MOUNT, + CRASH_CHECK_DISK_PATH, + TIZEN_OPT_USR_TYPE, mntflags, NULL) != 0) + sleep(2); + else + filesaveon = true; + + /* one more check core dump path for saving */ + if (access(CRASH_CORE_PATH, F_OK) != 0) + filesaveon = false; + } else + filesaveon = true; + + /* check that disk extra sapce is available */ + if (_check_disk_available(CRASH_CHECK_DISK_PATH, + CRASH_CHECK_SIZE) == true) { + /* check previous coredump file number, + because if system_server was dead, + crash-worker didn't working. + so coredump stacked an unlimited number*/ + filesaveon = _check_previous_coredump_num(CRASH_CORE_PATH, + CRASH_CHECK_COREDUMP_NUM); + } + + if (filesaveon == true) { + snprintf(corefile, PATH_MAX, + "%s/%s_%s_%s.core", + CRASH_CORE_PATH, argv[3], argv[4], argv[1]); + fd_coredump = open(corefile, O_WRONLY | O_SYNC | O_CREAT | O_TRUNC, 0644); + if (fd_coredump < 0) { + fprintf(stderr, + "[core-launcher]cannot open core dump file!\n"); + } else { + corefilesize = 0; + while ((nread = read(STDIN_FILENO, buf, BUF_SIZE)) > 0) { + corefilesize += nread; + safewrite(fd_coredump, buf, nread); + } + fsync(fd_coredump); + close(fd_coredump); + } + } + + if (haveinfo == false) { + /* NOTIFY CRASH */ + fd_curbs = open(CRASH_NOTI_PATH, O_RDWR | O_APPEND); + if (fd_curbs < 0) { + fprintf(stderr, + "[core-launcher]cannot make %s !\n", + CRASH_NOTI_PATH); + } else { + snprintf(notimsg, BUF_SIZE, + "C|%s|%s|%s|%s|%d\n", + argv[1], argv[2], argv[3], argv[4], strlen(argv[1]) + strlen(argv[4])); + write(fd_curbs, notimsg, strlen(notimsg)); + close(fd_curbs); + } + } +#ifdef DEBUG_CORE_LAUNCHER + fprintf(tfp, "haveinfo check(%d) %s %s\n", haveinfo, argv[1], argv[2]); + if (filesaveon == true) + fprintf(tfp, "Total bytes in core dump: %d\n", corefilesize); + else + fprintf(tfp, "We didn't save core dump\n"); + fclose(tfp); +#endif + exit(EXIT_SUCCESS); +} + diff --git a/coredumpctrl.sh b/coredumpctrl.sh new file mode 100755 index 0000000..52a9065 --- /dev/null +++ b/coredumpctrl.sh @@ -0,0 +1,47 @@ +#!/bin/sh +MODE=none +VAL=none +#echo "tizen_platform_coredump_control" +case "$1" in +get) + MODE=get +;; +set) + MODE=set +;; + +*) +echo "Usage: coredumpctrl.sh {get|set} {1|0}" +exit 1 +esac + +if [ "$MODE" = "set" ]; then + case "$2" in + 1) + VAL=1 + ;; + 0) + VAL=0 + ;; + *) + echo "Usage: coredumpctrl.sh {get|set} {1|0}" + exit 1 + esac +fi + +if [ "$MODE" = "set" ]; then + if [ "$VAL" = "1" ] ; then + touch /opt/etc/.coredump 2>/dev/null + elif [ "$VAL" = "0" ] ; then + rm -f /opt/etc/.coredump 2>/dev/null + fi + echo "You must reboot this target to apply the change!" +else + if [ -e "/opt/etc/.coredump" ]; then + echo 1 + else + echo 0 + fi +fi + +exit 0 diff --git a/packaging/sys-assert.spec b/packaging/sys-assert.spec new file mode 100644 index 0000000..238c712 --- /dev/null +++ b/packaging/sys-assert.spec @@ -0,0 +1,60 @@ +Name: sys-assert +Summary: libsys-assert (shared object). +Version: 0.3.2 +Release: 5 +Group: Framework/system +License: Apache License, Version 2.0 +Source0: %{name}-%{version}.tar.gz + +BuildRequires: pkgconfig(glib-2.0) +BuildRequires: cmake +Requires(post): coreutils + +%description +libsys-assert (shared object). + +%prep +%setup -q + +%build +export CFLAGS+=" -fPIC" +%ifarch %{arm} + export CFLAGS+=" -DTARGET" +%endif + +cmake . -DCMAKE_INSTALL_PREFIX=/usr + +make %{?jobs:-j%jobs} + +%install +rm -rf %{buildroot} +%make_install +mkdir -p %{buildroot}/usr/share/license +cp LICENSE.APLv2 %{buildroot}/usr/share/license/%{name} +%post +/sbin/ldconfig +mkdir -p /opt/share/crash/info +chown root:crash /opt/share/crash/info +chmod 775 /opt/share/crash/info + +chown root:crash /opt/share/crash +chmod 775 /opt/share/crash + +if [ -f %{_libdir}/rpm-plugins/msm.so ]; then + find /opt/share/crash -print0 | xargs -0 chsmack -a 'sys-assert::core' + find /opt/share/crash -type d -print0 | xargs -0 chsmack -t +fi + +if [ ! -d /.build ]; then + echo "/usr/lib/libsys-assert.so" >> /etc/ld.so.preload + chmod 644 /etc/ld.so.preload +fi + +%files +%manifest sys-assert.manifest +%{_bindir}/coredumpctrl.sh +%{_bindir}/core-launcher +%{_libdir}/libsys-assert.so +/usr/share/license/%{name} + + diff --git a/sys-assert.manifest b/sys-assert.manifest new file mode 100644 index 0000000..2b983c7 --- /dev/null +++ b/sys-assert.manifest @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + diff --git a/sys-assert/CMakeLists.txt b/sys-assert/CMakeLists.txt new file mode 100644 index 0000000..afba01d --- /dev/null +++ b/sys-assert/CMakeLists.txt @@ -0,0 +1,40 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(sys-assert C) + +SET(SRCS + src/sys-assert.c +) + +SET(PREFIX ${CMAKE_INSTALL_PREFIX}) +SET(LIBDIR "\${prefix}/lib") + +IF("${CMAKE_BUILD_TYPE}" STREQUAL "") + SET(CMAKE_BUILD_TYPE "Release") +ENDIF("${CMAKE_BUILD_TYPE}" STREQUAL "") +MESSAGE("Build type: ${CMAKE_BUILD_TYPE}") + +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src) + +FOREACH(flag ${pkgs_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_DEFINITIONS("-DPREFIX=\"${PREFIX}\"") +ADD_DEFINITIONS("-DEAPI") +ADD_DEFINITIONS("-DDEBUG_ON") + +ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS}) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_LDFLAGS} -ldl) + +INSTALL(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION lib) diff --git a/sys-assert/src/sys-assert.c b/sys-assert/src/sys-assert.c new file mode 100755 index 0000000..48608fc --- /dev/null +++ b/sys-assert/src/sys-assert.c @@ -0,0 +1,1246 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* for PR_SET_DUMPABLE */ +#include +#include "sys-assert.h" + +#define CMDLINE_PATH "/proc/self/cmdline" +#define DBG_DIR "/usr/lib/debug" +#define EXE_PATH "/proc/self/exe" +#define MAPS_PATH "/proc/self/maps" +#define MEMINFO_PATH "/proc/meminfo" +#define STATUS_PATH "/proc/self/status" + +#define CRASH_INFO_PATH "/opt/share/crash/info" +#define CRASH_REPORT_PATH "/opt/usr/share/crash/report" +#define CRASH_NOTI_PATH "/opt/share/crash/curbs.log" + +#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_REGISTERINFO_TITLE "Register Information" + +#define SUPPORT_LIBC_BACKTRACE 1 +#define USE_SYMBOL_DB 1 +#define FUNC_NAME_MAX_LEN 128 +#define FILE_LEN 255 +#define PATH_LEN (FILE_LEN + NAME_MAX) +#define BUF_SIZE 255 +#define CALLSTACK_SIZE 100 +/* 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[] = { /* SIGHUP, SIGINT, SIGQUIT, */ SIGILL, /*SIGTRAP, */ + SIGABRT, /*SIGIOT, */SIGBUS, + SIGFPE, /*SIGKILL, SIGUSR1 */ SIGSEGV, /*SIGUSR2, */ + SIGPIPE /*SIGXCPU,SIGXFSZ,,, */ +}; +#define NUM_SIG_TO_HANDLE \ + ((int)(sizeof(sig_to_handle)/sizeof(sig_to_handle[0]))) + +struct sigaction g_oldact[NUM_SIG_TO_HANDLE]; + +static char *fgets_fd(char *s, int n, int fd) +{ + char c; + register char *cs; + int num = 0; + + cs = s; + while (--n > 0 && (num = read(fd, &c, 1) > 0)) { + if ((*cs++ = c) == '\n') + break; + } + *cs = '\0'; + return (num == 0 && cs == s) ? NULL : s; +} + +/* WARNING : formatted string buffer is limited to 1024 byte */ +static int fprintf_fd(int fd, const char *fmt, ...) +{ + int n; + char buff[1024]; + va_list args; + + va_start(args, fmt); + n = vsnprintf(buff, 1024 - 1, fmt, args); + write(fd, buff, n); + va_end(args); + return n; +} +static char *remove_path(const char *cmd) +{ + char *t; + char *r; + + t = r = (char *)cmd; + while (*t) { + if (*t == '/') + r = t + 1; + t++; + } + return r; +} + +static 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 (t_node) { + if (t_node->endaddr <= value) { + /* next node */ + if (n_node == NULL) + return NULL; + t_node = n_node; + n_node = n_node->next; + } else if (t_node->startaddr <= value) + return t_node->fpath; + else + return NULL; + } +} + +static 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 (t_node) { + if (t_node->endaddr <= value) { + /* next node */ + if (n_node == NULL) + return NULL; + t_node = n_node; + n_node = n_node->next; + } else if (t_node->startaddr <= value) + return t_node->startaddr; + else + return NULL; + } +} + +#ifdef TARGET +/* get function symbol from elf */ +static int +trace_symbols(void *const *array, int size, struct addr_node *start, int fd_cs) +{ + int cnt; + Dl_info info_funcs; +#ifndef USE_SYMBOL_DB + int i; + Elf32_Ehdr elf_h; + Elf32_Shdr *s_headers; + int strtab_index = 0; + int symtab_index = 0; + int num_st = 0; + Elf32_Sym *symtab_entry; + int fd; + int ret; + char filename[256]; +#endif + unsigned int offset_addr; + unsigned int start_addr; + unsigned int addr; + + for (cnt = 0; cnt < size; cnt++) { +#ifndef USE_SYMBOL_DB + num_st = 0; +#endif + /* 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_cs, "%2d: (%p)\n", cnt, array[cnt]); + + 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 == (void *)0x8000 + && + (strncmp("/opt/apps/", info_funcs.dli_fname, + strlen("/opt/apps/")) == 0)) { + fprintf(stderr, + "[sys-assert][%d] fname = %s, fbase = %p, sname = %s, saddr = %p\n", + cnt, info_funcs.dli_fname, + info_funcs.dli_fbase, + info_funcs.dli_sname, info_funcs.dli_saddr); + info_funcs.dli_fname = get_fpath(array[cnt], start); + offset_addr = addr; + fprintf(stderr, + "[sys-assert][%d] start_addr : %x, addr : %x, offset_addr : %x\n", + cnt, start_addr, addr, offset_addr); + } else { + offset_addr = addr - start_addr; + } + if (info_funcs.dli_sname == NULL) { +#ifndef USE_SYMBOL_DB +/*FIXME : get dbg file name from debuglink and search dbg file in DBG_DIR */ + strcpy(filename, DBG_DIR); + strncat(filename, info_funcs.dli_fname, 128); + fd = open(filename, O_RDONLY); + if (fd < 0) { + fprintf_fd(fd_cs, + "%2d: (%p) [%s]+%p\n", + cnt, array[cnt], + info_funcs.dli_fname, offset_addr); + continue; + } + ret = read(fd, &elf_h, sizeof(Elf32_Ehdr)); + if (ret < sizeof(Elf32_Ehdr)) { + fprintf(stderr, + "[sys-assert]readnum = %d, [%s]\n", + ret, info_funcs.dli_fname); + fprintf_fd(fd_cs, + "%2d: (%p) [%s]+%p\n", + cnt, array[cnt], + info_funcs.dli_fname, offset_addr); + 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_cs, + "%2d: (%p) [%s]+%p\n", + cnt, array[cnt], + info_funcs.dli_fname, offset_addr); + continue; + } + lseek(fd, elf_h.e_shoff, SEEK_SET); + if (elf_h.e_shentsize > sizeof(Elf32_Shdr)) + return false; + for (i = 0; i < elf_h.e_shnum; i++) { + ret = + read(fd, &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)); + return false; + } + } + for (i = 0; i < elf_h.e_shnum; i++) { +/* find out .symtab Section index */ + if (s_headers[i].sh_type == SHT_SYMTAB) { + symtab_index = i; + num_st = + s_headers[i].sh_size / + s_headers[i].sh_entsize; +/* number of .symtab entry */ + break; + } + } + /*.strtab index */ + strtab_index = s_headers[symtab_index].sh_link; + 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)); + return false; + } + lseek(fd, s_headers[symtab_index].sh_offset, SEEK_SET); + for (i = 0; i < num_st; i++) { + ret = + read(fd, &symtab_entry[i], + sizeof(Elf32_Sym)); + if (ret < sizeof(Elf32_Sym)) { + fprintf(stderr, + "[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) { + lseek(fd, + s_headers + [strtab_index].sh_offset + + symtab_entry[i].st_name, + SEEK_SET); + info_funcs.dli_sname = (void *) + mmap(0, + FUNC_NAME_MAX_LEN, + PROT_READ + | + PROT_WRITE, + MAP_PRIVATE + | + MAP_ANONYMOUS, -1, 0); + ret = + read(fd, + info_funcs.dli_sname, + FUNC_NAME_MAX_LEN); + 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(fd); +#endif + fprintf_fd(fd_cs, "%2d: (%p) [%s]+%p\n", + cnt, array[cnt], + info_funcs.dli_fname, offset_addr); + } else { + + if (array[cnt] >= info_funcs.dli_saddr) { + fprintf_fd(fd_cs, + "%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_cs, + "%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); + } + } + } + return true; +} +#endif +/* get address list from maps with print to file */ +static struct addr_node *get_addr_list_from_maps_with_print(int fd_maps, int fd) +{ + int result; + char linebuf[BUF_SIZE]; + char addr[20]; + char perm[5]; + char path[PATH_LEN]; + long *saddr; + long *eaddr; + int fpath_len; + struct addr_node *head = NULL; + struct addr_node *tail = NULL; + struct addr_node *t_node = NULL; + + fprintf_fd(fd, "\n%s\n", CRASH_MAPSINFO_TITLE); + +/* parsing the maps to get executable code address */ + while (fgets_fd(linebuf, BUF_SIZE, fd_maps) != NULL) { + memset(path, 0, PATH_LEN); + result = + sscanf(linebuf, "%s %s %*s %*s %*s %s ", addr, perm, path); + perm[4] = 0; +/*if perm[2]=='x',addr is valid value so we have to store the address */ +#ifdef TARGET + if ((perm[2] == 'x' && path[0] == '/') + || (perm[1] == 'w' && path[0] != '/')) +#else + if (strncmp(perm, "r-xp", 4) == 0) +#endif + { + /* add addr node to list */ + addr[8] = 0; + saddr = (long *)strtoul(addr, NULL, 16); + eaddr = (long *)strtoul(&addr[9], NULL, 16); + /* 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, 5); + 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); + fprintf_fd(fd, "%08x %08x %s %s\n", + (unsigned int)t_node->startaddr, + (unsigned int)t_node->endaddr, + t_node->perm, t_node->fpath); + } else { + t_node->fpath = + (char *)mmap(0, 8, + PROT_READ | + PROT_WRITE, + MAP_PRIVATE | + MAP_ANONYMOUS, -1, 0); + memset(t_node->fpath, 0, 8); + memcpy(t_node->fpath, "[anony]", 7); + } + t_node->next = NULL; + if (head == NULL) { + head = t_node; + tail = t_node; + } else { + tail->next = t_node; + tail = t_node; + } + } + } + fprintf_fd(fd, "%s\n", CRASH_MAPSINFO_TITLE_E); + return head; +} +/* get address list from maps */ +static struct addr_node *get_addr_list_from_maps(int fd_maps) +{ + int result; + char linebuf[BUF_SIZE]; + char addr[20]; + char perm[5]; + char path[PATH_LEN]; + long *saddr; + long *eaddr; + int fpath_len; + 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_maps) != NULL) { + memset(path, 0, PATH_LEN); + result = + sscanf(linebuf, "%s %s %*s %*s %*s %s ", addr, perm, path); + perm[4] = 0; +/*if perm[2]=='x',addr is valid value so we have to store the address */ +#ifdef TARGET + if ((perm[2] == 'x' && path[0] == '/') + || (perm[1] == 'w' && path[0] != '/')) +#else + if (strncmp(perm, "r-xp", 4) == 0) +#endif + { + /* add addr node to list */ + addr[8] = 0; + saddr = (long *)strtoul(addr, NULL, 16); + eaddr = (long *)strtoul(&addr[9], NULL, 16); + /* 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, 5); + 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, 8, + PROT_READ | + PROT_WRITE, + MAP_PRIVATE | + MAP_ANONYMOUS, -1, 0); + memset(t_node->fpath, 0, 8); + memcpy(t_node->fpath, "[anony]", 7); + } + + 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(stderr, "[sys-assert]start print_node_to_file\n"); + fprintf_fd(fd, "\n%s\n", CRASH_MAPSINFO_TITLE); + while (t_node) { + if (!strncmp("[anony]", t_node->fpath, strlen("[anony]"))) { + 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(const siginfo_t *info, int fd) +{ + int signum = info->si_signo; + + fprintf_fd(fd, "Signal: %d\n", signum); + switch (signum) { + case SIGINT: + fprintf_fd(fd, " (SIGINT)\n"); + break; + case SIGILL: + fprintf_fd(fd, " (SIGILL)\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 SIGKILL: + fprintf_fd(fd, " (SIGKILL)\n"); + break; + case SIGSEGV: + fprintf_fd(fd, " (SIGSEGV)\n"); + break; + case SIGPIPE: + fprintf_fd(fd, " (SIGPIPE)\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: + /* FIXME : print exe name displace with info->si_pid */ + fprintf_fd(fd, + " signal sent by tkill (sent by pid %d, uid %d)\n", + info->si_pid, info->si_uid); + fprintf_fd(fd, " TIMER: %d\n", SI_TIMER); + break; +#endif +#ifdef SI_USER + case SI_USER: + /* FIXME : print exe name displace with info->si_pid */ + 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); + + } +} + + +#define VIP_PATH "/tmp/vip" +#define PERMANENT_PATH "/tmp/permanent" + +static int check_redscreen(int pid) +{ + DIR *dp; + struct dirent *dirp; + char pid_str[10]; + + snprintf(pid_str, 10, "%d", pid); + if ((dp = opendir(VIP_PATH)) == NULL) { + return 0; + } else { + while ((dirp = readdir(dp)) != NULL) { + if (strcmp(dirp->d_name, pid_str) == 0) { + fprintf(stderr, "pid=%d is VIP process\n", pid); + closedir(dp); + return 1; + } + } + } + closedir(dp); + if ((dp = opendir(PERMANENT_PATH)) == NULL) { + return 0; + } else { + while ((dirp = readdir(dp)) != NULL) { + if (strcmp(dirp->d_name, pid_str) == 0) { + fprintf(stderr, + "pid=%d is Permanent process\n", pid); + closedir(dp); + return 1; + } + } + } + closedir(dp); + return 0; +} +/*localtime() can not use in signal handler, +so we need signal safe version of localtime */ +static inline void get_localtime(time_t cur_time, struct tm *ctime) +{ + int tday[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + int time_var = cur_time; + int i = 0; + + ctime->tm_sec = time_var % 60; + time_var /= 60; + ctime->tm_min = time_var % 60; + time_var /= 60; + /* do we need to fix up timze zone ? */ + ctime->tm_hour = time_var % 24; + time_var /= 24; + int year = 1970; + int leak_year = 0; + while (time_var > 365 + (leak_year = (((year % 4) == 0) + && ((year % 100) != 0)) + || ((year % 400) == 0))) { + time_var = time_var - 365 - leak_year; + year++; + } + ctime->tm_year = year; + leak_year = (((year % 4) == 0) && ((year % 100) != 0)) + || ((year % 400) == 0); + time_var++; + while (time_var > tday[i]) { + time_var -= tday[i]; + if (i == 1) + time_var -= leak_year; + i++; + } + ctime->tm_mon = ++i; + ctime->tm_mday = time_var; + fprintf(stderr, "local time %d %d %d %d:%d:%d\n", + ctime->tm_year, ctime->tm_mon, ctime->tm_mday, + ctime->tm_hour, ctime->tm_min, ctime->tm_sec); +} +void sighandler(int signum, siginfo_t *info, void *context) +{ + /* for context info */ + ucontext_t *ucontext = context; + void *callstack_addrs[CALLSTACK_SIZE]; + int cnt_callstack = 0; + /* for backtrace_symbols() */ + char **callstack_strings; + struct addr_node *head = NULL; + int i; + /* file descriptor */ + int fd_cs; /* for cs file */ + int fd_maps; /* for maps */ + int fd_meminfo; /* for meminfo */ +#ifdef STANDALONE + int fd_verinfo; /* for version info */ +#endif + int fd_cmdline; /* for cmdline */ + int fd_status; /* for status */ + int fd_curbs; /* for inotify */ + pid_t cs_pid; + pid_t cs_tid; + char cs_timestr[64]; + char cs_processname[NAME_MAX] = {0,}; + char cs_exepath[PATH_LEN] = {0,}; + char cs_filepath[PATH_LEN]; + /* for get time */ + time_t cur_time; +#ifdef STANDALONE + struct tm ctime; + char timestr[64]; +#endif + /* for get info */ + int thread_use; + char *p_exepath = NULL; + char tag[64]; + char infoname[20]; + char memsize1[24]; + char linebuf[BUF_SIZE]; + + cur_time = time(NULL); +#ifdef STANDALONE + gmtime_r(&cur_time, &ctime); + /*localtime_r(&cur_time, &ctime);*/ + /*get_localtime(cur_time, &ctime);*/ +#endif + fprintf(stderr, "[sys_assert]START of sighandler\n"); + /* get pid */ + cs_pid = getpid(); + cs_tid = (long int)syscall(__NR_gettid); +#ifdef TARGET + /* open maps file */ + if ((fd_maps = 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_maps); + close(fd_maps); + } + if (head == NULL) { + fprintf(stderr, ">>>>error : cannot get address list from maps\n"); + } else { +#ifndef SUPPORT_LIBC_BACKTRACE + /* backtrace using fp */ + long *SP; /* point to the top of stack */ + long *PC; /* point to the program counter */ + long *BP = __libc_stack_end; + long *FP; + long *framep; + /* get sp , pc and bp */ + SP = (long *)ucontext->uc_mcontext.arm_sp; + PC = (long *)ucontext->uc_mcontext.arm_pc; + FP = (long *)ucontext->uc_mcontext.arm_fp; + framep = (long *)FP; + callstack_addrs[cnt_callstack++] = + (long *)ucontext->uc_mcontext.arm_pc; + if (FP != NULL) { + for (; framep < BP;) { + if (is_valid_addr(framep, head) == false) + break; + + if (is_valid_addr((long *)*framep, head) == false) + break; + + callstack_addrs[cnt_callstack] = (long *)*framep; + + framep--; + framep = (long *)(*framep); + cnt_callstack++; + + if (cnt_callstack == CALLSTACK_SIZE) + break; + if (framep < FP) + break; + } + } +#else /*SUPPORT_LIBC_BACKTRACE*/ + cnt_callstack = backtrace(callstack_addrs, CALLSTACK_SIZE); + if (cnt_callstack > 2) { + cnt_callstack -= 2; + } else { + callstack_addrs[2] = (long *)ucontext->uc_mcontext.arm_pc; + callstack_addrs[3] = (long *)ucontext->uc_mcontext.arm_lr; + cnt_callstack = 2; + } +#endif + } +#else /* i386 */ + layout *ebp = ucontext->uc_mcontext.gregs[REG_EBP]; + callstack_addrs[cnt_callstack++] = + (long *)ucontext->uc_mcontext.gregs[REG_EIP]; + while (ebp) { + callstack_addrs[cnt_callstack++] = ebp->ret; + ebp = ebp->ebp; + } + callstack_strings = backtrace_symbols(callstack_addrs, cnt_callstack); +#endif + /* get exepath */ + if ((fd_cmdline = open(CMDLINE_PATH, O_RDONLY)) < 0) { + fprintf(stderr, "[sys-assert]can't open %s\n", CMDLINE_PATH); + return; + } else { + i = read(fd_cmdline, cs_exepath, sizeof(cs_exepath)); + close(fd_cmdline); + if (i <= 0) { + fprintf(stderr, "[sys-assert]can't get cmdline\n"); + return; + } else { + cs_exepath[i] = '\0'; + fprintf(stderr, "[sys-assert]exepath = %s\n", cs_exepath); + } + } + /* get processname */ + if ((fd_status = open(STATUS_PATH, O_RDONLY)) < 0) { + fprintf(stderr, "[sys-assert]can't open %s\n", STATUS_PATH); + return; + } else { + i = read(fd_status, linebuf, sizeof(linebuf)); + close(fd_status); + if (i <= 0) { + fprintf(stderr, "[sys-assert]can't get status\n"); + cs_processname[0] = '\0'; + } else + sscanf(linebuf, "%s %s", tag, cs_processname); + + if (cs_processname[0] == '\0') { + p_exepath = remove_path(cs_exepath); + if (p_exepath == NULL) + return; + snprintf(cs_processname, NAME_MAX, "%s", p_exepath); + } + fprintf(stderr, "[sys-assert]processname = %s\n", cs_processname); + } + /* added temporary skip when crash-worker is asserted */ + if (!strcmp(cs_processname, "crash-worker") || !strcmp(cs_processname, "crash-popup")) + return; + /* thread check */ + if (cs_pid == cs_tid) { + thread_use = false; + fprintf(stderr, + "[sys_assert]this thread is main thread. pid=%d\n", + cs_pid); + } else { + thread_use = true; + fprintf(stderr, + "[sys_assert]this process is multi-thread process.\ + pid=%d, tid=%d\n", cs_pid, cs_tid); + } + /* make crash info file name */ +#ifdef STANDALONE + strftime(cs_timestr, sizeof(cs_timestr), "%Y%m%d%H%M%S", &ctime); + if (snprintf(cs_filepath, PATH_LEN, + "%s/%s_%s.cs", CRASH_REPORT_PATH, cs_processname, cs_timestr) == 0) { + fprintf(stderr, + "[sys-assert]can't make crash info file name : %s%s\n", + cs_processname, cs_timestr); + return; + } + /* check crash info dump directory, make directory if absent */ + if (access(CRASH_REPORT_PATH, F_OK) == -1) { + if (mkdir(CRASH_REPORT_PATH, DIR_PERMS) < 0) { + fprintf(stderr, + "[sys-assert]can't make dir : %s errno : %s\n", + CRASH_REPORT_PATH, strerror(errno)); + return; + } + } +#else + snprintf(cs_timestr, sizeof(cs_timestr), "%lu", cur_time); + fprintf(stderr, "[sys-assert]cs timestr %s\n",cs_timestr); + if (snprintf(cs_filepath, PATH_LEN, + "%s/%d_%s.info", CRASH_INFO_PATH, cs_pid, cs_timestr) == 0) { + fprintf(stderr, + "[sys-assert]can't make crash info file name : %d%s\n", + cs_pid, cs_timestr); + return; + } + /* check crash info dump directory, make directory if absent */ + if (access(CRASH_INFO_PATH, F_OK) == -1) { + if (mkdir(CRASH_INFO_PATH, DIR_PERMS) < 0) { + fprintf(stderr, + "[sys-assert]can't make dir : %s errno : %s\n", + CRASH_INFO_PATH, strerror(errno)); + return; + } + } +#endif + /* logging crash information to syslog */ + syslog(LOG_ERR, "crashed [%s] processname=%s, pid=%d, tid=%d, signal=%d", + cs_timestr, cs_processname, cs_pid, cs_tid, info->si_signo); + /* complete filepath_cs */ + if (!strlen(cs_filepath)) + return; + /* create cs file */ + if ((fd_cs = creat(cs_filepath, FILE_PERMS)) < 0) { + fprintf(stderr, + "[sys-assert]can't create %s. errno = %s\n", + cs_filepath, strerror(errno)); + return; + } +#ifdef STANDALONE + /* print version info */ + fprintf_fd(fd_cs, "S/W Version Information\n"); + if ((fd_verinfo = open(VERINFO_PATH, O_RDONLY)) < 0) { + fprintf(stderr, "[sys-assert]can't open %s\n", VERINFO_PATH); + } else { + while (fgets_fd(linebuf, BUF_SIZE, fd_verinfo) != NULL) { + if (strncmp("Major=", linebuf, 6) == 0) { + fprintf_fd(fd_cs, "%s", linebuf); + } else if (strncmp("Minor=", linebuf, 6) == 0) { + fprintf_fd(fd_cs, "%s", linebuf); + } else if (strncmp("Build=", linebuf, 6) == 0) { + fprintf_fd(fd_cs, "%s", linebuf); + } else if (strncmp("Date=", linebuf, 5) == 0) { + fprintf_fd(fd_cs, "%s", linebuf); + } else if (strncmp("Time=", linebuf, 5) == 0) { + fprintf_fd(fd_cs, "%s", linebuf); + break; + } + } + close(fd_verinfo); + } + /* print app info */ + fprintf_fd(fd_cs, "Process Name: %s\n", cs_processname); + fprintf_fd(fd_cs, "PID: %d\n", cs_pid); + /* print time */ + /*localtime_r(&cur_time, &ctime);*/ + strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", &ctime); + fprintf_fd(fd_cs, "Date: %s ( UTC )\n", timestr); + /* print exe path */ + fprintf_fd(fd_cs, "Executable File Path: %s\n", cs_exepath); + fprintf(stderr, "[sys assert]Exe Path: %s\n", cs_exepath); +#endif + /* print thread info */ + if (thread_use == true) { + fprintf_fd(fd_cs, + "This process is multi-thread process\npid=%d tid=%d\n", + cs_pid, cs_tid); + } + /* print signal info */ + print_signal_info(info, fd_cs); + fsync(fd_cs); + /* print additional info */ +#ifdef TARGET + fprintf_fd(fd_cs, "\n%s\n", CRASH_REGISTERINFO_TITLE); + fprintf_fd(fd_cs, + "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_cs, + "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_cs, + "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_cs, + "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_cs, "cpsr = 0x%08x\n", ucontext->uc_mcontext.arm_cpsr); +#endif + /* print meminfo */ + fprintf_fd(fd_cs, "\n%s\n", CRASH_MEMINFO_TITLE); + if ((fd_meminfo = 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_meminfo) != NULL) { + sscanf(linebuf, "%s %s %*s", infoname, memsize1); + if (strcmp("MemTotal:", infoname) == 0) { + fprintf_fd(fd_cs, "%s %s KB\n", infoname, + memsize1); + } else if (strcmp("MemFree:", infoname) == 0) { + fprintf_fd(fd_cs, "%s %s KB\n", infoname, + memsize1); + } else if (strcmp("Buffers:", infoname) == 0) { + fprintf_fd(fd_cs, "%s %s KB\n", + infoname, memsize1); + } else if (strcmp("Cached:", infoname) == 0) { + fprintf_fd(fd_cs, "%s %s KB\n", + infoname, memsize1); + break; + } + } + close(fd_meminfo); + } +#ifdef TARGET + if (head == NULL) { + fprintf_fd(fd_cs, "Failed to get address list\n"); + fprintf(stderr, ">>>>error : cannot get address list from maps\n"); + } else { + /* print maps information */ + print_node_to_file(head, fd_cs); + fprintf_fd(fd_cs, "\n%s (PID:%d)\n", CRASH_CALLSTACKINFO_TITLE, cs_pid); +#ifndef SUPPORT_LIBC_BACKTRACE + fprintf_fd(fd_cs, "Call Stack Count: %d\n", cnt_callstack); + /* print callstack */ + if (false == + trace_symbols(callstack_addrs, cnt_callstack, head, fd_cs)) { + callstack_strings = + backtrace_symbols(callstack_addrs, cnt_callstack); + /* print callstack information */ + for (i = 0; i < cnt_callstack; i++) + fprintf_fd(fd_cs, "%2d: %s\n", i, callstack_strings[i]); + } + if (FP == NULL) + fprintf_fd(fd_cs, + "there is no callstack because of fp == NULL\n"); +#else /*SUPPORT_LIBC_BACKTRACE*/ + fprintf_fd(fd_cs, "Call Stack Count: %d\n", cnt_callstack); + /* print callstack */ + if (false == + trace_symbols(&callstack_addrs[2], cnt_callstack, head, fd_cs)) { + fprintf(stderr, "[sys-assert] trace_symbols failed\n"); + } +#endif + fprintf_fd(fd_cs, "%s\n", CRASH_CALLSTACKINFO_TITLE_E); + free_all_nodes(head); + } +#else /* i386 */ + fprintf_fd(fd_cs, "\n%s (PID:%d)\n", CRASH_CALLSTACKINFO_TITLE, cs_pid); + fprintf_fd(fd_cs, "Call Stack Count: %d\n", cnt_callstack); + /* print callstack information */ + for (i = 0; i < cnt_callstack; i++) + fprintf_fd(fd_cs, "%2d: %s\n", i, callstack_strings[i]); + fprintf_fd(fd_cs, "%s\n", CRASH_CALLSTACKINFO_TITLE_E); +#endif + /* cs file sync */ + fsync(fd_cs); + /* clean up */ + if (close(fd_cs) == -1) + fprintf(stderr, "[sys-assert] fd_cs close error!!\n"); +#ifndef STANDALONE + /* core dump set */ + if (prctl(PR_GET_DUMPABLE) == 0) { + fprintf(stderr, "[sys-assert]set PR_SET_DUMPABLE to 1\n"); + prctl(PR_SET_DUMPABLE, 1); + } + /* NOTIFY CRASH */ + if ((fd_curbs = open(CRASH_NOTI_PATH, O_RDWR | O_APPEND)) < 0) { + fprintf(stderr, "[sys-assert]cannot make %s !\n", CRASH_NOTI_PATH); + } else { + fprintf_fd(fd_curbs, "S|%s|%s|%d|%s|%d\n", + cs_processname, cs_timestr, cs_pid, cs_exepath, + strlen(cs_processname) + strlen(cs_exepath)); + close(fd_curbs); + } +#endif + for (i = 0; i < NUM_SIG_TO_HANDLE; i++) { + if (sig_to_handle[i] == signum) { + sigaction(signum, &g_oldact[i], NULL); + fprintf(stderr, + "sighandler = %p, g_sig_oldact[i] = %p\n", + (void *)sighandler, g_oldact[i].sa_handler); + break; + } + } + raise(signum); + fprintf(stderr, "[sys_assert]END of sighandler\n"); +} +__attribute__ ((constructor)) +void init() +{ + int i; + + for (i = 0; i < NUM_SIG_TO_HANDLE; i++) { + 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[i], &act, &g_oldact[i]) < 0) { + perror("[sys-assert]could not set signal handler "); + continue; + } + } +} diff --git a/sys-assert/src/sys-assert.h b/sys-assert/src/sys-assert.h new file mode 100755 index 0000000..1b64f6d --- /dev/null +++ b/sys-assert/src/sys-assert.h @@ -0,0 +1,54 @@ +/* + * 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 __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_ */