From 443f2c042b036fed60b4c09eb13f8b50dea7ed68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Stelmach?= Date: Wed, 14 Dec 2016 15:06:43 +0100 Subject: crash-stack: print maps information Print information about mapped memory regions. Add stub for printing system and process VM information. Change-Id: I47b2c5f837620f9d22b3270a75d8f5e663d44c78 --- src/crash-stack/crash-stack.c | 229 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 211 insertions(+), 18 deletions(-) (limited to 'src/crash-stack') diff --git a/src/crash-stack/crash-stack.c b/src/crash-stack/crash-stack.c index 2507055..bd5731f 100644 --- a/src/crash-stack/crash-stack.c +++ b/src/crash-stack/crash-stack.c @@ -16,6 +16,8 @@ * Authors: Adrian Szyndela * Ɓukasz Stelmach */ +#define _GNU_SOURCE 1 + /** * @file crash-stack.c * @brief This file contains Main module of call stack unwinding program @@ -24,9 +26,27 @@ * of a crashed program. Crash-stack must be called with proper arguments: * either core dump file name or PID of a crashed program. */ -#include -#include +#include "crash-stack.h" +#include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include #include /* * In case the program is compiled with core dumps, the license may switch to GPL2. @@ -34,22 +54,13 @@ #ifdef WITH_CORE_DUMP #include #endif -#include -#include -#include -#include -#include -#include -#include "crash-stack.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include + +#define BUF_SIZE (BUFSIZ) +#define HEXA 16 +#define PERM_LEN 5 +#define ADDR_LEN 16 +#define STR_ANONY "[anony]" +#define STR_ANONY_LEN 8 static siginfo_t __siginfo; static FILE *outputfile = NULL; ///< global output stream @@ -76,6 +87,22 @@ const struct option opts[] = { { 0, 0, 0, 0 } }; +/** + * @brief container for information from /proc/PID/maps + */ +struct addr_node { + uintptr_t startaddr; + uintptr_t endaddr; + char perm[PERM_LEN]; + char *fpath; + struct addr_node *next; +}; + +/* helper functions for reading /proc/PID/maps */ +static struct addr_node *get_addr_list_from_maps(int fd); +static void free_all_nodes(struct addr_node *start); +static char *fgets_fd(char *str, int len, int fd); + /* * __cxa_demangle() is taken from libstdc++, however there is no header that we * can take a declaration from. Importing through 'extern' allows using it. @@ -854,6 +881,166 @@ static void __crash_stack_print_threads(FILE* outputfile, pid_t pid, pid_t tid) } +/** + * @brief Print information about mapped memory regions + * + * @param outputfile File handle for printing report. + * @param pid PID of the inspected process + */ +static void __crash_stack_print_maps(FILE* outputfile, pid_t pid) +{ + char file_path[PATH_MAX]; + struct addr_node *head = NULL; + struct addr_node *t_node; + int fd; + + snprintf(file_path, PATH_MAX, "/proc/%d/maps", pid); + + if ((fd = open(file_path, O_RDONLY)) < 0) { + fprintf(errfile, "[crash-stack] cannot open %s\n", file_path); + } else { + /* parsing the maps to get code segment address*/ + head = get_addr_list_from_maps(fd); + close(fd); + } + if (head == NULL) { + return; + } + + t_node = head; + fprintf(outputfile, "\nMaps Information\n"); + while (t_node) { + if (!strncmp(STR_ANONY, t_node->fpath, STR_ANONY_LEN)) { + t_node = t_node->next; + } else { + printf( "%16lx %16lx %s %s\n", + (unsigned long)t_node->startaddr, + (unsigned long)t_node->endaddr, + t_node->perm, t_node->fpath); + t_node = t_node->next; + } + } + fprintf(outputfile, "End of Maps Information\n"); + free_all_nodes(head); +} + +static struct addr_node *get_addr_list_from_maps(int fd) +{ + int fpath_len, result; + uintptr_t saddr; + uintptr_t eaddr; + char perm[PERM_LEN]; + char path[PATH_MAX]; + char addr[ADDR_LEN * 2 + 2]; + char linebuf[BUF_SIZE]; + struct addr_node *head = NULL; + struct addr_node *tail = NULL; + struct addr_node *t_node = NULL; + + /* parsing the maps to get executable code address */ + while (fgets_fd(linebuf, BUF_SIZE, fd) != NULL) { + memset(path, 0, PATH_MAX); + result = sscanf(linebuf, "%s %s %*s %*s %*s %s ", addr, perm, path); + if (result < 0) + continue; + perm[PERM_LEN - 1] = 0; + /* rwxp */ + if ((perm[2] == 'x' && path[0] == '/') || + (perm[1] == 'w' && path[0] != '/')) + { + char* addr2 = strchr(addr, '-'); + *(addr2++) = '\0'; + /* add addr node to list */ + saddr = strtoul(addr, NULL, HEXA); + /* ffff0000-ffff1000 */ + eaddr = strtoul(addr2, NULL, HEXA); + /* make node and attach to the list */ + t_node = (struct addr_node *)mmap(0, sizeof(struct addr_node), + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (t_node == NULL) { + fprintf(stderr, "error : mmap\n"); + return NULL; + } + memcpy(t_node->perm, perm, PERM_LEN); + t_node->startaddr = saddr; + t_node->endaddr = eaddr; + t_node->fpath = NULL; + fpath_len = strlen(path); + if (fpath_len > 0) { + t_node->fpath = (char *)mmap(0, fpath_len + 1, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + memset(t_node->fpath, 0, fpath_len + 1); + memcpy(t_node->fpath, path, fpath_len); + } else { + t_node->fpath = (char *)mmap(0, STR_ANONY_LEN, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + memset(t_node->fpath, 0, STR_ANONY_LEN); + memcpy(t_node->fpath, STR_ANONY, STR_ANONY_LEN); + } + t_node->next = NULL; + if (head == NULL) { + head = t_node; + tail = t_node; + } else { + tail->next = t_node; + tail = t_node; + } + } + } + return head; +} + +static void free_all_nodes(struct addr_node *start) +{ + struct addr_node *t_node, *n_node; + int fpath_len; + + if (start == NULL) + return; + t_node = start; + n_node = t_node->next; + while (t_node) { + if (t_node->fpath != NULL) { + fpath_len = strlen(t_node->fpath); + munmap(t_node->fpath, fpath_len + 1); + } + munmap(t_node, sizeof(struct addr_node)); + if (n_node == NULL) + break; + t_node = n_node; + n_node = n_node->next; + } +} + +static char *fgets_fd(char *str, int len, int fd) +{ + char ch; + register char *cs; + int num = 0; + + cs = str; + while (--len > 0 && (num = read(fd, &ch, 1) > 0)) { + if ((*cs++ = ch) == '\n') + break; + } + *cs = '\0'; + return (num == 0 && cs == str) ? NULL : str; +} + +/** + * @brief Print process and system memory information + * + * @param outputfile File handle for printing report. + * @param pid PID of the inspected process + */ +static void __crash_stack_print_meminfo(FILE* outputfile, pid_t pid) +{ + fprintf(outputfile, "\nMemory Information\n"); +} + /** * @brief Main function. * @@ -969,9 +1156,15 @@ int main(int argc, char **argv) /* Print registers */ _crash_stack_print_regs(outputfile); + /* Memory information */ + __crash_stack_print_meminfo(outputfile, pid); + /* Threads */ __crash_stack_print_threads(outputfile, pid, tid); + /* Maps Information */ + __crash_stack_print_maps(outputfile, pid); + /* Print the results */ __print_callstack(&callstack, tid); -- cgit v1.2.3