diff options
author | hunt <hunt> | 2007-05-30 14:33:55 +0000 |
---|---|---|
committer | hunt <hunt> | 2007-05-30 14:33:55 +0000 |
commit | 79e80fedc4bcac4cd1d5a684537f20a4331efd4e (patch) | |
tree | accd5d9105d2438ae2f0171ee3d3813de1b25f11 /runtime/stack-arm.c | |
parent | 2cbe17e95de653099901e34124ab1a376e150514 (diff) | |
download | systemtap-steved-79e80fedc4bcac4cd1d5a684537f20a4331efd4e.tar.gz systemtap-steved-79e80fedc4bcac4cd1d5a684537f20a4331efd4e.tar.xz systemtap-steved-79e80fedc4bcac4cd1d5a684537f20a4331efd4e.zip |
2007-05-30 Martin Hunt <hunt@redhat.com>
Patch from Quentin Barnes.
* arith.c: Add arm support for 64-bit division.
* copy.c: Enable arm support.
* loc2c-runtime.h: Ditto.
* regs.[ch]: Ditto.
* stack.c: Include stack-arm.c.
* stack-arm.c: New file.
* time.c (_stp_gettimeofday_ns): hack
for arm. See PR 4569.
Diffstat (limited to 'runtime/stack-arm.c')
-rw-r--r-- | runtime/stack-arm.c | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/runtime/stack-arm.c b/runtime/stack-arm.c new file mode 100644 index 00000000..9d3307ec --- /dev/null +++ b/runtime/stack-arm.c @@ -0,0 +1,72 @@ +/* -*- linux-c -*- + * arm stack tracing functions + * Copyright (C) 2007 Quentin Barnes + * + * This file is part of systemtap, and is free software. You can + * redistribute it and/or modify it under the terms of the GNU General + * Public License (GPL); either version 2, or (at your option) any + * later version. + */ + +/* + * For STR and STM instructions, an ARM core may choose to use either + * a +8 or a +12 displacement from the current instruction's address. + * Whichever value is chosen for a given core, it must be the same for + * both instructions and may not change. This function measures it. + */ + +static int __init find_str_pc_offset(void) +{ + int addr; + int scratch; + int ret; + + __asm__("sub %[ret], pc, #4 \n\t" + "str pc, %[addr] \n\t" + "ldr %[scr], %[addr] \n\t" + "sub %[ret], %[scr], %[ret] \n\t" + : [ret] "=r" (ret), [scr] "=r" (scratch), [addr] "+m" (addr) ); + + return ret; +} + + +static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels) +{ +#if defined(CONFIG_FRAME_POINTER) + int pc_offset = find_str_pc_offset(); + unsigned long *fp = (unsigned long *)regs->ARM_fp; + unsigned long *next_fp, *pc; + + if (levels == 0) + --levels; + + while (fp && levels--) { + next_fp = (unsigned long *)*(fp - 3); + pc = (unsigned long *)(*fp - pc_offset); + + /* 0xe92dd8xx == stmfd sp!, { ..., fp, ip, lr, pc } */ + if ((*pc & 0xffffd800) == 0xe92dd800) { + pc -= 1; + + /* Varargs functions have two stmfd instructions. */ + if ((*pc & 0xffff0000) == 0xe92d0000) + pc -= 1; + } + + if (verbose) { + _stp_print_char(' '); + _stp_symbol_print((unsigned long)pc); + _stp_print_char('\n'); + } else { + _stp_printf("%08lx ", pc); + } + + /* Sanity check the next_fp. */ + if (next_fp && next_fp <= fp) + break; + + fp = next_fp; + } +#endif +} |