summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhunt <hunt>2007-05-30 14:33:55 +0000
committerhunt <hunt>2007-05-30 14:33:55 +0000
commit79e80fedc4bcac4cd1d5a684537f20a4331efd4e (patch)
treeaccd5d9105d2438ae2f0171ee3d3813de1b25f11
parent2cbe17e95de653099901e34124ab1a376e150514 (diff)
downloadsystemtap-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/ChangeLog12
-rw-r--r--runtime/arith.c440
-rw-r--r--runtime/copy.c2
-rw-r--r--runtime/loc2c-runtime.h38
-rw-r--r--runtime/regs.c70
-rw-r--r--runtime/regs.h6
-rw-r--r--runtime/stack-arm.c72
-rw-r--r--runtime/stack.c2
-rw-r--r--runtime/time.c8
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: