diff options
author | Markus Metzger <markus.t.metzger@intel.com> | 2008-01-30 07:32:03 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-01-30 07:32:03 -0500 |
commit | e6ae5d9540727b0e2e5e2fbeb683c84671ed0a31 (patch) | |
tree | 921ac1e9d98478b4d3b23171e965b868df7e36a9 /arch | |
parent | da35c37198132abebf877cca2ad3c6d9bcd84282 (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')
-rw-r--r-- | arch/x86/kernel/ds.c | 91 | ||||
-rw-r--r-- | arch/x86/kernel/ptrace.c | 2 |
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 | */ |
114 | static inline void *get_bts_buffer_base(char *base) | 114 | static 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 | } |
118 | static inline void set_bts_buffer_base(char *base, void *value) | 118 | static 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 | } |
122 | static inline void *get_bts_index(char *base) | 122 | static 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 | } |
126 | static inline void set_bts_index(char *base, void *value) | 126 | static 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 | } |
130 | static inline void *get_bts_absolute_maximum(char *base) | 130 | static 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 | } |
134 | static inline void set_bts_absolute_maximum(char *base, void *value) | 134 | static 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 | } |
138 | static inline void *get_bts_interrupt_threshold(char *base) | 138 | static 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 | } |
142 | static inline void set_bts_interrupt_threshold(char *base, void *value) | 142 | static 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 | } |
146 | static inline long get_from_ip(char *base) | 146 | static 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 | } |
150 | static inline void set_from_ip(char *base, long value) | 150 | static 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 | } |
154 | static inline long get_to_ip(char *base) | 154 | static 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 | } |
158 | static inline void set_to_ip(char *base, long value) | 158 | static 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 | } |
162 | static inline unsigned char get_info_type(char *base) | 162 | static 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) | |||
180 | int ds_allocate(void **dsp, size_t bts_size_in_bytes) | 180 | int 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) | |||
221 | int ds_free(void **dsp) | 221 | int 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 | ||
231 | int ds_get_bts_size(void *ds) | 231 | int 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 | ||
247 | int ds_get_bts_end(void *ds) | 247 | int 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 | ||
257 | int ds_get_bts_index(void *ds) | 257 | int 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) | |||
288 | int ds_clear(void *ds) | 288 | int 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 | ||
303 | int ds_read_bts(void *ds, size_t index, struct bts_struct *out) | 303 | int 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 | ||
332 | int ds_write_bts(void *ds, const struct bts_struct *in) | 331 | int 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 | ||
373 | unsigned long ds_debugctl_mask(void) | 372 | unsigned 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))) |