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 | |
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.
-rw-r--r-- | runtime/ChangeLog | 12 | ||||
-rw-r--r-- | runtime/arith.c | 440 | ||||
-rw-r--r-- | runtime/copy.c | 2 | ||||
-rw-r--r-- | runtime/loc2c-runtime.h | 38 | ||||
-rw-r--r-- | runtime/regs.c | 70 | ||||
-rw-r--r-- | runtime/regs.h | 6 | ||||
-rw-r--r-- | runtime/stack-arm.c | 72 | ||||
-rw-r--r-- | runtime/stack.c | 2 | ||||
-rw-r--r-- | runtime/time.c | 8 |
9 files changed, 541 insertions, 109 deletions
diff --git a/runtime/ChangeLog b/runtime/ChangeLog index a5a094f0..b96623bb 100644 --- a/runtime/ChangeLog +++ b/runtime/ChangeLog @@ -1,3 +1,15 @@ +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. + 2007-05-29 Frank Ch. Eigler <fche@elastic.org> PR 4458 diff --git a/runtime/arith.c b/runtime/arith.c index 97121ae8..60576090 100644 --- a/runtime/arith.c +++ b/runtime/arith.c @@ -20,7 +20,7 @@ /* 64-bit division for 64-bit cpus and i386 */ /* Other 32-bit cpus will need to modify this file. */ -#ifdef __i386__ +#if defined (__i386__) || defined(__arm__) long long _div64 (long long u, long long v); long long _mod64 (long long u, long long v); #endif @@ -46,7 +46,7 @@ int64_t _stp_div64 (const char **error, int64_t x, int64_t y) if (unlikely (y == -1)) return -x; -#ifdef __LP64__ +#if defined (__LP64__) return x/y; #else if (likely ((x >= LONG_MIN && x <= LONG_MAX) && @@ -72,7 +72,7 @@ int64_t _stp_mod64 (const char **error, int64_t x, int64_t y) if (unlikely (y == 1 || y == -1)) return 0; -#ifdef __LP64__ +#if defined (__LP64__) return x%y; #else if (likely ((x >= LONG_MIN && x <= LONG_MAX) && @@ -106,14 +106,15 @@ int _stp_random_pm (int n) #endif /* _STP_TEST_ */ +#if defined (__i386__) || defined (__arm__) -#ifdef __i386__ /* 64-bit division functions extracted from libgcc */ typedef long long DWtype; typedef unsigned long long UDWtype; typedef unsigned long UWtype; typedef long Wtype; typedef unsigned int USItype; +typedef unsigned int UQItype __attribute__ ((mode (QI))); #ifdef _BIG_ENDIAN struct DWstruct {Wtype high, low;}; @@ -121,8 +122,15 @@ struct DWstruct {Wtype high, low;}; struct DWstruct {Wtype low, high;}; #endif +#define __CLOBBER_CC : "cc" + #define W_TYPE_SIZE 32 +#define __BITS4 (W_TYPE_SIZE / 4) +#define __ll_B ((UWtype) 1 << (W_TYPE_SIZE / 2)) +#define __ll_lowpart(t) ((UWtype) (t) & (__ll_B - 1)) +#define __ll_highpart(t) ((UWtype) (t) >> (W_TYPE_SIZE / 2)) + typedef union { struct DWstruct s; @@ -130,6 +138,7 @@ typedef union } DWunion; +#if defined (__i386__) /* these are the i386 versions of these macros from gcc/longlong.h */ #define umul_ppmm(w1, w0, u, v) \ @@ -164,111 +173,330 @@ typedef union (count) = __cbtmp ^ 31; \ } while (0) -inline UDWtype _stp_udivmoddi4 (UDWtype n, UDWtype d, UDWtype *rp) +#elif defined (__arm__) + +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("subs %1, %4, %5\n\tsbc %0, %2, %3" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "r" ((USItype) (ah)), \ + "rI" ((USItype) (bh)), \ + "r" ((USItype) (al)), \ + "rI" ((USItype) (bl)) __CLOBBER_CC) +#define umul_ppmm(xh, xl, a, b) \ +{register USItype __t0, __t1, __t2; \ + __asm__ ("%@ Inlined umul_ppmm\n" \ + " mov %2, %5, lsr #16\n" \ + " mov %0, %6, lsr #16\n" \ + " bic %3, %5, %2, lsl #16\n" \ + " bic %4, %6, %0, lsl #16\n" \ + " mul %1, %3, %4\n" \ + " mul %4, %2, %4\n" \ + " mul %3, %0, %3\n" \ + " mul %0, %2, %0\n" \ + " adds %3, %4, %3\n" \ + " addcs %0, %0, #65536\n" \ + " adds %1, %1, %3, lsl #16\n" \ + " adc %0, %0, %3, lsr #16" \ + : "=&r" ((USItype) (xh)), \ + "=r" ((USItype) (xl)), \ + "=&r" (__t0), "=&r" (__t1), "=r" (__t2) \ + : "r" ((USItype) (a)), \ + "r" ((USItype) (b)) __CLOBBER_CC );} + +#endif + +#define __udiv_qrnnd_c(q, r, n1, n0, d) \ + do { \ + UWtype __d1, __d0, __q1, __q0; \ + UWtype __r1, __r0, __m; \ + __d1 = __ll_highpart (d); \ + __d0 = __ll_lowpart (d); \ + \ + __r1 = (n1) % __d1; \ + __q1 = (n1) / __d1; \ + __m = (UWtype) __q1 * __d0; \ + __r1 = __r1 * __ll_B | __ll_highpart (n0); \ + if (__r1 < __m) \ + { \ + __q1--, __r1 += (d); \ + if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */\ + if (__r1 < __m) \ + __q1--, __r1 += (d); \ + } \ + __r1 -= __m; \ + \ + __r0 = __r1 % __d1; \ + __q0 = __r1 / __d1; \ + __m = (UWtype) __q0 * __d0; \ + __r0 = __r0 * __ll_B | __ll_lowpart (n0); \ + if (__r0 < __m) \ + { \ + __q0--, __r0 += (d); \ + if (__r0 >= (d)) \ + if (__r0 < __m) \ + __q0--, __r0 += (d); \ + } \ + __r0 -= __m; \ + \ + (q) = (UWtype) __q1 * __ll_B | __q0; \ + (r) = __r0; \ + } while (0) + +#if !defined (udiv_qrnnd) +#define UDIV_NEEDS_NORMALIZATION 1 +#define udiv_qrnnd __udiv_qrnnd_c +#else +#define UDIV_NEEDS_NORMALIZATION 0 +#endif + +#if !defined (count_leading_zeros) +const UQItype _stp_clz_tab[256] = { - const DWunion nn = {.ll = n}; - const DWunion dd = {.ll = d}; - DWunion ww,rr; - UWtype d0, d1, n0, n1, n2; - UWtype q0, q1; - UWtype b, bm; - - d0 = dd.s.low; - d1 = dd.s.high; - n0 = nn.s.low; - n1 = nn.s.high; - - if (d1 == 0) { - if (d0 > n1) { - /* 0q = nn / 0D */ - udiv_qrnnd (q0, n0, n1, n0, d0); - q1 = 0; - /* Remainder in n0. */ - } else { - /* qq = NN / 0d */ - if (d0 == 0) - d0 = 1 / d0; /* Divide intentionally by zero. */ - udiv_qrnnd (q1, n1, 0, n1, d0); - udiv_qrnnd (q0, n0, n1, n0, d0); - /* Remainder in n0. */ + 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 +}; + +#define count_leading_zeros(count, x) \ + do { \ + UWtype __xr = (x); \ + UWtype __a; \ + \ + if (W_TYPE_SIZE <= 32) \ + { \ + __a = __xr < ((UWtype)1<<2*__BITS4) \ + ? (__xr < ((UWtype)1<<__BITS4) ? 0 : __BITS4) \ + : (__xr < ((UWtype)1<<3*__BITS4) ? 2*__BITS4 : 3*__BITS4); \ + } \ + else \ + { \ + for (__a = W_TYPE_SIZE - 8; __a > 0; __a -= 8) \ + if (((__xr >> __a) & 0xff) != 0) \ + break; \ + } \ + \ + (count) = W_TYPE_SIZE - (_stp_clz_tab[__xr >> __a] + __a); \ + } while (0) +#define COUNT_LEADING_ZEROS_0 W_TYPE_SIZE +#endif + +UDWtype +_stp_udivmoddi4 (UDWtype n, UDWtype d, UDWtype *rp) +{ + const DWunion nn = {.ll = n}; + const DWunion dd = {.ll = d}; + DWunion ww, rr; + UWtype d0, d1, n0, n1, n2; + UWtype q0, q1; + UWtype b, bm; + + d0 = dd.s.low; + d1 = dd.s.high; + n0 = nn.s.low; + n1 = nn.s.high; + +#if !UDIV_NEEDS_NORMALIZATION + if (d1 == 0) + { + if (d0 > n1) + { + /* 0q = nn / 0D */ + + udiv_qrnnd (q0, n0, n1, n0, d0); + q1 = 0; + + /* Remainder in n0. */ + } + else + { + /* qq = NN / 0d */ + + if (d0 == 0) + d0 = 1 / d0; /* Divide intentionally by zero. */ + + udiv_qrnnd (q1, n1, 0, n1, d0); + udiv_qrnnd (q0, n0, n1, n0, d0); + + /* Remainder in n0. */ + } + + if (rp != 0) + { + rr.s.low = n0; + rr.s.high = 0; + *rp = rr.ll; + } + } + +#else /* UDIV_NEEDS_NORMALIZATION */ + + if (d1 == 0) + { + if (d0 > n1) + { + /* 0q = nn / 0D */ + + count_leading_zeros (bm, d0); + + if (bm != 0) + { + /* Normalize, i.e. make the most significant bit of the + denominator set. */ + + d0 = d0 << bm; + n1 = (n1 << bm) | (n0 >> (W_TYPE_SIZE - bm)); + n0 = n0 << bm; + } + + udiv_qrnnd (q0, n0, n1, n0, d0); + q1 = 0; + + /* Remainder in n0 >> bm. */ + } + else + { + /* qq = NN / 0d */ + + if (d0 == 0) + d0 = 1 / d0; /* Divide intentionally by zero. */ + + count_leading_zeros (bm, d0); + + if (bm == 0) + { + /* From (n1 >= d0) /\ (the most significant bit of d0 is set), + conclude (the most significant bit of n1 is set) /\ (the + leading quotient digit q1 = 1). + + This special case is necessary, not an optimization. + (Shifts counts of W_TYPE_SIZE are undefined.) */ + + n1 -= d0; + q1 = 1; + } + else + { + /* Normalize. */ + + b = W_TYPE_SIZE - bm; + + d0 = d0 << bm; + n2 = n1 >> b; + n1 = (n1 << bm) | (n0 >> b); + n0 = n0 << bm; + + udiv_qrnnd (q1, n1, n2, n1, d0); + } + + /* n1 != d0... */ + + udiv_qrnnd (q0, n0, n1, n0, d0); + + /* Remainder in n0 >> bm. */ + } + + if (rp != 0) + { + rr.s.low = n0 >> bm; + rr.s.high = 0; + *rp = rr.ll; + } + } +#endif /* UDIV_NEEDS_NORMALIZATION */ + + else + { + if (d1 > n1) + { + /* 00 = nn / DD */ + + q0 = 0; + q1 = 0; + + /* Remainder in n1n0. */ + if (rp != 0) + { + rr.s.low = n0; + rr.s.high = n1; + *rp = rr.ll; + } + } + else + { + /* 0q = NN / dd */ + + count_leading_zeros (bm, d1); + if (bm == 0) + { + /* From (n1 >= d1) /\ (the most significant bit of d1 is set), + conclude (the most significant bit of n1 is set) /\ (the + quotient digit q0 = 0 or 1). + + This special case is necessary, not an optimization. */ + + /* The condition on the next line takes advantage of that + n1 >= d1 (true due to program flow). */ + if (n1 > d1 || n0 >= d0) + { + q0 = 1; + sub_ddmmss (n1, n0, n1, n0, d1, d0); } - - if (rp != 0) { - rr.s.low = n0; - rr.s.high = 0; - *rp = rr.ll; + else + q0 = 0; + + q1 = 0; + + if (rp != 0) + { + rr.s.low = n0; + rr.s.high = n1; + *rp = rr.ll; } - } else { - if (d1 > n1) { - /* 00 = nn / DD */ - q0 = 0; - q1 = 0; - - /* Remainder in n1n0. */ - if (rp != 0) { - rr.s.low = n0; - rr.s.high = n1; - *rp = rr.ll; - } - } else { - /* 0q = NN / dd */ - count_leading_zeros (bm, d1); - if (bm == 0) { - /* From (n1 >= d1) /\ (the most significant bit of d1 is set), - conclude (the most significant bit of n1 is set) /\ (the - quotient digit q0 = 0 or 1). - This special case is necessary, not an optimization. */ - - /* The condition on the next line takes advantage of that - n1 >= d1 (true due to program flow). */ - if (n1 > d1 || n0 >= d0) { - q0 = 1; - sub_ddmmss (n1, n0, n1, n0, d1, d0); - } else - q0 = 0; - - q1 = 0; - - if (rp != 0) { - rr.s.low = n0; - rr.s.high = n1; - *rp = rr.ll; - } - } else { - UWtype m1, m0; - /* Normalize. */ - - b = W_TYPE_SIZE - bm; - - d1 = (d1 << bm) | (d0 >> b); - d0 = d0 << bm; - n2 = n1 >> b; - n1 = (n1 << bm) | (n0 >> b); - n0 = n0 << bm; - - udiv_qrnnd (q0, n1, n2, n1, d1); - umul_ppmm (m1, m0, q0, d0); - - if (m1 > n1 || (m1 == n1 && m0 > n0)) { - q0--; - sub_ddmmss (m1, m0, m1, m0, d1, d0); - } - - q1 = 0; - - /* Remainder in (n1n0 - m1m0) >> bm. */ - if (rp != 0) { - sub_ddmmss (n1, n0, n1, n0, m1, m0); - rr.s.low = (n1 << b) | (n0 >> bm); - rr.s.high = n1 >> bm; - *rp = rr.ll; - } - } + } + else + { + UWtype m1, m0; + /* Normalize. */ + + b = W_TYPE_SIZE - bm; + + d1 = (d1 << bm) | (d0 >> b); + d0 = d0 << bm; + n2 = n1 >> b; + n1 = (n1 << bm) | (n0 >> b); + n0 = n0 << bm; + + udiv_qrnnd (q0, n1, n2, n1, d1); + umul_ppmm (m1, m0, q0, d0); + + if (m1 > n1 || (m1 == n1 && m0 > n0)) + { + q0--; + sub_ddmmss (m1, m0, m1, m0, d1, d0); + } + + q1 = 0; + + /* Remainder in (n1n0 - m1m0) >> bm. */ + if (rp != 0) + { + sub_ddmmss (n1, n0, n1, n0, m1, m0); + rr.s.low = (n1 << b) | (n0 >> bm); + rr.s.high = n1 >> bm; + *rp = rr.ll; } + } } - - ww.s.low = q0; ww.s.high = q1; - return ww.ll; + } + + ww.s.low = q0; ww.s.high = q1; + return ww.ll; } long long _div64 (long long u, long long v) @@ -311,5 +539,7 @@ long long _mod64 (long long u, long long v) return w; } -#endif /* __i386__ */ + +#endif /* __i386__ || __arm__ */ + #endif /* _ARITH_C_ */ diff --git a/runtime/copy.c b/runtime/copy.c index da27673c..ef3fd223 100644 --- a/runtime/copy.c +++ b/runtime/copy.c @@ -85,7 +85,7 @@ do { \ : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \ : "memory"); \ } while (0) -#elif defined (__powerpc64__) || defined (__ia64__) +#elif defined (__powerpc64__) || defined (__ia64__) || defined (__arm__) #define __stp_strncpy_from_user(dst,src,count,res) \ do { res = __strncpy_from_user(dst, src, count); } while(0) diff --git a/runtime/loc2c-runtime.h b/runtime/loc2c-runtime.h index 9c84f6df..df180949 100644 --- a/runtime/loc2c-runtime.h +++ b/runtime/loc2c-runtime.h @@ -112,6 +112,13 @@ #define fetch_register(regno) ((intptr_t) c->regs->gpr[regno]) #define store_register(regno) (c->regs->gpr[regno] = (value)) +#elif defined (__arm__) + +#undef fetch_register +#undef store_register +#define fetch_register(regno) ((long) c->regs->uregs[regno]) +#define store_register(regno) (c->regs->uregs[regno] = (value)) + #elif defined (__s390__) || defined (__s390x__) #undef fetch_register #undef store_register @@ -294,6 +301,37 @@ goto deref_fault; \ }) +#elif defined (__arm__) + +#define deref(size, addr) \ + ({ \ + int _bad = 0; \ + intptr_t _v=0; \ + switch (size){ \ + case 1: __get_user_asm_byte(_v, addr, _bad); break; \ + case 2: __get_user_asm_half(_v, addr, _bad); break; \ + case 4: __get_user_asm_word(_v, addr, _bad); break; \ + default: __get_user_bad(); break; \ + } \ + if (_bad) \ + goto deref_fault; \ + _v; \ + }) + +#define store_deref(size, addr, value) \ + ({ \ + int _bad=0; \ + switch (size){ \ + case 1: __put_user_asm_byte(value, addr, _bad); break; \ + case 2: __put_user_asm_half(value, addr, _bad); break; \ + case 4: __put_user_asm_word(value, addr, _bad); break; \ + case 8: __put_user_asm_dword(value, addr, _bad); break; \ + default: __put_user_bad(); break; \ + } \ + if (_bad) \ + goto deref_fault; \ + }) + #elif defined (__s390__) || defined (__s390x__) #ifndef EX_TABLE diff --git a/runtime/regs.c b/runtime/regs.c index 227a237e..d202c8aa 100644 --- a/runtime/regs.c +++ b/runtime/regs.c @@ -1,7 +1,8 @@ /* -*- linux-c -*- * Functions to access the members of pt_regs struct - * Copyright (C) 2005 Red Hat Inc. + * Copyright (C) 2005, 2007 Red Hat Inc. * Copyright (C) 2005 Intel Corporation. + * 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 @@ -40,7 +41,7 @@ unsigned long _stp_ret_addr (struct pt_regs *regs) return 0; #elif defined (__i386__) return regs->esp; -#elif defined (__powerpc64__) +#elif defined (__powerpc64__) || defined (__arm__) return REG_LINK(regs); #elif defined (__ia64__) return regs->b0; @@ -207,6 +208,71 @@ void _stp_print_regs(struct pt_regs * regs) _stp_printf("LR [%016lx]\n", regs->link); } +#elif defined (__arm__) + +static const char *processor_modes[]= +{ "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" , + "UK8_26" , "UK9_26" , "UK10_26", "UK11_26", "UK12_26", "UK13_26", "UK14_26", "UK15_26", + "USER_32", "FIQ_32" , "IRQ_32" , "SVC_32" , "UK4_32" , "UK5_32" , "UK6_32" , "ABT_32" , + "UK8_32" , "UK9_32" , "UK10_32", "UND_32" , "UK12_32", "UK13_32", "UK14_32", "SYS_32" +}; + + +void _stp_print_regs(struct pt_regs * regs) +{ + unsigned long flags = condition_codes(regs); + +#ifdef CONFIG_SMP + _stp_printf(" CPU: %d", smp_processor_id()); +#endif /* CONFIG_SMP */ + + _stp_printf("pc : [<%08lx>] lr : [<%08lx>]\n" + "sp : %08lx ip : %08lx fp : %08lx\n", + instruction_pointer(regs), + regs->ARM_lr, regs->ARM_sp, + regs->ARM_ip, regs->ARM_fp); + _stp_printf("r10: %08lx r9 : %08lx r8 : %08lx\n", + regs->ARM_r10, regs->ARM_r9, + regs->ARM_r8); + _stp_printf("r7 : %08lx r6 : %08lx r5 : %08lx r4 : %08lx\n", + regs->ARM_r7, regs->ARM_r6, + regs->ARM_r5, regs->ARM_r4); + _stp_printf("r3 : %08lx r2 : %08lx r1 : %08lx r0 : %08lx\n", + regs->ARM_r3, regs->ARM_r2, + regs->ARM_r1, regs->ARM_r0); + _stp_printf("Flags: %c%c%c%c", + flags & PSR_N_BIT ? 'N' : 'n', + flags & PSR_Z_BIT ? 'Z' : 'z', + flags & PSR_C_BIT ? 'C' : 'c', + flags & PSR_V_BIT ? 'V' : 'v'); + _stp_printf(" IRQs o%s FIQs o%s Mode %s%s Segment %s\n", + interrupts_enabled(regs) ? "n" : "ff", + fast_interrupts_enabled(regs) ? "n" : "ff", + processor_modes[processor_mode(regs)], + thumb_mode(regs) ? " (T)" : "", + get_fs() == get_ds() ? "kernel" : "user"); +#if CONFIG_CPU_CP15 + { + unsigned int ctrl; + __asm__ ( + " mrc p15, 0, %0, c1, c0\n" + : "=r" (ctrl)); + _stp_printf("Control: %04X\n", ctrl); + } +#ifdef CONFIG_CPU_CP15_MMU + { + unsigned int transbase, dac; + __asm__ ( + " mrc p15, 0, %0, c2, c0\n" + " mrc p15, 0, %1, c3, c0\n" + : "=r" (transbase), "=r" (dac)); + _stp_printf("Table: %08X DAC: %08X\n", + transbase, dac); + } +#endif +#endif +} + #elif defined (__s390x__) || defined (__s390__) #ifdef __s390x__ diff --git a/runtime/regs.h b/runtime/regs.h index 580e0d8d..0887d628 100644 --- a/runtime/regs.h +++ b/runtime/regs.h @@ -32,6 +32,12 @@ #define REG_SP(regs) regs->gpr[1] #define REG_LINK(regs) regs->link +#elif defined (__arm__) + +#define REG_IP(regs) regs->ARM_pc +#define REG_SP(regs) regs->ARM_sp +#define REG_LINK(regs) regs->ARM_lr + #elif defined (__s390__) || defined (__s390x__) #ifndef __s390x__ #define PSW_ADDR_AMODE 0x80000000UL 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 +} diff --git a/runtime/stack.c b/runtime/stack.c index dcf23e06..5dc627b7 100644 --- a/runtime/stack.c +++ b/runtime/stack.c @@ -35,6 +35,8 @@ static int _stp_kta(unsigned long addr); #include "stack-i386.c" #elif defined (__powerpc64__) #include "stack-ppc64.c" +#elif defined (__arm__) +#include "stack-arm.c" #elif defined (__s390__) || defined (__s390x__) #include "stack-s390.c" #else diff --git a/runtime/time.c b/runtime/time.c index 657b5e8c..275fd98d 100644 --- a/runtime/time.c +++ b/runtime/time.c @@ -61,7 +61,7 @@ int stp_timer_reregister = 0; static unsigned int __stp_estimate_cpufreq(void) { -#if defined (__s390__) || defined (__s390x__) +#if defined (__s390__) || defined (__s390x__) || defined (__arm__) // We don't need to find the cpu freq on s390 as the // TOD clock is always a fix freq. (see: POO pg 4-36.) return 0; @@ -255,6 +255,12 @@ _stp_gettimeofday_ns(void) delta = (delta * 125) >> 7; +#elif defined (__arm__) + + /* arm always returns 0 for get_cycles() */ + /* so this is just a fake value until we get a real fix. */ + delta = 1000; + #else /* __s390__ || __s390x__ */ // Verify units: |