From 84d35d67cf0f2666dff8c6588aadf1d68bd47b56 Mon Sep 17 00:00:00 2001 From: Aleksey Demakov Date: Thu, 29 May 2008 21:03:30 +0000 Subject: [PATCH] add unwinding interface --- ChangeLog | 9 +- include/jit/Makefile.am | 52 +++++----- include/jit/jit-unwind.h | 59 +++++++++++ include/jit/jit.h | 3 +- jit/Makefile.am | 153 ++++++++++++++-------------- jit/jit-except.c | 81 ++++++--------- jit/jit-unwind.c | 212 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 415 insertions(+), 154 deletions(-) create mode 100644 include/jit/jit-unwind.h create mode 100644 jit/jit-unwind.c diff --git a/ChangeLog b/ChangeLog index 210bb46..66a9f56 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,7 +4,14 @@ type. * include/jit/jit-except.h, include/jit/jit-common.h: move - JIT_NO_OFFSET from jit-except.h to jit-common.h + JIT_NO_OFFSET from jit-except.h to jit-common.h. + + * include/jit/jit-unwind.h, jit/jit-unwind.c: new files. + * include/jit/jit.h, include/jit/Makefile.am: add jit-unwind.h. + * jit/Makefile.am: add jit-unwind.c. + + * jit/jit-except.c (jit_exception_get_stack_trace): re-implement + using unwind routines. 2008-05-28 Juan Jesus Garcia de Soria diff --git a/include/jit/Makefile.am b/include/jit/Makefile.am index c676d89..4ec9bf1 100644 --- a/include/jit/Makefile.am +++ b/include/jit/Makefile.am @@ -3,31 +3,33 @@ ARCH_HEADER = jit-arch-@JIT_ARCH@.h BUILT_SOURCES = jit-arch.h libjitincludedir = $(includedir)/jit -libjitinclude_HEADERS = jit.h \ - jit-arch.h \ - jit-apply.h \ - jit-block.h \ - jit-common.h \ - jit-context.h \ - jit-debugger.h \ - jit-defs.h \ - jit-dump.h \ - jit-dynamic.h \ - jit-elf.h \ - jit-except.h \ - jit-function.h \ - jit-init.h \ - jit-insn.h \ - jit-intrinsic.h \ - jit-meta.h \ - jit-objmodel.h \ - jit-objmodel-private.h \ - jit-opcode.h \ - jit-plus.h \ - jit-type.h \ - jit-util.h \ - jit-value.h \ - jit-walk.h +libjitinclude_HEADERS = \ + jit.h \ + jit-arch.h \ + jit-apply.h \ + jit-block.h \ + jit-common.h \ + jit-context.h \ + jit-debugger.h \ + jit-defs.h \ + jit-dump.h \ + jit-dynamic.h \ + jit-elf.h \ + jit-except.h \ + jit-function.h \ + jit-init.h \ + jit-insn.h \ + jit-intrinsic.h \ + jit-meta.h \ + jit-objmodel.h \ + jit-objmodel-private.h \ + jit-opcode.h \ + jit-plus.h \ + jit-type.h \ + jit-unwind.h \ + jit-util.h \ + jit-value.h \ + jit-walk.h noinst_HEADERS = jit-arch-generic.h jit-arch-x86.h jit-arch-x86-64.h diff --git a/include/jit/jit-unwind.h b/include/jit/jit-unwind.h new file mode 100644 index 0000000..822d65d --- /dev/null +++ b/include/jit/jit-unwind.h @@ -0,0 +1,59 @@ +/* + * jit-unwind.h - Routines for performing stack unwinding. + * + * Copyright (C) 2008 Southern Storm Software, Pty Ltd. + * + * This file is part of the libjit library. + * + * The libjit library is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation, either version 2.1 of + * the License, or (at your option) any later version. + * + * The libjit library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the libjit library. If not, see + * . + */ + +#ifndef _JIT_UNWIND_H +#define _JIT_UNWIND_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + void *frame; + void *cache; + jit_context_t context; +#ifdef _JIT_ARCH_UNWIND_DATA + _JIT_ARCH_UNWIND_DATA +#endif +} jit_unwind_context_t; + +int jit_unwind_init(jit_unwind_context_t *unwind, jit_context_t context); +void jit_unwind_free(jit_unwind_context_t *unwind); + +int jit_unwind_next(jit_unwind_context_t *unwind); +int jit_unwind_next_pc(jit_unwind_context_t *unwind); +void *jit_unwind_get_pc(jit_unwind_context_t *unwind); + +int jit_unwind_jump(jit_unwind_context_t *unwind, void *pc); + +jit_function_t jit_unwind_get_function(jit_unwind_context_t *unwind); +unsigned int jit_unwind_get_offset(jit_unwind_context_t *unwind); + +#ifdef __cplusplus +}; +#endif + +#endif /* _JIT_UNWIND_H */ diff --git a/include/jit/jit.h b/include/jit/jit.h index 46ea6cb..0cbdc75 100644 --- a/include/jit/jit.h +++ b/include/jit/jit.h @@ -36,11 +36,12 @@ extern "C" { #include #include #include +#include #include #include #include #include -#include +#include #include #include #include diff --git a/jit/Makefile.am b/jit/Makefile.am index 254b276..68588e4 100644 --- a/jit/Makefile.am +++ b/jit/Makefile.am @@ -2,84 +2,85 @@ lib_LTLIBRARIES = libjit.la libjit_la_SOURCES = \ - jit-alloc.c \ - jit-apply.c \ - jit-apply-func.h \ - jit-apply-alpha.h \ - jit-apply-alpha.c \ - jit-apply-arm.h \ - jit-apply-arm.c \ - jit-apply-x86.h \ - jit-apply-x86.c \ - jit-apply-x86-64.h \ - jit-apply-x86-64.c \ - jit-bitset.h \ - jit-bitset.c \ - jit-block.c \ - jit-cache.h \ - jit-cache.c \ - jit-cfg.h \ - jit-cfg.c \ - jit-context.c \ - jit-cpuid-x86.h \ - jit-cpuid-x86.c \ - jit-debugger.c \ - jit-dump.c \ - jit-elf-defs.h \ - jit-elf-read.c \ - jit-elf-write.c \ - jit-except.c \ - jit-function.c \ - jit-gen-alpha.h \ - jit-gen-arm.h \ - jit-gen-arm.c \ - jit-gen-x86.h \ - jit-gen-x86-64.h \ - jit-insn.c \ - jit-init.c \ - jit-internal.h \ - jit-interp.h \ - jit-interp.c \ - jit-intrinsic.c \ - jit-live.c \ - jit-memory.c \ - jit-memory.h \ - jit-meta.c \ - jit-objmodel.c \ - jit-opcode.c \ - jit-pool.c \ - jit-reg-alloc.h \ - jit-reg-alloc.c \ - jit-reg-class.h \ - jit-reg-class.c \ - jit-rules.h \ - jit-rules.c \ - jit-rules-interp.c \ - jit-rules-interp.h \ - jit-rules-alpha.h \ - jit-rules-alpha.c \ - jit-rules-arm.h \ - jit-rules-arm.c \ - jit-rules-x86.h \ - jit-rules-x86.c \ - jit-rules-x86-64.h \ - jit-rules-x86-64.c \ - jit-setjmp.h \ - jit-signal.c \ - jit-string.c \ - jit-symbol.c \ - jit-thread.c \ - jit-thread.h \ - jit-type.c \ - jit-value.c \ - jit-walk.c + jit-alloc.c \ + jit-apply.c \ + jit-apply-func.h \ + jit-apply-alpha.h \ + jit-apply-alpha.c \ + jit-apply-arm.h \ + jit-apply-arm.c \ + jit-apply-x86.h \ + jit-apply-x86.c \ + jit-apply-x86-64.h \ + jit-apply-x86-64.c \ + jit-bitset.h \ + jit-bitset.c \ + jit-block.c \ + jit-cache.h \ + jit-cache.c \ + jit-cfg.h \ + jit-cfg.c \ + jit-context.c \ + jit-cpuid-x86.h \ + jit-cpuid-x86.c \ + jit-debugger.c \ + jit-dump.c \ + jit-elf-defs.h \ + jit-elf-read.c \ + jit-elf-write.c \ + jit-except.c \ + jit-function.c \ + jit-gen-alpha.h \ + jit-gen-arm.h \ + jit-gen-arm.c \ + jit-gen-x86.h \ + jit-gen-x86-64.h \ + jit-insn.c \ + jit-init.c \ + jit-internal.h \ + jit-interp.h \ + jit-interp.c \ + jit-intrinsic.c \ + jit-live.c \ + jit-memory.c \ + jit-memory.h \ + jit-meta.c \ + jit-objmodel.c \ + jit-opcode.c \ + jit-pool.c \ + jit-reg-alloc.h \ + jit-reg-alloc.c \ + jit-reg-class.h \ + jit-reg-class.c \ + jit-rules.h \ + jit-rules.c \ + jit-rules-interp.c \ + jit-rules-interp.h \ + jit-rules-alpha.h \ + jit-rules-alpha.c \ + jit-rules-arm.h \ + jit-rules-arm.c \ + jit-rules-x86.h \ + jit-rules-x86.c \ + jit-rules-x86-64.h \ + jit-rules-x86-64.c \ + jit-setjmp.h \ + jit-signal.c \ + jit-string.c \ + jit-symbol.c \ + jit-thread.c \ + jit-thread.h \ + jit-type.c \ + jit-unwind.c \ + jit-value.c \ + jit-walk.c EXTRA_DIST = \ - mklabel.sh \ - jit-rules-alpha.ins \ - jit-rules-arm.sel \ - jit-rules-x86.ins \ - jit-rules-x86-64.ins + mklabel.sh \ + jit-rules-alpha.ins \ + jit-rules-arm.sel \ + jit-rules-x86.ins \ + jit-rules-x86-64.ins AM_CFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include -I. -I$(srcdir) diff --git a/jit/jit-except.c b/jit/jit-except.c index bd6d613..a4ad75e 100644 --- a/jit/jit-except.c +++ b/jit/jit-except.c @@ -305,32 +305,32 @@ struct jit_stack_trace @*/ jit_stack_trace_t jit_exception_get_stack_trace(void) { - jit_stack_trace_t trace = 0; - unsigned int size = 0; -#if JIT_APPLY_BROKEN_FRAME_BUILTINS != 0 - jit_thread_control_t control; - jit_backtrace_t top; - jit_backtrace_t item; - + jit_stack_trace_t trace; + unsigned int size; + jit_unwind_context_t unwind; + /* Count the number of items in the current thread's call stack */ - control = _jit_thread_get_control(); - if(!control) + size = 0; + if(jit_unwind_init(&unwind, NULL)) { - return 0; + do + { + size++; + } + while(jit_unwind_next_pc(&unwind)); + jit_unwind_free(&unwind); } - size = 0; - top = control->backtrace_head; - item = top; - while(item != 0) + + /* Bail out if the stack is not available */ + if(size == 0) { - ++size; - item = item->parent; + return 0; } /* Allocate memory for the stack trace */ - trace = (jit_stack_trace_t)jit_malloc - (sizeof(struct jit_stack_trace) + - size * sizeof(void *) - sizeof(void *)); + trace = (jit_stack_trace_t) jit_malloc(sizeof(struct jit_stack_trace) + + size * sizeof(void *) + - sizeof(void *)); if(!trace) { return 0; @@ -339,43 +339,22 @@ jit_stack_trace_t jit_exception_get_stack_trace(void) /* Populate the stack trace with the items we counted earlier */ size = 0; - item = top; - while(item != 0) - { - trace->items[size] = item->pc; - ++size; - item = item->parent; - } -#else - void *frame = jit_get_current_frame(); - - /* Count the number of items in the current thread's call stack */ - while(frame != 0) + if(jit_unwind_init(&unwind, NULL)) { - frame = jit_get_next_frame_address(frame); - ++size; + do + { + trace->items[size] = jit_unwind_get_pc(&unwind); + size++; + } + while(jit_unwind_next_pc(&unwind)); + jit_unwind_free(&unwind); } - - /* Allocate memory for the stack trace */ - trace = (jit_stack_trace_t)jit_malloc - (sizeof(struct jit_stack_trace) + - size * sizeof(void *) - sizeof(void *)); - if(!trace) + else { + jit_free(trace); return 0; } - trace->size = size; - /* Populate the stack trace with the items we counted earlier */ - size = 0; - frame = jit_get_current_frame(); - while(frame != 0) - { - trace->items[size] = jit_get_return_address(frame); - frame = jit_get_next_frame_address(frame); - ++size; - } -#endif return trace; } @@ -469,7 +448,7 @@ unsigned int jit_stack_trace_get_offset } } } - return JIT_CACHE_NO_OFFSET; + return JIT_NO_OFFSET; } /*@ diff --git a/jit/jit-unwind.c b/jit/jit-unwind.c new file mode 100644 index 0000000..d88d6de --- /dev/null +++ b/jit/jit-unwind.c @@ -0,0 +1,212 @@ +/* + * jit-unwind.c - Routines for performing stack unwinding. + * + * Copyright (C) 2008 Southern Storm Software, Pty Ltd. + * + * This file is part of the libjit library. + * + * The libjit library is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation, either version 2.1 of + * the License, or (at your option) any later version. + * + * The libjit library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the libjit library. If not, see + * . + */ + +#include "jit-internal.h" +#include "jit-cache.h" +#include "jit-rules.h" +#include "jit-apply-rules.h" +#include +#include + +int +jit_unwind_init(jit_unwind_context_t *unwind, jit_context_t context) +{ +#if defined(JIT_BACKENED_INTERP) || JIT_APPLY_BROKEN_FRAME_BUILTINS != 0 + jit_thread_control_t control; + + control = _jit_thread_get_control(); + if(!control) + { + return 0; + } + + unwind->frame = control->backtrace_head; +#elif JIT_FAST_GET_CURRENT_FRAME != 0 + unwind->frame = jit_get_next_frame_address(jit_get_current_frame()); +#else + unwind->frame = jit_get_frame_address(1); +#endif + + unwind->context = context; + unwind->cache = 0; + +#ifdef _JIT_ARCH_UNWIND_INIT + _JIT_ARCH_UNWIND_INIT(unwind); +#endif + + return (unwind->frame != 0); +} + +void +jit_unwind_free(jit_unwind_context_t *unwind) +{ +#ifdef _JIT_ARCH_UNWIND_FREE + _JIT_ARCH_UNWIND_FREE(unwind); +#endif +} + +int +jit_unwind_next(jit_unwind_context_t *unwind) +{ +#if defined(_JIT_ARCH_UNWIND_NEXT) || defined(_JIT_ARCH_UNWIND_NEXT_PRE) + jit_function_t func; +#endif + + if(!unwind || !unwind->frame) + { + return 0; + } + + unwind->cache = 0; + +#if defined(JIT_BACKENED_INTERP) || JIT_APPLY_BROKEN_FRAME_BUILTINS != 0 + unwind->frame = ((jit_backtrace_t) unwind->frame)->parent; + return (unwind->frame != 0); +#else + +#ifdef _JIT_ARCH_UNWIND_NEXT_PRE + func = jit_unwind_get_function(unwind); + if(func) + { + _JIT_ARCH_UNWIND_NEXT_PRE(unwind, func); + } +#endif + + unwind->frame = jit_get_next_frame_address(unwind->frame); + if(!unwind->frame) + { + return 0; + } + +#ifdef _JIT_ARCH_UNWIND_NEXT + func = jit_unwind_get_function(unwind); + if(func) + { + _JIT_ARCH_UNWIND_NEXT(unwind, func); + } +#endif + + return 1; +#endif +} + +int +jit_unwind_next_pc(jit_unwind_context_t *unwind) +{ + if(!unwind || !unwind->frame) + { + return 0; + } + + unwind->cache = 0; + +#if defined(JIT_BACKENED_INTERP) || JIT_APPLY_BROKEN_FRAME_BUILTINS != 0 + unwind->frame = ((jit_backtrace_t) unwind->frame)->parent; +#else + unwind->frame = jit_get_next_frame_address(unwind->frame); +#endif + return (unwind->frame != 0); +} + +void * +jit_unwind_get_pc(jit_unwind_context_t *unwind) +{ + if(!unwind || !unwind->frame) + { + return 0; + } + +#if defined(JIT_BACKENED_INTERP) || JIT_APPLY_BROKEN_FRAME_BUILTINS != 0 + return ((jit_backtrace_t) unwind->frame)->pc; +#else + return jit_get_return_address(unwind->frame); +#endif +} + +int +jit_unwind_jump(jit_unwind_context_t *unwind, void *pc) +{ +#ifdef _JIT_ARCH_UNWIND_JUMP + if(!unwind || !unwind->frame || !pc) + { + return 0; + } + + return _JIT_ARCH_UNWIND_JUMP(unwind, pc); +#else + return 0; +#endif +} + +jit_function_t +jit_unwind_get_function(jit_unwind_context_t *unwind) +{ + if(!unwind || !unwind->frame || !unwind->context) + { + return 0; + } + + if(!unwind->cache) + { + jit_cache_t cache = _jit_context_get_cache(unwind->context); + void *pc = jit_unwind_get_pc(unwind); + unwind->cache = (jit_function_t) + _jit_cache_get_method(cache, pc, NULL); + } + + return (jit_function_t) unwind->cache; +} + +unsigned int +jit_unwind_get_offset(jit_unwind_context_t *unwind) +{ + jit_function_t func; + jit_cache_t cache; + void *pc, *start; + + if(!unwind || !unwind->frame || !unwind->context) + { + return JIT_NO_OFFSET; + } + + pc = jit_unwind_get_pc(unwind); + if(!pc) + { + return JIT_NO_OFFSET; + } + + func = jit_unwind_get_function(unwind); + if(!func) + { + return JIT_NO_OFFSET; + } + + cache = _jit_context_get_cache(unwind->context); + +#ifdef JIT_PROLOG_SIZE + start = _jit_cache_get_start_method(cache, func->entry_point); +#else + start = func->entry_point; +#endif + + return _jit_cache_get_bytecode(cache, start, pc - start, 0); +} -- 2.47.3