aboutsummaryrefslogtreecommitdiff
path: root/libcalltrace
diff options
context:
space:
mode:
authorbhgv <bhgv.empire@gmail.com>2018-03-01 16:54:45 +0200
committerbhgv <bhgv.empire@gmail.com>2018-03-01 16:54:45 +0200
commitb786f20bbab5a59046aa78a2c6c2a11536497202 (patch)
tree0851ecdec889eb9b7ba3751cc04d4f0b474e4a9e /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.c273
-rw-r--r--libcalltrace/calltrace2.c214
-rw-r--r--libcalltrace/mkfile8
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