]>
Commit | Line | Data |
---|---|---|
5a24160a WC |
1 | /* Dwarfless register access for arm */ |
2 | ||
3 | global _reg_offsets, _stp_regs_registered | |
4 | ||
5 | function _stp_register_regs() { | |
6 | ||
7 | /* Same order as pt_regs */ | |
8 | _reg_offsets["r0"] = 0 _reg_offsets["a1"] = 0 | |
9 | _reg_offsets["r1"] = 4 _reg_offsets["a2"] = 4 | |
10 | _reg_offsets["r2"] = 8 _reg_offsets["a3"] = 8 | |
11 | _reg_offsets["r3"] = 12 _reg_offsets["a4"] = 12 | |
12 | _reg_offsets["r4"] = 16 _reg_offsets["v1"] = 16 | |
13 | _reg_offsets["r5"] = 20 _reg_offsets["v2"] = 20 | |
14 | _reg_offsets["r6"] = 24 _reg_offsets["v3"] = 24 | |
15 | _reg_offsets["r7"] = 28 _reg_offsets["v4"] = 28 | |
16 | _reg_offsets["r8"] = 32 _reg_offsets["v5"] = 32 | |
17 | _reg_offsets["r9"] = 36 _reg_offsets["v6"] = 36 | |
18 | _reg_offsets["r10"] = 40 _reg_offsets["v7"] = 40 | |
19 | _reg_offsets["fp"] = 44 _reg_offsets["v8"] = 44 | |
20 | _reg_offsets["ip"] = 48 | |
21 | _reg_offsets["sp"] = 52 | |
22 | _reg_offsets["lr"] = 56 | |
23 | _reg_offsets["pc"] = 60 | |
24 | _reg_offsets["cpsr"] = 64 | |
25 | _reg_offsets["orig_r0"] = 68 | |
26 | ||
27 | _stp_regs_registered = 1 | |
28 | } | |
29 | ||
30 | function _stp_get_register_by_offset:long (offset:long) %{ /* pure */ | |
31 | long value; | |
d9aed31e | 32 | struct pt_regs *regs; |
f52d32a9 | 33 | if (CONTEXT->probe_flags & _STP_PROBE_STATE_USER_MODE) { |
d9aed31e | 34 | regs = CONTEXT->uregs; |
6c40239d MW |
35 | } else { |
36 | regs = CONTEXT->kregs; | |
d9aed31e MW |
37 | } |
38 | if (!regs) { | |
5a24160a WC |
39 | CONTEXT->last_error = "No registers available in this context"; |
40 | return; | |
41 | } | |
42 | if (THIS->offset < 0 || THIS->offset > sizeof(struct pt_regs) - sizeof(long)) { | |
43 | snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), | |
44 | "Bad register offset: %lld", THIS->offset); | |
45 | CONTEXT->last_error = CONTEXT->error_buffer; | |
46 | return; | |
47 | } | |
d9aed31e | 48 | memcpy(&value, ((char *)regs) + THIS->offset, sizeof(value)); |
5a24160a WC |
49 | THIS->__retvalue = value; |
50 | %} | |
51 | ||
92c25572 MW |
52 | function _stp_probing_kernel:long () { |
53 | return !user_mode(); | |
54 | } | |
5a24160a WC |
55 | |
56 | /* Return the named register value as a signed value. */ | |
57 | function register:long (name:string) { | |
58 | if (!registers_valid()) { | |
59 | error("cannot access CPU registers in this context") | |
60 | return 0 | |
61 | } | |
62 | if (!_stp_regs_registered) | |
63 | _stp_register_regs() | |
64 | offset = _reg_offsets[name] | |
65 | if (offset == 0 && !(name in _reg_offsets)) { | |
66 | error("Unknown register: " . name) | |
67 | return 0 | |
68 | } | |
69 | return _stp_get_register_by_offset(offset) | |
70 | } | |
71 | ||
72 | /* | |
73 | * Return the named register value as an unsigned value. Specifically, | |
74 | * don't sign-extend the register value when promoting it to 64 bits. | |
75 | */ | |
76 | function u_register:long (name:string) { | |
77 | return register(name) & 0xffffffff; | |
78 | } | |
79 | ||
80 | /* Return the value of function arg #argnum (1=first arg) as a signed value. | |
81 | * | |
82 | * We don't yet support extracting arg #5 and beyond, which are passed | |
83 | * on stack | |
84 | */ | |
85 | function _stp_arg:long (argnum:long) { | |
86 | val = 0 | |
87 | if (argnum < 1 || argnum > 4) { | |
88 | error(sprintf("Cannot access arg(%d)", argnum)) | |
89 | return 0 | |
90 | } | |
91 | ||
92 | if (argnum == 1) | |
f52d32a9 | 93 | val = register("r0") |
5a24160a | 94 | else if (argnum == 2) |
f52d32a9 | 95 | val = register("r1") |
5a24160a | 96 | else if (argnum == 3) |
f52d32a9 | 97 | val = register("r2") |
5a24160a | 98 | else if (argnum == 4) |
f52d32a9 | 99 | val = register("r3") |
5a24160a WC |
100 | |
101 | return val; | |
102 | } | |
103 | ||
104 | /* Return the value of function arg #argnum as a signed int. */ | |
105 | function int_arg:long (argnum:long) { | |
106 | return _stp_arg(argnum) | |
107 | } | |
108 | ||
109 | /* Return the value of function arg #argnum as an unsigned int. */ | |
110 | function uint_arg:long (argnum:long) { | |
111 | return _stp_arg(argnum) & 0xffffffff; | |
112 | } | |
113 | ||
114 | function long_arg:long (argnum:long) { | |
115 | return int_arg(argnum) | |
116 | } | |
117 | ||
118 | function ulong_arg:long (argnum:long) { | |
119 | return uint_arg(argnum) | |
120 | } | |
121 | ||
122 | function longlong_arg:long (argnum:long) { | |
123 | /* | |
124 | * TODO: If argnum == nr_regarg, gcc puts the whole 64-bit arg | |
125 | * on the stack. | |
126 | */ | |
127 | lowbits = uint_arg(argnum) | |
128 | highbits = uint_arg(argnum+1) | |
129 | return ((highbits << 32) | lowbits) | |
130 | } | |
131 | ||
132 | function ulonglong_arg:long (argnum:long) { | |
133 | return longlong_arg(argnum) | |
134 | } | |
135 | ||
136 | function pointer_arg:long (argnum:long) { | |
137 | return ulong_arg(argnum) | |
138 | } | |
139 | ||
140 | function s32_arg:long (argnum:long) { | |
141 | return int_arg(argnum) | |
142 | } | |
143 | ||
144 | function u32_arg:long (argnum:long) { | |
145 | return uint_arg(argnum) | |
146 | } | |
147 | ||
148 | function s64_arg:long (argnum:long) { | |
149 | return longlong_arg(argnum) | |
150 | } | |
151 | ||
152 | function u64_arg:long (argnum:long) { | |
153 | return ulonglong_arg(argnum) | |
154 | } | |
155 | ||
156 | function asmlinkage() %{ /* pure */ %} | |
157 | ||
158 | function fastcall() %{ /* pure */ %} | |
159 | ||
309d67d8 | 160 | function regparm(n:long) %{ |
5a24160a WC |
161 | snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), |
162 | "regparm is invalid on arm."); | |
163 | CONTEXT->last_error = CONTEXT->error_buffer; | |
164 | %} |