]>
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; | |
32 | if (!CONTEXT->regs) { | |
33 | CONTEXT->last_error = "No registers available in this context"; | |
34 | return; | |
35 | } | |
36 | if (THIS->offset < 0 || THIS->offset > sizeof(struct pt_regs) - sizeof(long)) { | |
37 | snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), | |
38 | "Bad register offset: %lld", THIS->offset); | |
39 | CONTEXT->last_error = CONTEXT->error_buffer; | |
40 | return; | |
41 | } | |
42 | memcpy(&value, ((char *)CONTEXT->regs) + THIS->offset, sizeof(value)); | |
43 | THIS->__retvalue = value; | |
44 | %} | |
45 | ||
46 | function _stp_probing_kernel:long () %{ /* pure */ | |
47 | THIS->__retvalue = !user_mode(CONTEXT->regs); | |
48 | %} | |
49 | ||
50 | /* Return the named register value as a signed value. */ | |
51 | function register:long (name:string) { | |
52 | if (!registers_valid()) { | |
53 | error("cannot access CPU registers in this context") | |
54 | return 0 | |
55 | } | |
56 | if (!_stp_regs_registered) | |
57 | _stp_register_regs() | |
58 | offset = _reg_offsets[name] | |
59 | if (offset == 0 && !(name in _reg_offsets)) { | |
60 | error("Unknown register: " . name) | |
61 | return 0 | |
62 | } | |
63 | return _stp_get_register_by_offset(offset) | |
64 | } | |
65 | ||
66 | /* | |
67 | * Return the named register value as an unsigned value. Specifically, | |
68 | * don't sign-extend the register value when promoting it to 64 bits. | |
69 | */ | |
70 | function u_register:long (name:string) { | |
71 | return register(name) & 0xffffffff; | |
72 | } | |
73 | ||
74 | /* Return the value of function arg #argnum (1=first arg) as a signed value. | |
75 | * | |
76 | * We don't yet support extracting arg #5 and beyond, which are passed | |
77 | * on stack | |
78 | */ | |
79 | function _stp_arg:long (argnum:long) { | |
80 | val = 0 | |
81 | if (argnum < 1 || argnum > 4) { | |
82 | error(sprintf("Cannot access arg(%d)", argnum)) | |
83 | return 0 | |
84 | } | |
85 | ||
86 | if (argnum == 1) | |
87 | val = u_register("r0") | |
88 | else if (argnum == 2) | |
89 | val = u_register("r1") | |
90 | else if (argnum == 3) | |
91 | val = u_register("r2") | |
92 | else if (argnum == 4) | |
93 | val = u_register("r3") | |
94 | ||
95 | return val; | |
96 | } | |
97 | ||
98 | /* Return the value of function arg #argnum as a signed int. */ | |
99 | function int_arg:long (argnum:long) { | |
100 | return _stp_arg(argnum) | |
101 | } | |
102 | ||
103 | /* Return the value of function arg #argnum as an unsigned int. */ | |
104 | function uint_arg:long (argnum:long) { | |
105 | return _stp_arg(argnum) & 0xffffffff; | |
106 | } | |
107 | ||
108 | function long_arg:long (argnum:long) { | |
109 | return int_arg(argnum) | |
110 | } | |
111 | ||
112 | function ulong_arg:long (argnum:long) { | |
113 | return uint_arg(argnum) | |
114 | } | |
115 | ||
116 | function longlong_arg:long (argnum:long) { | |
117 | /* | |
118 | * TODO: If argnum == nr_regarg, gcc puts the whole 64-bit arg | |
119 | * on the stack. | |
120 | */ | |
121 | lowbits = uint_arg(argnum) | |
122 | highbits = uint_arg(argnum+1) | |
123 | return ((highbits << 32) | lowbits) | |
124 | } | |
125 | ||
126 | function ulonglong_arg:long (argnum:long) { | |
127 | return longlong_arg(argnum) | |
128 | } | |
129 | ||
130 | function pointer_arg:long (argnum:long) { | |
131 | return ulong_arg(argnum) | |
132 | } | |
133 | ||
134 | function s32_arg:long (argnum:long) { | |
135 | return int_arg(argnum) | |
136 | } | |
137 | ||
138 | function u32_arg:long (argnum:long) { | |
139 | return uint_arg(argnum) | |
140 | } | |
141 | ||
142 | function s64_arg:long (argnum:long) { | |
143 | return longlong_arg(argnum) | |
144 | } | |
145 | ||
146 | function u64_arg:long (argnum:long) { | |
147 | return ulonglong_arg(argnum) | |
148 | } | |
149 | ||
150 | function asmlinkage() %{ /* pure */ %} | |
151 | ||
152 | function fastcall() %{ /* pure */ %} | |
153 | ||
154 | function regparm() %{ | |
155 | snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), | |
156 | "regparm is invalid on arm."); | |
157 | CONTEXT->last_error = CONTEXT->error_buffer; | |
158 | %} |