aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel
diff options
context:
space:
mode:
authorMarkus Metzger <markus.t.metzger@intel.com>2008-01-30 07:32:03 -0500
committerIngo Molnar <mingo@elte.hu>2008-01-30 07:32:03 -0500
commite6ae5d9540727b0e2e5e2fbeb683c84671ed0a31 (patch)
tree921ac1e9d98478b4d3b23171e965b868df7e36a9 /arch/x86/kernel
parentda35c37198132abebf877cca2ad3c6d9bcd84282 (diff)
x86, ptrace: support 32bit-cross-64bit BTS recording
Support BTS recording of 32bit and 64bit tasks from 32bit or 64bit tasks. Signed-off-by: Markus Metzger <markus.t.metzger@intel.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch/x86/kernel')
-rw-r--r--arch/x86/kernel/ds.c91
-rw-r--r--arch/x86/kernel/ptrace.c2
2 files changed, 46 insertions, 47 deletions
diff --git a/arch/x86/kernel/ds.c b/arch/x86/kernel/ds.c
index 6eb5d49a36bb..1c5ca4d18787 100644
--- a/arch/x86/kernel/ds.c
+++ b/arch/x86/kernel/ds.c
@@ -111,53 +111,53 @@ static struct ds_configuration ds_cfg;
111 * Accessor functions for some DS and BTS fields using the above 111 * Accessor functions for some DS and BTS fields using the above
112 * global ptrace_bts_cfg. 112 * global ptrace_bts_cfg.
113 */ 113 */
114static inline void *get_bts_buffer_base(char *base) 114static inline unsigned long get_bts_buffer_base(char *base)
115{ 115{
116 return *(void **)(base + ds_cfg.bts_buffer_base.offset); 116 return *(unsigned long *)(base + ds_cfg.bts_buffer_base.offset);
117} 117}
118static inline void set_bts_buffer_base(char *base, void *value) 118static inline void set_bts_buffer_base(char *base, unsigned long value)
119{ 119{
120 (*(void **)(base + ds_cfg.bts_buffer_base.offset)) = value; 120 (*(unsigned long *)(base + ds_cfg.bts_buffer_base.offset)) = value;
121} 121}
122static inline void *get_bts_index(char *base) 122static inline unsigned long get_bts_index(char *base)
123{ 123{
124 return *(void **)(base + ds_cfg.bts_index.offset); 124 return *(unsigned long *)(base + ds_cfg.bts_index.offset);
125} 125}
126static inline void set_bts_index(char *base, void *value) 126static inline void set_bts_index(char *base, unsigned long value)
127{ 127{
128 (*(void **)(base + ds_cfg.bts_index.offset)) = value; 128 (*(unsigned long *)(base + ds_cfg.bts_index.offset)) = value;
129} 129}
130static inline void *get_bts_absolute_maximum(char *base) 130static inline unsigned long get_bts_absolute_maximum(char *base)
131{ 131{
132 return *(void **)(base + ds_cfg.bts_absolute_maximum.offset); 132 return *(unsigned long *)(base + ds_cfg.bts_absolute_maximum.offset);
133} 133}
134static inline void set_bts_absolute_maximum(char *base, void *value) 134static inline void set_bts_absolute_maximum(char *base, unsigned long value)
135{ 135{
136 (*(void **)(base + ds_cfg.bts_absolute_maximum.offset)) = value; 136 (*(unsigned long *)(base + ds_cfg.bts_absolute_maximum.offset)) = value;
137} 137}
138static inline void *get_bts_interrupt_threshold(char *base) 138static inline unsigned long get_bts_interrupt_threshold(char *base)
139{ 139{
140 return *(void **)(base + ds_cfg.bts_interrupt_threshold.offset); 140 return *(unsigned long *)(base + ds_cfg.bts_interrupt_threshold.offset);
141} 141}
142static inline void set_bts_interrupt_threshold(char *base, void *value) 142static inline void set_bts_interrupt_threshold(char *base, unsigned long value)
143{ 143{
144 (*(void **)(base + ds_cfg.bts_interrupt_threshold.offset)) = value; 144 (*(unsigned long *)(base + ds_cfg.bts_interrupt_threshold.offset)) = value;
145} 145}
146static inline long get_from_ip(char *base) 146static inline unsigned long get_from_ip(char *base)
147{ 147{
148 return *(long *)(base + ds_cfg.from_ip.offset); 148 return *(unsigned long *)(base + ds_cfg.from_ip.offset);
149} 149}
150static inline void set_from_ip(char *base, long value) 150static inline void set_from_ip(char *base, unsigned long value)
151{ 151{
152 (*(long *)(base + ds_cfg.from_ip.offset)) = value; 152 (*(unsigned long *)(base + ds_cfg.from_ip.offset)) = value;
153} 153}
154static inline long get_to_ip(char *base) 154static inline unsigned long get_to_ip(char *base)
155{ 155{
156 return *(long *)(base + ds_cfg.to_ip.offset); 156 return *(unsigned long *)(base + ds_cfg.to_ip.offset);
157} 157}
158static inline void set_to_ip(char *base, long value) 158static inline void set_to_ip(char *base, unsigned long value)
159{ 159{
160 (*(long *)(base + ds_cfg.to_ip.offset)) = value; 160 (*(unsigned long *)(base + ds_cfg.to_ip.offset)) = value;
161} 161}
162static inline unsigned char get_info_type(char *base) 162static inline unsigned char get_info_type(char *base)
163{ 163{
@@ -180,7 +180,7 @@ static inline void set_info_data(char *base, unsigned long value)
180int ds_allocate(void **dsp, size_t bts_size_in_bytes) 180int ds_allocate(void **dsp, size_t bts_size_in_bytes)
181{ 181{
182 size_t bts_size_in_records; 182 size_t bts_size_in_records;
183 void *bts; 183 unsigned long bts;
184 void *ds; 184 void *ds;
185 185
186 if (!ds_cfg.sizeof_ds || !ds_cfg.sizeof_bts) 186 if (!ds_cfg.sizeof_ds || !ds_cfg.sizeof_bts)
@@ -197,7 +197,7 @@ int ds_allocate(void **dsp, size_t bts_size_in_bytes)
197 if (bts_size_in_bytes <= 0) 197 if (bts_size_in_bytes <= 0)
198 return -EINVAL; 198 return -EINVAL;
199 199
200 bts = kzalloc(bts_size_in_bytes, GFP_KERNEL); 200 bts = (unsigned long)kzalloc(bts_size_in_bytes, GFP_KERNEL);
201 201
202 if (!bts) 202 if (!bts)
203 return -ENOMEM; 203 return -ENOMEM;
@@ -205,7 +205,7 @@ int ds_allocate(void **dsp, size_t bts_size_in_bytes)
205 ds = kzalloc(ds_cfg.sizeof_ds, GFP_KERNEL); 205 ds = kzalloc(ds_cfg.sizeof_ds, GFP_KERNEL);
206 206
207 if (!ds) { 207 if (!ds) {
208 kfree(bts); 208 kfree((void *)bts);
209 return -ENOMEM; 209 return -ENOMEM;
210 } 210 }
211 211
@@ -221,7 +221,7 @@ int ds_allocate(void **dsp, size_t bts_size_in_bytes)
221int ds_free(void **dsp) 221int ds_free(void **dsp)
222{ 222{
223 if (*dsp) 223 if (*dsp)
224 kfree(get_bts_buffer_base(*dsp)); 224 kfree((void *)get_bts_buffer_base(*dsp));
225 kfree(*dsp); 225 kfree(*dsp);
226 *dsp = 0; 226 *dsp = 0;
227 227
@@ -230,7 +230,7 @@ int ds_free(void **dsp)
230 230
231int ds_get_bts_size(void *ds) 231int ds_get_bts_size(void *ds)
232{ 232{
233 size_t size_in_bytes; 233 int size_in_bytes;
234 234
235 if (!ds_cfg.sizeof_ds || !ds_cfg.sizeof_bts) 235 if (!ds_cfg.sizeof_ds || !ds_cfg.sizeof_bts)
236 return -EOPNOTSUPP; 236 return -EOPNOTSUPP;
@@ -246,7 +246,7 @@ int ds_get_bts_size(void *ds)
246 246
247int ds_get_bts_end(void *ds) 247int ds_get_bts_end(void *ds)
248{ 248{
249 size_t size_in_bytes = ds_get_bts_size(ds); 249 int size_in_bytes = ds_get_bts_size(ds);
250 250
251 if (size_in_bytes <= 0) 251 if (size_in_bytes <= 0)
252 return size_in_bytes; 252 return size_in_bytes;
@@ -256,7 +256,7 @@ int ds_get_bts_end(void *ds)
256 256
257int ds_get_bts_index(void *ds) 257int ds_get_bts_index(void *ds)
258{ 258{
259 size_t index_offset_in_bytes; 259 int index_offset_in_bytes;
260 260
261 if (!ds_cfg.sizeof_ds || !ds_cfg.sizeof_bts) 261 if (!ds_cfg.sizeof_ds || !ds_cfg.sizeof_bts)
262 return -EOPNOTSUPP; 262 return -EOPNOTSUPP;
@@ -288,19 +288,19 @@ int ds_get_overflow(void *ds)
288int ds_clear(void *ds) 288int ds_clear(void *ds)
289{ 289{
290 int bts_size = ds_get_bts_size(ds); 290 int bts_size = ds_get_bts_size(ds);
291 void *bts_base; 291 unsigned long bts_base;
292 292
293 if (bts_size <= 0) 293 if (bts_size <= 0)
294 return bts_size; 294 return bts_size;
295 295
296 bts_base = get_bts_buffer_base(ds); 296 bts_base = get_bts_buffer_base(ds);
297 memset(bts_base, 0, bts_size); 297 memset((void *)bts_base, 0, bts_size);
298 298
299 set_bts_index(ds, bts_base); 299 set_bts_index(ds, bts_base);
300 return 0; 300 return 0;
301} 301}
302 302
303int ds_read_bts(void *ds, size_t index, struct bts_struct *out) 303int ds_read_bts(void *ds, int index, struct bts_struct *out)
304{ 304{
305 void *bts; 305 void *bts;
306 306
@@ -313,8 +313,7 @@ int ds_read_bts(void *ds, size_t index, struct bts_struct *out)
313 if (index >= ds_get_bts_size(ds)) 313 if (index >= ds_get_bts_size(ds))
314 return -EINVAL; 314 return -EINVAL;
315 315
316 bts = get_bts_buffer_base(ds); 316 bts = (void *)(get_bts_buffer_base(ds) + (index * ds_cfg.sizeof_bts));
317 bts = (char *)bts + (index * ds_cfg.sizeof_bts);
318 317
319 memset(out, 0, sizeof(*out)); 318 memset(out, 0, sizeof(*out));
320 if (get_from_ip(bts) == BTS_ESCAPE_ADDRESS) { 319 if (get_from_ip(bts) == BTS_ESCAPE_ADDRESS) {
@@ -326,12 +325,12 @@ int ds_read_bts(void *ds, size_t index, struct bts_struct *out)
326 out->variant.lbr.to_ip = get_to_ip(bts); 325 out->variant.lbr.to_ip = get_to_ip(bts);
327 } 326 }
328 327
329 return 0; 328 return sizeof(*out);;
330} 329}
331 330
332int ds_write_bts(void *ds, const struct bts_struct *in) 331int ds_write_bts(void *ds, const struct bts_struct *in)
333{ 332{
334 void *bts; 333 unsigned long bts;
335 334
336 if (!ds_cfg.sizeof_ds || !ds_cfg.sizeof_bts) 335 if (!ds_cfg.sizeof_ds || !ds_cfg.sizeof_bts)
337 return -EOPNOTSUPP; 336 return -EOPNOTSUPP;
@@ -341,33 +340,33 @@ int ds_write_bts(void *ds, const struct bts_struct *in)
341 340
342 bts = get_bts_index(ds); 341 bts = get_bts_index(ds);
343 342
344 memset(bts, 0, ds_cfg.sizeof_bts); 343 memset((void *)bts, 0, ds_cfg.sizeof_bts);
345 switch (in->qualifier) { 344 switch (in->qualifier) {
346 case BTS_INVALID: 345 case BTS_INVALID:
347 break; 346 break;
348 347
349 case BTS_BRANCH: 348 case BTS_BRANCH:
350 set_from_ip(bts, in->variant.lbr.from_ip); 349 set_from_ip((void *)bts, in->variant.lbr.from_ip);
351 set_to_ip(bts, in->variant.lbr.to_ip); 350 set_to_ip((void *)bts, in->variant.lbr.to_ip);
352 break; 351 break;
353 352
354 case BTS_TASK_ARRIVES: 353 case BTS_TASK_ARRIVES:
355 case BTS_TASK_DEPARTS: 354 case BTS_TASK_DEPARTS:
356 set_from_ip(bts, BTS_ESCAPE_ADDRESS); 355 set_from_ip((void *)bts, BTS_ESCAPE_ADDRESS);
357 set_info_type(bts, in->qualifier); 356 set_info_type((void *)bts, in->qualifier);
358 set_info_data(bts, in->variant.jiffies); 357 set_info_data((void *)bts, in->variant.jiffies);
359 break; 358 break;
360 359
361 default: 360 default:
362 return -EINVAL; 361 return -EINVAL;
363 } 362 }
364 363
365 bts = (char *)bts + ds_cfg.sizeof_bts; 364 bts = bts + ds_cfg.sizeof_bts;
366 if (bts >= get_bts_absolute_maximum(ds)) 365 if (bts >= get_bts_absolute_maximum(ds))
367 bts = get_bts_buffer_base(ds); 366 bts = get_bts_buffer_base(ds);
368 set_bts_index(ds, bts); 367 set_bts_index(ds, bts);
369 368
370 return 0; 369 return ds_cfg.sizeof_bts;
371} 370}
372 371
373unsigned long ds_debugctl_mask(void) 372unsigned long ds_debugctl_mask(void)
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index 88ed1e74cee9..236528bec6eb 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -558,7 +558,7 @@ static int ptrace_bts_read_record(struct task_struct *child,
558 558
559 retval = ds_read_bts((void *)child->thread.ds_area_msr, 559 retval = ds_read_bts((void *)child->thread.ds_area_msr,
560 bts_index, &ret); 560 bts_index, &ret);
561 if (retval) 561 if (retval < 0)
562 return retval; 562 return retval;
563 563
564 if (copy_to_user(out, &ret, sizeof(ret))) 564 if (copy_to_user(out, &ret, sizeof(ret)))