diff options
| author | bhgv <bhgv.empire@gmail.com> | 2018-03-01 16:54:45 +0200 |
|---|---|---|
| committer | bhgv <bhgv.empire@gmail.com> | 2018-03-01 16:54:45 +0200 |
| commit | b786f20bbab5a59046aa78a2c6c2a11536497202 (patch) | |
| tree | 0851ecdec889eb9b7ba3751cc04d4f0b474e4a9e /libcalltrace | |
inferno-os tree was separated from the inferno-os-android (separated from the Android driver)
Diffstat (limited to 'libcalltrace')
| -rw-r--r-- | libcalltrace/calltrace.c | 273 | ||||
| -rw-r--r-- | libcalltrace/calltrace2.c | 214 | ||||
| -rw-r--r-- | libcalltrace/mkfile | 8 |
3 files changed, 495 insertions, 0 deletions
diff --git a/libcalltrace/calltrace.c b/libcalltrace/calltrace.c new file mode 100644 index 0000000..7ff2d34 --- /dev/null +++ b/libcalltrace/calltrace.c @@ -0,0 +1,273 @@ +/* call-trace.c - converting addresses to files and lines + Copyright (C) 1997-2017 Free Software Foundation, Inc. + Contributed by Emil Ohlsson <emil.ohlsson@kottland.net> + + 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +/* Derived from addr2line by Ulrich.Lauther@mchp.siemens.de */ + +/**** Includes *****/ + +#include <bfd.h> +#include <demangle.h> +#include <errno.h> +#include <libiberty.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +/**** Defines ****/ + +#define LINEBUF 256 + +/** Function decorators **/ + +#define INSTRUMENT __attribute__((no_instrument_function)) +#define INSTRUMENT_CONSTRUCTOR __attribute__((no_instrument_function, constructor)) +#define INSTRUMENT_DESTRUCTOR __attribute__((no_instrument_function, destructor)) + +/** Arguments **/ + +#ifndef UNWIND_INLINES +#define UNWIND_INLINES 1 +#endif + +#ifndef WITH_ADDRESSES +#define WITH_ADDRESSES 1 +#endif + +#ifndef WITH_FUNCTIONS +#define WITH_FUNCTIONS 1 +#endif + +#ifndef DO_DEMANGLE +#define DO_DEMANGLE 1 +#endif + +#ifndef PRETTY_PRINT +#define PRETTY_PRINT 1 +#endif + +#ifndef BASE_NAMES +#define BASE_NAMES 1 +#endif + +/** Helpers **/ + +#define err(fmt, ...) fprintf(stderr, "ERR: " fmt "\n", ##__VA_ARGS__) +#define log(fmt, ...) fprintf(stderr, fmt "\n", ##__VA_ARGS__) + +/**** Data ****/ + +/** Options **/ + +static bfd_boolean unwind_inlines = UNWIND_INLINES; /* unwind inlined functions. */ +static bfd_boolean with_addresses = WITH_ADDRESSES; /* show addresses. */ +static bfd_boolean with_functions = WITH_FUNCTIONS; /* show function names. */ +static bfd_boolean do_demangle = DO_DEMANGLE; /* demangle names. */ +static bfd_boolean pretty_print = PRETTY_PRINT; /* print on one line. */ +static bfd_boolean base_names = BASE_NAMES; /* strip directory names. */ + +/* These global variables are used to pass information between translate_addresses and + * find_address_in_section. */ + +static asymbol **syms; +static bfd *abfd; +static bfd_boolean found; +static bfd_vma pc; +static const char *filename; +static const char *functionname; +static unsigned int discriminator; +static unsigned int line; + +/**** Private functions ****/ + +/** Preparation and cleanup **/ + +static void INSTRUMENT slurp(bfd *abfd) +{ + long symcount; + unsigned int size; + + if ((bfd_get_file_flags(abfd) & HAS_SYMS) == 0) return; + + symcount = bfd_read_minisymbols(abfd, false, (void *) &syms, &size); + if (symcount == 0) { + symcount = bfd_read_minisymbols(abfd, TRUE, (void *) &syms, &size); + } + if (symcount < 0) { + err("Could not read symbol table"); + } +} + +static void INSTRUMENT_CONSTRUCTOR setup() +{ + char **matching; + const char *self = "/proc/self/exe"; + + bfd_init(); + + abfd = bfd_openr(self, NULL); + if (!abfd) { + err("Unable to open self"); + return; + } + + if (bfd_check_format(abfd, bfd_archive)) { + err("Cannot identify self"); + return; + } + + if (!bfd_check_format_matches(abfd, bfd_object, &matching)) { + err("Format does not match"); + } + + slurp(abfd); +} + +static void INSTRUMENT_DESTRUCTOR teardown() +{ + free(syms); + bfd_close(abfd); +} + +/** Translation **/ + +/** + * Look for an address in a section. This is called via bfd_map_over_sections. + */ +static void INSTRUMENT find_address_in_section(bfd *abfd, asection *section, + void *data ATTRIBUTE_UNUSED) +{ + bfd_vma vma; + bfd_size_type size; + + if (found) return; + + if ((bfd_get_section_flags(abfd, section) & SEC_ALLOC) == 0) return; + + vma = bfd_get_section_vma(abfd, section); + if (pc < vma) return; + + size = bfd_get_section_size(section); + if (pc >= vma + size) return; + + found = bfd_find_nearest_line_discriminator(abfd, section, syms, pc - vma, &filename, + &functionname, &line, &discriminator); +} + +static void INSTRUMENT describe_address(char* buffer, size_t buffer_length, void *addr) +{ + size_t buffer_index = 0; + + void INSTRUMENT bprintf(const char *fmt, ...) + { + va_list args; + va_start(args, fmt); + buffer_index += vsnprintf(buffer + buffer_index, buffer_length - buffer_index, fmt, args); + va_end(args); + } + + pc = (intptr_t) addr; + if (with_addresses) { + bprintf("%p ", addr); + } + + found = FALSE; + bfd_map_over_sections(abfd, find_address_in_section, NULL); + + if (!found) { + if (with_functions) { + if (pretty_print) { + bprintf("?? "); + } else { + bprintf("??"); + } + } + bprintf("??:0"); + } else { + while (1) { + if (with_functions) { + const char *name; + char *alloc = NULL; + + name = functionname; + if (name == NULL || *name == '\0') { + name = "??"; + } else if (do_demangle) { + alloc = bfd_demangle(abfd, name, DMGL_ANSI | DMGL_PARAMS); + if (alloc != NULL) name = alloc; + } + + bprintf("%s", name); + if (pretty_print) { + bprintf(" at "); + } + + if (alloc != NULL) free(alloc); + } + + if (base_names && filename != NULL) { + char *h; + + h = strrchr(filename, '/'); + if (h != NULL) filename = h + 1; + } + + bprintf("%s:", filename ? filename : "??"); + if (line != 0) { + if (discriminator != 0) { + bprintf("%u (discriminator %u)", line, discriminator); + } + else { + bprintf("%u", line); + } + } else { + bprintf("?"); + } + if (!unwind_inlines) { + found = FALSE; + } else { + found = bfd_find_inliner_info(abfd, &filename, &functionname, &line); + } + if (!found) break; + if (pretty_print) { + bprintf(" (inlined by) "); + } + } + } +} + +/**** Public functions ****/ + +void INSTRUMENT __cyg_profile_func_enter(void *this_fn, void *call_site) +{ + char from[LINEBUF] = {0}; + char to[LINEBUF] = {0}; + + describe_address(to, LINEBUF, this_fn); + describe_address(from, LINEBUF, call_site); + log("-trace- calling [%s] from [%s]", to, from); +} + +void INSTRUMENT __cyg_profile_func_exit(void *this_fn ATTRIBUTE_UNUSED, + void *call_site ATTRIBUTE_UNUSED) +{ +} + + diff --git a/libcalltrace/calltrace2.c b/libcalltrace/calltrace2.c new file mode 100644 index 0000000..11b5735 --- /dev/null +++ b/libcalltrace/calltrace2.c @@ -0,0 +1,214 @@ + +#include <stdio.h> +#include <time.h> + +#include <unwind.h> +#include <dlfcn.h> + + + +#if def ANDROID +#include <android/log.h> + +#define LOG_TAG "inferno CT" +#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) +#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__) +#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) +#else +#define LOGI(...) printf(__VA_ARGS__) +#define LOGW(...) +#define LOGE(...) +#endif + +//static FILE *fp_trace; + + +typedef struct BacktraceState +{ + void** current; + void** end; +} BacktraceState; + + +typedef struct +{ + uintptr_t r[16]; +} core_regs; + + +typedef struct +{ + uintptr_t demand_save_flags; + core_regs core; +} phase2_vrs; + + + +extern ucontext_t *sig_ctx; + +extern _Unwind_Reason_Code __gnu_Unwind_Backtrace(_Unwind_Trace_Fn trace, void * trace_argument, phase2_vrs * entry_vrs); + + + +static _Unwind_Reason_Code unwindCallback(struct _Unwind_Context* context, void* arg) +{ + BacktraceState* state = (BacktraceState*)(arg); + uintptr_t pc = _Unwind_GetIP(context); + if (pc) { + if (state->current == state->end) { + return _URC_END_OF_STACK; + } else { + *state->current++ = (void*)(pc); + } + } + return _URC_NO_REASON; +} + + +char** dumpBacktrace(void** buffer, size_t count) +{ + size_t idx; + int len; + char **sym_buf = (char**)malloc( count * sizeof(char**) ); + + for (idx = 0; idx < count; ++idx) { + const void* addr = buffer[idx]; + const char* symbol = ""; + char *sym_rslt; + + Dl_info info; + if (dladdr(addr, &info) && info.dli_sname) { + symbol = info.dli_sname; + } + len = strlen(symbol) + 1 + 25; + sym_rslt = malloc(len); + + snprint(sym_rslt, len-1, "# %d: %#p %s", idx, addr, symbol); + sym_buf[idx] = sym_rslt; + } + return sym_buf; +} + + +size_t captureBacktrace(void** buffer, size_t max, void *arg) +{ + + BacktraceState state = {buffer, buffer + max}; + + if(arg != nil){ + ucontext_t* signal_context = (ucontext_t*) arg; + + phase2_vrs pre_signal_state = {}; + // pre_signal_state.demand_save_flags = 0; + pre_signal_state.core = *(const core_regs*)(&(signal_context->uc_mcontext.arm_r0)); + + __gnu_Unwind_Backtrace(unwindCallback, &state, &pre_signal_state); + }else{ + _Unwind_Backtrace(unwindCallback, &state); + } + + return state.current - buffer; +} + + +void do_backtrace(char *err_str) +{ + size_t i, max = 30; + void* buffer[max]; + char **sym_buf; + + FILE *f = fopen("/sdcard/Inferno/backtrace.log", "a"); + + max = captureBacktrace(buffer, max, sig_ctx ); + + sym_buf = dumpBacktrace(buffer, max); + + sig_ctx = nil; + + if(f != nil ){ + fprintf(f, "\n%s\n-----\n", err_str ? err_str : "ERROR: ??"); + + for(i=2; i<max; i++){ + if(sym_buf[i]) + fprintf(f, "%s\n", sym_buf[i]); + } + + fclose(f); + } + + for(i=0; i<max; i++){ + if(sym_buf[i]){ +// LOGE("%s", sym_buf[i]); + free(sym_buf[i]); + } + } + free(sym_buf); +} + + + +#if 0 +#include <execinfo.h> + +void **backtrace_buf[32]; + + +void do_backtrace(){ + int i, cnt = backtrace(backtrace_buf, 30); + char **symbs; + int f = open("/sdcard/Inferno/backtrace.txt", O_WRONLY); + if(f){ + backtrace_symbols_fd(backtrace_buf, cnt, f); + close(f); + } + + symbs = backtrace_symbols(backtrace_buf, cnt); + for(i=0; i<cnt; i++){ + LOGE("%s", symbs[i]); + } + free(symbs); +} +#endif + + +/* +void +__attribute__ ((constructor)) +trace_begin (void) +{ +//LOGI("trace_begin"); +// fp_trace = fopen("/sdcard/Inferno/trace.out", "w"); +} +*/ + +/* +void +__attribute__ ((destructor)) +trace_end (void) +{ +LOGI("trace_end"); +// if(fp_trace != NULL) { +// fclose(fp_trace); +// } +} +*/ + +void +__cyg_profile_func_enter (void *func, void *caller) +{ +//LOGI("trace_foo_ent %p, %p", func, caller); +// if(fp_trace != NULL) { +// fprintf(fp_trace, "e %p %p %lu\n", func, caller, time(NULL) ); +// } +} + +void +__cyg_profile_func_exit (void *func, void *caller) +{ +//LOGI("trace_foo_exit %p, %p", func, caller); +// if(fp_trace != NULL) { +// fprintf(fp_trace, "x %p %p %lu\n", func, caller, time(NULL)); +// } +} + + diff --git a/libcalltrace/mkfile b/libcalltrace/mkfile new file mode 100644 index 0000000..c0b870f --- /dev/null +++ b/libcalltrace/mkfile @@ -0,0 +1,8 @@ +<../mkconfig + +LIB=libcalltrace.a +OFILES=\ + calltrace2.$O\ + + +<$ROOT/mkfiles/mksyslib-$SHELLTYPE |
