diff --git a/lib/Makefile.am b/lib/Makefile.am index cb461a6..30f5cc3 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -4,6 +4,7 @@ pkginclude_HEADERS = \ location.h \ metrics.h \ normalize.h \ + sharedlib.h \ strbuf.h \ thread.h \ utils.h @@ -23,6 +24,7 @@ libbtparser_la_SOURCES = \ normalize_libstdcpp.c \ normalize_linux.c \ normalize_xorg.c \ + sharedlib.c \ strbuf.c \ thread.c \ utils.c diff --git a/lib/sharedlib.c b/lib/sharedlib.c index e69de29..c5e6fa0 100644 --- a/lib/sharedlib.c +++ b/lib/sharedlib.c @@ -0,0 +1,216 @@ +/* + sharedlib.c + + Copyright (C) 2011 Red Hat, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include +#include +#include +#include "sharedlib.h" +#include "strbuf.h" +#include "utils.h" + +struct btp_sharedlib * +btp_sharedlib_new() +{ + struct btp_sharedlib *result = btp_malloc(sizeof(struct btp_sharedlib)); + btp_sharedlib_init(result); + return result; +} + +void +btp_sharedlib_init(struct btp_sharedlib *sharedlib) +{ + sharedlib->from = -1; + sharedlib->to = -1; + sharedlib->symbols = SYMS_NOT_FOUND; + sharedlib->soname = NULL; + sharedlib->next = NULL; +} + +void +btp_sharedlib_free(struct btp_sharedlib *sharedlib) +{ + if (!sharedlib) + return; + + free(sharedlib->soname); + free(sharedlib); +} + +void +btp_sharedlib_append(struct btp_sharedlib *a, + struct btp_sharedlib *b) +{ + struct btp_sharedlib *tmp = a; + while (tmp->next) + tmp = tmp->next; + + tmp->next = b; +} + +int +btp_sharedlib_count(struct btp_sharedlib *a) +{ + struct btp_sharedlib *tmp = a; + int count = 0; + while (tmp) + { + ++count; + tmp = tmp->next; + } + + return count; +} + +struct btp_sharedlib * +btp_sharedlib_find_address(struct btp_sharedlib *first, + unsigned long address) +{ + struct btp_sharedlib *tmp = first; + while (tmp) + { + if (address >= tmp->from && address <= tmp->to) + return tmp; + + tmp = tmp->next; + } + + return NULL; +} + +static char * +find_sharedlib_section_start(const char *input) +{ + /* searching for + From To Syms Read Shared Object Library + */ + char *tmp, *result; + + /* ugly */ + for (result = strstr(input, "From"); result; result = strstr(result + 1, "From")) + { + /* must be at the beginning of the line + or at the beginning of whole input */ + if (result != input && *(result - 1) != '\n') + continue; + + tmp = result + strlen("From"); + while (isspace(*tmp)) + ++tmp; + + if (strcmp("To", tmp) != 0) + continue; + + tmp += strlen("To"); + while (isspace(*tmp)) + ++tmp; + + if (strcmp("Syms Read", tmp) != 0) + continue; + + tmp += strlen("Syms Read"); + while (isspace(*tmp)) + ++tmp; + + if (strcmp("Shared Object Library\n", tmp) != 0) + continue; + + /* jump to the next line - the first loaded library */ + return tmp + strlen("Shared Object Library\n"); + } + + return NULL; +} + +struct btp_sharedlib * +btp_sharedlib_parse(const char *input) +{ + char *tmp = find_sharedlib_section_start(input); + if (!tmp) + return NULL; + + struct btp_sharedlib *first = NULL, *current = NULL; + unsigned long from, to; + int symbols; + /* Parsing + From To Syms Read Shared Object Library + 0x0123456789abcdef 0xfedcba987654321 Yes (*)|Yes|No /usr/lib64/libbtparser.so.2.2.2 + */ + while (1) + { + /* From To */ + if (sscanf(tmp, "0x%lx 0x%lx", &from, &to) != 2) + break; + + while (isxdigit(*tmp) || isspace(*tmp) || *tmp == 'x') + ++tmp; + + /* Syms Read */ + if (strcmp("Yes (*)", tmp) == 0) + { + tmp += strlen("Yes (*)"); + symbols = SYMS_NOT_FOUND; + } + else if (strcmp("Yes", tmp) == 0) + { + tmp += strlen("Yes"); + symbols = SYMS_OK; + } + else if (strcmp("No", tmp) == 0) + { + tmp += strlen("No"); + symbols = SYMS_WRONG; + } + else + break; + + while (isspace(*tmp)) + ++tmp; + + /* Shared Object Library */ + struct btp_strbuf *buf = btp_strbuf_new(); + while (*tmp && *tmp != '\n') + { + btp_strbuf_append_char(buf, *tmp); + ++tmp; + } + + if (current) + { + /* round 2+ */ + current->next = btp_sharedlib_new(); + current = current->next; + } + else + { + /* round 1 */ + current = btp_sharedlib_new(); + first = current; + } + + current->from = from; + current->to = to; + current->symbols = symbols; + current->soname = btp_strbuf_free_nobuf(buf); + + /* we are on '\n' character, jump to next line */ + ++tmp; + } + + return first; +} diff --git a/lib/sharedlib.h b/lib/sharedlib.h index e69de29..862426b 100644 --- a/lib/sharedlib.h +++ b/lib/sharedlib.h @@ -0,0 +1,107 @@ +/* + sharedlib.h + + Copyright (C) 2011 Red Hat, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#ifndef BTPARSER_SHAREDLIB_H +#define BTPARSER_SHAREDLIB_H + +#ifdef __cplusplus +extern "C" { +#endif + +enum +{ + SYMS_OK, + SYMS_WRONG, + SYMS_NOT_FOUND, +}; + +struct btp_sharedlib +{ + unsigned long from; + unsigned long to; + int symbols; + char *soname; + struct btp_sharedlib *next; +}; + +/** + * Creates and initializes a new sharedlib structure. + * @returns + * It never returns NULL. The returned pointer must be released by + * calling the function btp_sharedlib_free(). + */ +struct btp_sharedlib * +btp_sharedlib_new(); + +/** + * Initializes all members of the sharedlib to default values. + * No memory is released, members are simply overwritten. + * This is useful for initializing a sharedlib structure placed on the + * stack. + */ +void +btp_sharedlib_init(struct btp_sharedlib *sharedlib); + +/** + * Releases the memory held by the sharedlib. + * Sharedlibs referenced by .next are not released. + * @param sharedlib + * If sharedlib is NULL, no operation is performed. + */ +void +btp_sharedlib_free(struct btp_sharedlib *sharedlib); + +/** + * Appends 'b' to the list 'a'. + */ +void +btp_sharedlib_append(struct btp_sharedlib *a, + struct btp_sharedlib *b); + +/** + * Returns the number of sharedlibs in the list. + */ +int +btp_sharedlib_count(struct btp_sharedlib *sharedlib); + +/** + * Finds whether the address belongs to some sharedlib + * from the list starting by 'first'. + * @returns + * Pointer to an existing structure or NULL if not found. + */ +struct btp_sharedlib * +btp_sharedlib_find_address(struct btp_sharedlib *first, + unsigned long address); + +/** + * Parses the output of GDB's 'info sharedlib' command. + * @param input + * String representing the backtrace. + * @returns + * First element of the list of loaded libraries. + */ +struct btp_sharedlib * +btp_sharedlib_parse(const char *input); + +#ifdef __cplusplus +} +#endif + +#endif