]>
Commit | Line | Data |
---|---|---|
4ff1e447 JK |
1 | /* Dwarfless register access for s390x */ |
2 | ||
3 | global _reg_offsets, _stp_regs_registered | |
4 | ||
5 | function _stp_register_regs() { | |
6 | /* Same order as pt_regs */ | |
7 | _reg_offsets["args"] = 0 | |
8 | _reg_offsets["psw.mask"] = 8 | |
9 | _reg_offsets["psw.addr"] = 16 | |
10 | _reg_offsets["r0"] = 24 | |
11 | _reg_offsets["r1"] = 32 | |
12 | _reg_offsets["r2"] = 40 | |
13 | _reg_offsets["r3"] = 48 | |
14 | _reg_offsets["r4"] = 56 | |
15 | _reg_offsets["r5"] = 64 | |
16 | _reg_offsets["r6"] = 72 | |
17 | _reg_offsets["r7"] = 80 | |
18 | _reg_offsets["r8"] = 88 | |
19 | _reg_offsets["r9"] = 96 | |
20 | _reg_offsets["r10"] = 104 | |
21 | _reg_offsets["r11"] = 112 | |
22 | _reg_offsets["r12"] = 120 | |
23 | _reg_offsets["r13"] = 128 | |
24 | _reg_offsets["r14"] = 136 | |
25 | _reg_offsets["r15"] = 144 | |
26 | ||
27 | _reg_offsets["orig_gpr2"] = 152 | |
28 | _reg_offsets["ilc"] = 160 | |
29 | _reg_offsets["trap"] = 162 | |
30 | ||
31 | /* | |
32 | * If we ever need to support s390 (31-bit arch), we can | |
33 | * get to the register offsets by using just a | |
34 | * reg32_offset = _reg_offsets["reg"]/2 | |
35 | * or somesuch | |
36 | */ | |
37 | _stp_regs_registered = 1 | |
38 | } | |
39 | ||
40 | ||
41 | /* | |
42 | * Though the flag says 31bit, asm-s390/thread_info.h comment | |
43 | * says "32bit process" | |
44 | */ | |
45 | function probing_32bit_app() %{ /* pure */ | |
46 | if (CONTEXT->regs) | |
47 | THIS->__retvalue = (user_mode(CONTEXT->regs) && | |
48 | test_tsk_thread_flag(current, TIF_31BIT)); | |
49 | else | |
50 | THIS->__retvalue = 0; | |
51 | %} | |
52 | ||
92c25572 MW |
53 | function _stp_probing_kernel: long () { |
54 | return !user_mode(); | |
55 | } | |
4ff1e447 JK |
56 | |
57 | function _stp_get_register_by_offset:long (offset:long) %{ /* pure */ | |
58 | long value; | |
ba4e4ff4 JS |
59 | if (!CONTEXT->regs) { |
60 | CONTEXT->last_error = "No registers available in this context"; | |
61 | return; | |
62 | } | |
63 | if (THIS->offset < 0 || THIS->offset > sizeof(struct pt_regs) - sizeof(unsigned short)) { | |
64 | snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), | |
08fcfd65 DS |
65 | "Bad register offset: %lld", |
66 | (long long)THIS->offset); | |
ba4e4ff4 JS |
67 | CONTEXT->last_error = CONTEXT->error_buffer; |
68 | return; | |
69 | } | |
4ff1e447 | 70 | |
ba4e4ff4 | 71 | if (THIS->offset < sizeof(struct pt_regs) - 2 * sizeof(unsigned short)) |
4ff1e447 JK |
72 | memcpy(&value, ((char *)CONTEXT->regs) + THIS->offset, |
73 | sizeof(value)); | |
74 | else { | |
75 | /* ilc or trap */ | |
76 | unsigned short us_value; | |
77 | memcpy(&us_value, ((char *)CONTEXT->regs) + THIS->offset, | |
78 | sizeof(us_value)); | |
79 | value = us_value; // not sign-extended | |
80 | } | |
81 | THIS->__retvalue = value; | |
82 | %} | |
83 | ||
84 | function _stp_sign_extend32:long (value:long) { | |
85 | if (value & 0x80000000) | |
86 | value |= (0xffffffff << 32) | |
87 | return value | |
88 | } | |
89 | ||
90 | function _stp_register:long (name:string, sign_extend:long) { | |
91 | if (!registers_valid()) { | |
92 | error("cannot access CPU registers in this context") | |
93 | return 0 | |
94 | } | |
95 | if (!_stp_regs_registered) | |
96 | _stp_register_regs() | |
97 | offset = _reg_offsets[name] | |
98 | if (offset == 0 && !(name in _reg_offsets)) { | |
99 | error("Unknown register: " . name) | |
100 | return 0 | |
101 | } | |
102 | value = _stp_get_register_by_offset(offset) | |
103 | if (probing_32bit_app()) { | |
104 | if (sign_extend) | |
105 | value = _stp_sign_extend32(value) | |
106 | else | |
107 | value &= 0xffffffff | |
108 | } | |
109 | return value | |
110 | } | |
111 | ||
112 | /* Return the named register value as a signed value. */ | |
113 | function register:long (name:string) { | |
114 | return _stp_register(name, 1) | |
115 | } | |
116 | ||
117 | /* | |
118 | * Return the named register value as an unsigned value. Specifically, | |
119 | * don't sign-extend the register value when promoting it to 64 bits. | |
120 | */ | |
121 | function u_register:long (name:string) { | |
122 | return _stp_register(name, 0) | |
123 | } | |
124 | ||
125 | /* | |
126 | * Return the value of function arg #argnum (1=first arg). | |
127 | * If truncate=1, mask off the top 32 bits. | |
128 | * If sign_extend=1 and (truncate=1 or the probepoint we've hit is in a | |
129 | * 32-bit app), sign-extend the 32-bit value. | |
130 | * | |
131 | * We don't yet support extracting arg #6 and beyond, which are passed | |
132 | * on stack | |
133 | */ | |
134 | function _stp_arg:long (argnum:long, sign_extend:long, truncate:long) { | |
135 | val = 0 | |
136 | if (argnum < 1 || argnum > 5) { | |
137 | error(sprintf("Cannot access arg(%d)", argnum)) | |
138 | return 0 | |
139 | } | |
140 | ||
141 | if (argnum == 1) | |
142 | val = u_register("r2") | |
143 | else if (argnum == 2) | |
144 | val = u_register("r3") | |
145 | else if (argnum == 3) | |
146 | val = u_register("r4") | |
147 | else if (argnum == 4) | |
148 | val = u_register("r5") | |
903dc69f | 149 | else if (argnum == 5) |
4ff1e447 JK |
150 | val = u_register("r6") |
151 | ||
152 | if (truncate) { | |
153 | if (sign_extend) | |
154 | val = _stp_sign_extend32(val) | |
155 | else | |
156 | /* High bits may be garbage. */ | |
157 | val = (val & 0xffffffff); | |
158 | } | |
159 | return val; | |
160 | } | |
161 | ||
162 | /* Return the value of function arg #argnum (1=first arg) as a signed int. */ | |
163 | function int_arg:long (argnum:long) { | |
164 | return _stp_arg(argnum, 1, 1) | |
165 | } | |
166 | ||
167 | /* Return the value of function arg #argnum (1=first arg) as an unsigned int. */ | |
168 | function uint_arg:long (argnum:long) { | |
169 | return _stp_arg(argnum, 0, 1) | |
170 | } | |
171 | ||
172 | function long_arg:long (argnum:long) { | |
173 | return _stp_arg(argnum, 1, 0) | |
174 | } | |
175 | ||
176 | function ulong_arg:long (argnum:long) { | |
177 | return _stp_arg(argnum, 0, 0) | |
178 | } | |
179 | ||
180 | function longlong_arg:long (argnum:long) { | |
181 | if (probing_32bit_app()) { | |
182 | /* TODO verify if this is correct for 31bit apps */ | |
183 | highbits = _stp_arg(argnum, 0, 1) | |
184 | lowbits = _stp_arg(argnum+1, 0, 1) | |
185 | return ((highbits << 32) | lowbits) | |
186 | } else | |
187 | return _stp_arg(argnum, 0, 0) | |
188 | } | |
189 | ||
190 | function ulonglong_arg:long (argnum:long) { | |
191 | return longlong_arg(argnum) | |
192 | } | |
193 | ||
194 | function pointer_arg:long (argnum:long) { | |
195 | return _stp_arg(argnum, 0, 0) | |
196 | } | |
197 | ||
198 | function s32_arg:long (argnum:long) { | |
199 | return int_arg(argnum) | |
200 | } | |
201 | ||
202 | function u32_arg:long (argnum:long) { | |
203 | return uint_arg(argnum) | |
204 | } | |
205 | ||
206 | function s64_arg:long (argnum:long) { | |
207 | return longlong_arg(argnum) | |
208 | } | |
209 | ||
210 | function u64_arg:long (argnum:long) { | |
211 | return ulonglong_arg(argnum) | |
212 | } | |
213 | ||
29d0edeb | 214 | function asmlinkage() %{ /* pure */ %} |
4ff1e447 | 215 | |
29d0edeb | 216 | function fastcall() %{ /* pure */ %} |
4ff1e447 | 217 | |
309d67d8 | 218 | function regparm(n:long) %{ |
4ff1e447 JK |
219 | snprintf(CONTEXT->error_buffer, sizeof(CONTEXT->error_buffer), |
220 | "regparm is invalid on s390."); | |
221 | CONTEXT->last_error = CONTEXT->error_buffer; | |
222 | %} |