ia64/linux-2.6.18-xen.hg

annotate kernel/unwind.c @ 912:dd42cdb0ab89

[IA64] Build blktap2 driver by default in x86 builds.

add CONFIG_XEN_BLKDEV_TAP2=y to buildconfigs/linux-defconfig_xen_ia64.

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
author Isaku Yamahata <yamahata@valinux.co.jp>
date Mon Jun 29 12:09:16 2009 +0900 (2009-06-29)
parents 831230e53067
children
rev   line source
ian@0 1 /*
ian@0 2 * Copyright (C) 2002-2006 Novell, Inc.
ian@0 3 * Jan Beulich <jbeulich@novell.com>
ian@0 4 * This code is released under version 2 of the GNU GPL.
ian@0 5 *
ian@0 6 * A simple API for unwinding kernel stacks. This is used for
ian@0 7 * debugging and error reporting purposes. The kernel doesn't need
ian@0 8 * full-blown stack unwinding with all the bells and whistles, so there
ian@0 9 * is not much point in implementing the full Dwarf2 unwind API.
ian@0 10 */
ian@0 11
ian@0 12 #include <linux/unwind.h>
ian@0 13 #include <linux/module.h>
ian@0 14 #include <linux/delay.h>
ian@0 15 #include <linux/stop_machine.h>
ian@0 16 #include <asm/sections.h>
ian@0 17 #include <asm/uaccess.h>
ian@0 18 #include <asm/unaligned.h>
ian@0 19
ian@0 20 extern char __start_unwind[], __end_unwind[];
ian@0 21
ian@0 22 #define MAX_STACK_DEPTH 8
ian@0 23
ian@0 24 #define EXTRA_INFO(f) { \
ian@0 25 BUILD_BUG_ON_ZERO(offsetof(struct unwind_frame_info, f) \
ian@0 26 % FIELD_SIZEOF(struct unwind_frame_info, f)) \
ian@0 27 + offsetof(struct unwind_frame_info, f) \
ian@0 28 / FIELD_SIZEOF(struct unwind_frame_info, f), \
ian@0 29 FIELD_SIZEOF(struct unwind_frame_info, f) \
ian@0 30 }
ian@0 31 #define PTREGS_INFO(f) EXTRA_INFO(regs.f)
ian@0 32
ian@0 33 static const struct {
ian@0 34 unsigned offs:BITS_PER_LONG / 2;
ian@0 35 unsigned width:BITS_PER_LONG / 2;
ian@0 36 } reg_info[] = {
ian@0 37 UNW_REGISTER_INFO
ian@0 38 };
ian@0 39
ian@0 40 #undef PTREGS_INFO
ian@0 41 #undef EXTRA_INFO
ian@0 42
ian@0 43 #ifndef REG_INVALID
ian@0 44 #define REG_INVALID(r) (reg_info[r].width == 0)
ian@0 45 #endif
ian@0 46
ian@0 47 #define DW_CFA_nop 0x00
ian@0 48 #define DW_CFA_set_loc 0x01
ian@0 49 #define DW_CFA_advance_loc1 0x02
ian@0 50 #define DW_CFA_advance_loc2 0x03
ian@0 51 #define DW_CFA_advance_loc4 0x04
ian@0 52 #define DW_CFA_offset_extended 0x05
ian@0 53 #define DW_CFA_restore_extended 0x06
ian@0 54 #define DW_CFA_undefined 0x07
ian@0 55 #define DW_CFA_same_value 0x08
ian@0 56 #define DW_CFA_register 0x09
ian@0 57 #define DW_CFA_remember_state 0x0a
ian@0 58 #define DW_CFA_restore_state 0x0b
ian@0 59 #define DW_CFA_def_cfa 0x0c
ian@0 60 #define DW_CFA_def_cfa_register 0x0d
ian@0 61 #define DW_CFA_def_cfa_offset 0x0e
ian@0 62 #define DW_CFA_def_cfa_expression 0x0f
ian@0 63 #define DW_CFA_expression 0x10
ian@0 64 #define DW_CFA_offset_extended_sf 0x11
ian@0 65 #define DW_CFA_def_cfa_sf 0x12
ian@0 66 #define DW_CFA_def_cfa_offset_sf 0x13
ian@0 67 #define DW_CFA_val_offset 0x14
ian@0 68 #define DW_CFA_val_offset_sf 0x15
ian@0 69 #define DW_CFA_val_expression 0x16
ian@0 70 #define DW_CFA_lo_user 0x1c
ian@0 71 #define DW_CFA_GNU_window_save 0x2d
ian@0 72 #define DW_CFA_GNU_args_size 0x2e
ian@0 73 #define DW_CFA_GNU_negative_offset_extended 0x2f
ian@0 74 #define DW_CFA_hi_user 0x3f
ian@0 75
ian@0 76 #define DW_EH_PE_FORM 0x07
ian@0 77 #define DW_EH_PE_native 0x00
ian@0 78 #define DW_EH_PE_leb128 0x01
ian@0 79 #define DW_EH_PE_data2 0x02
ian@0 80 #define DW_EH_PE_data4 0x03
ian@0 81 #define DW_EH_PE_data8 0x04
ian@0 82 #define DW_EH_PE_signed 0x08
ian@0 83 #define DW_EH_PE_ADJUST 0x70
ian@0 84 #define DW_EH_PE_abs 0x00
ian@0 85 #define DW_EH_PE_pcrel 0x10
ian@0 86 #define DW_EH_PE_textrel 0x20
ian@0 87 #define DW_EH_PE_datarel 0x30
ian@0 88 #define DW_EH_PE_funcrel 0x40
ian@0 89 #define DW_EH_PE_aligned 0x50
ian@0 90 #define DW_EH_PE_indirect 0x80
ian@0 91 #define DW_EH_PE_omit 0xff
ian@0 92
ian@0 93 typedef unsigned long uleb128_t;
ian@0 94 typedef signed long sleb128_t;
ian@0 95
ian@0 96 static struct unwind_table {
ian@0 97 struct {
ian@0 98 unsigned long pc;
ian@0 99 unsigned long range;
ian@0 100 } core, init;
ian@0 101 const void *address;
ian@0 102 unsigned long size;
ian@0 103 struct unwind_table *link;
ian@0 104 const char *name;
ian@0 105 } root_table, *last_table;
ian@0 106
ian@0 107 struct unwind_item {
ian@0 108 enum item_location {
ian@0 109 Nowhere,
ian@0 110 Memory,
ian@0 111 Register,
ian@0 112 Value
ian@0 113 } where;
ian@0 114 uleb128_t value;
ian@0 115 };
ian@0 116
ian@0 117 struct unwind_state {
ian@0 118 uleb128_t loc, org;
ian@0 119 const u8 *cieStart, *cieEnd;
ian@0 120 uleb128_t codeAlign;
ian@0 121 sleb128_t dataAlign;
ian@0 122 struct cfa {
ian@0 123 uleb128_t reg, offs;
ian@0 124 } cfa;
ian@0 125 struct unwind_item regs[ARRAY_SIZE(reg_info)];
ian@0 126 unsigned stackDepth:8;
ian@0 127 unsigned version:8;
ian@0 128 const u8 *label;
ian@0 129 const u8 *stack[MAX_STACK_DEPTH];
ian@0 130 };
ian@0 131
ian@0 132 static const struct cfa badCFA = { ARRAY_SIZE(reg_info), 1 };
ian@0 133
ian@0 134 static struct unwind_table *find_table(unsigned long pc)
ian@0 135 {
ian@0 136 struct unwind_table *table;
ian@0 137
ian@0 138 for (table = &root_table; table; table = table->link)
ian@0 139 if ((pc >= table->core.pc
ian@0 140 && pc < table->core.pc + table->core.range)
ian@0 141 || (pc >= table->init.pc
ian@0 142 && pc < table->init.pc + table->init.range))
ian@0 143 break;
ian@0 144
ian@0 145 return table;
ian@0 146 }
ian@0 147
ian@0 148 static void init_unwind_table(struct unwind_table *table,
ian@0 149 const char *name,
ian@0 150 const void *core_start,
ian@0 151 unsigned long core_size,
ian@0 152 const void *init_start,
ian@0 153 unsigned long init_size,
ian@0 154 const void *table_start,
ian@0 155 unsigned long table_size)
ian@0 156 {
ian@0 157 table->core.pc = (unsigned long)core_start;
ian@0 158 table->core.range = core_size;
ian@0 159 table->init.pc = (unsigned long)init_start;
ian@0 160 table->init.range = init_size;
ian@0 161 table->address = table_start;
ian@0 162 table->size = table_size;
ian@0 163 table->link = NULL;
ian@0 164 table->name = name;
ian@0 165 }
ian@0 166
ian@0 167 void __init unwind_init(void)
ian@0 168 {
ian@0 169 init_unwind_table(&root_table, "kernel",
ian@0 170 _text, _end - _text,
ian@0 171 NULL, 0,
ian@0 172 __start_unwind, __end_unwind - __start_unwind);
ian@0 173 }
ian@0 174
ian@0 175 #ifdef CONFIG_MODULES
ian@0 176
ian@0 177 /* Must be called with module_mutex held. */
ian@0 178 void *unwind_add_table(struct module *module,
ian@0 179 const void *table_start,
ian@0 180 unsigned long table_size)
ian@0 181 {
ian@0 182 struct unwind_table *table;
ian@0 183
ian@0 184 if (table_size <= 0)
ian@0 185 return NULL;
ian@0 186
ian@0 187 table = kmalloc(sizeof(*table), GFP_KERNEL);
ian@0 188 if (!table)
ian@0 189 return NULL;
ian@0 190
ian@0 191 init_unwind_table(table, module->name,
ian@0 192 module->module_core, module->core_size,
ian@0 193 module->module_init, module->init_size,
ian@0 194 table_start, table_size);
ian@0 195
ian@0 196 if (last_table)
ian@0 197 last_table->link = table;
ian@0 198 else
ian@0 199 root_table.link = table;
ian@0 200 last_table = table;
ian@0 201
ian@0 202 return table;
ian@0 203 }
ian@0 204
ian@0 205 struct unlink_table_info
ian@0 206 {
ian@0 207 struct unwind_table *table;
ian@0 208 int init_only;
ian@0 209 };
ian@0 210
ian@0 211 static int unlink_table(void *arg)
ian@0 212 {
ian@0 213 struct unlink_table_info *info = arg;
ian@0 214 struct unwind_table *table = info->table, *prev;
ian@0 215
ian@0 216 for (prev = &root_table; prev->link && prev->link != table; prev = prev->link)
ian@0 217 ;
ian@0 218
ian@0 219 if (prev->link) {
ian@0 220 if (info->init_only) {
ian@0 221 table->init.pc = 0;
ian@0 222 table->init.range = 0;
ian@0 223 info->table = NULL;
ian@0 224 } else {
ian@0 225 prev->link = table->link;
ian@0 226 if (!prev->link)
ian@0 227 last_table = prev;
ian@0 228 }
ian@0 229 } else
ian@0 230 info->table = NULL;
ian@0 231
ian@0 232 return 0;
ian@0 233 }
ian@0 234
ian@0 235 /* Must be called with module_mutex held. */
ian@0 236 void unwind_remove_table(void *handle, int init_only)
ian@0 237 {
ian@0 238 struct unwind_table *table = handle;
ian@0 239 struct unlink_table_info info;
ian@0 240
ian@0 241 if (!table || table == &root_table)
ian@0 242 return;
ian@0 243
ian@0 244 if (init_only && table == last_table) {
ian@0 245 table->init.pc = 0;
ian@0 246 table->init.range = 0;
ian@0 247 return;
ian@0 248 }
ian@0 249
ian@0 250 info.table = table;
ian@0 251 info.init_only = init_only;
ian@0 252 stop_machine_run(unlink_table, &info, NR_CPUS);
ian@0 253
ian@0 254 if (info.table)
ian@0 255 kfree(table);
ian@0 256 }
ian@0 257
ian@0 258 #endif /* CONFIG_MODULES */
ian@0 259
ian@0 260 static uleb128_t get_uleb128(const u8 **pcur, const u8 *end)
ian@0 261 {
ian@0 262 const u8 *cur = *pcur;
ian@0 263 uleb128_t value;
ian@0 264 unsigned shift;
ian@0 265
ian@0 266 for (shift = 0, value = 0; cur < end; shift += 7) {
ian@0 267 if (shift + 7 > 8 * sizeof(value)
ian@0 268 && (*cur & 0x7fU) >= (1U << (8 * sizeof(value) - shift))) {
ian@0 269 cur = end + 1;
ian@0 270 break;
ian@0 271 }
ian@0 272 value |= (uleb128_t)(*cur & 0x7f) << shift;
ian@0 273 if (!(*cur++ & 0x80))
ian@0 274 break;
ian@0 275 }
ian@0 276 *pcur = cur;
ian@0 277
ian@0 278 return value;
ian@0 279 }
ian@0 280
ian@0 281 static sleb128_t get_sleb128(const u8 **pcur, const u8 *end)
ian@0 282 {
ian@0 283 const u8 *cur = *pcur;
ian@0 284 sleb128_t value;
ian@0 285 unsigned shift;
ian@0 286
ian@0 287 for (shift = 0, value = 0; cur < end; shift += 7) {
ian@0 288 if (shift + 7 > 8 * sizeof(value)
ian@0 289 && (*cur & 0x7fU) >= (1U << (8 * sizeof(value) - shift))) {
ian@0 290 cur = end + 1;
ian@0 291 break;
ian@0 292 }
ian@0 293 value |= (sleb128_t)(*cur & 0x7f) << shift;
ian@0 294 if (!(*cur & 0x80)) {
ian@0 295 value |= -(*cur++ & 0x40) << shift;
ian@0 296 break;
ian@0 297 }
ian@0 298 }
ian@0 299 *pcur = cur;
ian@0 300
ian@0 301 return value;
ian@0 302 }
ian@0 303
ian@0 304 static unsigned long read_pointer(const u8 **pLoc,
ian@0 305 const void *end,
ian@0 306 signed ptrType)
ian@0 307 {
ian@0 308 unsigned long value = 0;
ian@0 309 union {
ian@0 310 const u8 *p8;
ian@0 311 const u16 *p16u;
ian@0 312 const s16 *p16s;
ian@0 313 const u32 *p32u;
ian@0 314 const s32 *p32s;
ian@0 315 const unsigned long *pul;
ian@0 316 } ptr;
ian@0 317
ian@0 318 if (ptrType < 0 || ptrType == DW_EH_PE_omit)
ian@0 319 return 0;
ian@0 320 ptr.p8 = *pLoc;
ian@0 321 switch(ptrType & DW_EH_PE_FORM) {
ian@0 322 case DW_EH_PE_data2:
ian@0 323 if (end < (const void *)(ptr.p16u + 1))
ian@0 324 return 0;
ian@0 325 if(ptrType & DW_EH_PE_signed)
ian@0 326 value = get_unaligned(ptr.p16s++);
ian@0 327 else
ian@0 328 value = get_unaligned(ptr.p16u++);
ian@0 329 break;
ian@0 330 case DW_EH_PE_data4:
ian@0 331 #ifdef CONFIG_64BIT
ian@0 332 if (end < (const void *)(ptr.p32u + 1))
ian@0 333 return 0;
ian@0 334 if(ptrType & DW_EH_PE_signed)
ian@0 335 value = get_unaligned(ptr.p32s++);
ian@0 336 else
ian@0 337 value = get_unaligned(ptr.p32u++);
ian@0 338 break;
ian@0 339 case DW_EH_PE_data8:
ian@0 340 BUILD_BUG_ON(sizeof(u64) != sizeof(value));
ian@0 341 #else
ian@0 342 BUILD_BUG_ON(sizeof(u32) != sizeof(value));
ian@0 343 #endif
ian@0 344 case DW_EH_PE_native:
ian@0 345 if (end < (const void *)(ptr.pul + 1))
ian@0 346 return 0;
ian@0 347 value = get_unaligned(ptr.pul++);
ian@0 348 break;
ian@0 349 case DW_EH_PE_leb128:
ian@0 350 BUILD_BUG_ON(sizeof(uleb128_t) > sizeof(value));
ian@0 351 value = ptrType & DW_EH_PE_signed
ian@0 352 ? get_sleb128(&ptr.p8, end)
ian@0 353 : get_uleb128(&ptr.p8, end);
ian@0 354 if ((const void *)ptr.p8 > end)
ian@0 355 return 0;
ian@0 356 break;
ian@0 357 default:
ian@0 358 return 0;
ian@0 359 }
ian@0 360 switch(ptrType & DW_EH_PE_ADJUST) {
ian@0 361 case DW_EH_PE_abs:
ian@0 362 break;
ian@0 363 case DW_EH_PE_pcrel:
ian@0 364 value += (unsigned long)*pLoc;
ian@0 365 break;
ian@0 366 default:
ian@0 367 return 0;
ian@0 368 }
ian@0 369 if ((ptrType & DW_EH_PE_indirect)
ian@0 370 && __get_user(value, (unsigned long *)value))
ian@0 371 return 0;
ian@0 372 *pLoc = ptr.p8;
ian@0 373
ian@0 374 return value;
ian@0 375 }
ian@0 376
ian@0 377 static signed fde_pointer_type(const u32 *cie)
ian@0 378 {
ian@0 379 const u8 *ptr = (const u8 *)(cie + 2);
ian@0 380 unsigned version = *ptr;
ian@0 381
ian@0 382 if (version != 1)
ian@0 383 return -1; /* unsupported */
ian@0 384 if (*++ptr) {
ian@0 385 const char *aug;
ian@0 386 const u8 *end = (const u8 *)(cie + 1) + *cie;
ian@0 387 uleb128_t len;
ian@0 388
ian@0 389 /* check if augmentation size is first (and thus present) */
ian@0 390 if (*ptr != 'z')
ian@0 391 return -1;
ian@0 392 /* check if augmentation string is nul-terminated */
ian@0 393 if ((ptr = memchr(aug = (const void *)ptr, 0, end - ptr)) == NULL)
ian@0 394 return -1;
ian@0 395 ++ptr; /* skip terminator */
ian@0 396 get_uleb128(&ptr, end); /* skip code alignment */
ian@0 397 get_sleb128(&ptr, end); /* skip data alignment */
ian@0 398 /* skip return address column */
ian@0 399 version <= 1 ? (void)++ptr : (void)get_uleb128(&ptr, end);
ian@0 400 len = get_uleb128(&ptr, end); /* augmentation length */
ian@0 401 if (ptr + len < ptr || ptr + len > end)
ian@0 402 return -1;
ian@0 403 end = ptr + len;
ian@0 404 while (*++aug) {
ian@0 405 if (ptr >= end)
ian@0 406 return -1;
ian@0 407 switch(*aug) {
ian@0 408 case 'L':
ian@0 409 ++ptr;
ian@0 410 break;
ian@0 411 case 'P': {
ian@0 412 signed ptrType = *ptr++;
ian@0 413
ian@0 414 if (!read_pointer(&ptr, end, ptrType) || ptr > end)
ian@0 415 return -1;
ian@0 416 }
ian@0 417 break;
ian@0 418 case 'R':
ian@0 419 return *ptr;
ian@0 420 default:
ian@0 421 return -1;
ian@0 422 }
ian@0 423 }
ian@0 424 }
ian@0 425 return DW_EH_PE_native|DW_EH_PE_abs;
ian@0 426 }
ian@0 427
ian@0 428 static int advance_loc(unsigned long delta, struct unwind_state *state)
ian@0 429 {
ian@0 430 state->loc += delta * state->codeAlign;
ian@0 431
ian@0 432 return delta > 0;
ian@0 433 }
ian@0 434
ian@0 435 static void set_rule(uleb128_t reg,
ian@0 436 enum item_location where,
ian@0 437 uleb128_t value,
ian@0 438 struct unwind_state *state)
ian@0 439 {
ian@0 440 if (reg < ARRAY_SIZE(state->regs)) {
ian@0 441 state->regs[reg].where = where;
ian@0 442 state->regs[reg].value = value;
ian@0 443 }
ian@0 444 }
ian@0 445
ian@0 446 static int processCFI(const u8 *start,
ian@0 447 const u8 *end,
ian@0 448 unsigned long targetLoc,
ian@0 449 signed ptrType,
ian@0 450 struct unwind_state *state)
ian@0 451 {
ian@0 452 union {
ian@0 453 const u8 *p8;
ian@0 454 const u16 *p16;
ian@0 455 const u32 *p32;
ian@0 456 } ptr;
ian@0 457 int result = 1;
ian@0 458
ian@0 459 if (start != state->cieStart) {
ian@0 460 state->loc = state->org;
ian@0 461 result = processCFI(state->cieStart, state->cieEnd, 0, ptrType, state);
ian@0 462 if (targetLoc == 0 && state->label == NULL)
ian@0 463 return result;
ian@0 464 }
ian@0 465 for (ptr.p8 = start; result && ptr.p8 < end; ) {
ian@0 466 switch(*ptr.p8 >> 6) {
ian@0 467 uleb128_t value;
ian@0 468
ian@0 469 case 0:
ian@0 470 switch(*ptr.p8++) {
ian@0 471 case DW_CFA_nop:
ian@0 472 break;
ian@0 473 case DW_CFA_set_loc:
ian@0 474 if ((state->loc = read_pointer(&ptr.p8, end, ptrType)) == 0)
ian@0 475 result = 0;
ian@0 476 break;
ian@0 477 case DW_CFA_advance_loc1:
ian@0 478 result = ptr.p8 < end && advance_loc(*ptr.p8++, state);
ian@0 479 break;
ian@0 480 case DW_CFA_advance_loc2:
ian@0 481 result = ptr.p8 <= end + 2
ian@0 482 && advance_loc(*ptr.p16++, state);
ian@0 483 break;
ian@0 484 case DW_CFA_advance_loc4:
ian@0 485 result = ptr.p8 <= end + 4
ian@0 486 && advance_loc(*ptr.p32++, state);
ian@0 487 break;
ian@0 488 case DW_CFA_offset_extended:
ian@0 489 value = get_uleb128(&ptr.p8, end);
ian@0 490 set_rule(value, Memory, get_uleb128(&ptr.p8, end), state);
ian@0 491 break;
ian@0 492 case DW_CFA_val_offset:
ian@0 493 value = get_uleb128(&ptr.p8, end);
ian@0 494 set_rule(value, Value, get_uleb128(&ptr.p8, end), state);
ian@0 495 break;
ian@0 496 case DW_CFA_offset_extended_sf:
ian@0 497 value = get_uleb128(&ptr.p8, end);
ian@0 498 set_rule(value, Memory, get_sleb128(&ptr.p8, end), state);
ian@0 499 break;
ian@0 500 case DW_CFA_val_offset_sf:
ian@0 501 value = get_uleb128(&ptr.p8, end);
ian@0 502 set_rule(value, Value, get_sleb128(&ptr.p8, end), state);
ian@0 503 break;
ian@0 504 case DW_CFA_restore_extended:
ian@0 505 case DW_CFA_undefined:
ian@0 506 case DW_CFA_same_value:
ian@0 507 set_rule(get_uleb128(&ptr.p8, end), Nowhere, 0, state);
ian@0 508 break;
ian@0 509 case DW_CFA_register:
ian@0 510 value = get_uleb128(&ptr.p8, end);
ian@0 511 set_rule(value,
ian@0 512 Register,
ian@0 513 get_uleb128(&ptr.p8, end), state);
ian@0 514 break;
ian@0 515 case DW_CFA_remember_state:
ian@0 516 if (ptr.p8 == state->label) {
ian@0 517 state->label = NULL;
ian@0 518 return 1;
ian@0 519 }
ian@0 520 if (state->stackDepth >= MAX_STACK_DEPTH)
ian@0 521 return 0;
ian@0 522 state->stack[state->stackDepth++] = ptr.p8;
ian@0 523 break;
ian@0 524 case DW_CFA_restore_state:
ian@0 525 if (state->stackDepth) {
ian@0 526 const uleb128_t loc = state->loc;
ian@0 527 const u8 *label = state->label;
ian@0 528
ian@0 529 state->label = state->stack[state->stackDepth - 1];
ian@0 530 memcpy(&state->cfa, &badCFA, sizeof(state->cfa));
ian@0 531 memset(state->regs, 0, sizeof(state->regs));
ian@0 532 state->stackDepth = 0;
ian@0 533 result = processCFI(start, end, 0, ptrType, state);
ian@0 534 state->loc = loc;
ian@0 535 state->label = label;
ian@0 536 } else
ian@0 537 return 0;
ian@0 538 break;
ian@0 539 case DW_CFA_def_cfa:
ian@0 540 state->cfa.reg = get_uleb128(&ptr.p8, end);
ian@0 541 /*nobreak*/
ian@0 542 case DW_CFA_def_cfa_offset:
ian@0 543 state->cfa.offs = get_uleb128(&ptr.p8, end);
ian@0 544 break;
ian@0 545 case DW_CFA_def_cfa_sf:
ian@0 546 state->cfa.reg = get_uleb128(&ptr.p8, end);
ian@0 547 /*nobreak*/
ian@0 548 case DW_CFA_def_cfa_offset_sf:
ian@0 549 state->cfa.offs = get_sleb128(&ptr.p8, end)
ian@0 550 * state->dataAlign;
ian@0 551 break;
ian@0 552 case DW_CFA_def_cfa_register:
ian@0 553 state->cfa.reg = get_uleb128(&ptr.p8, end);
ian@0 554 break;
ian@0 555 /*todo case DW_CFA_def_cfa_expression: */
ian@0 556 /*todo case DW_CFA_expression: */
ian@0 557 /*todo case DW_CFA_val_expression: */
ian@0 558 case DW_CFA_GNU_args_size:
ian@0 559 get_uleb128(&ptr.p8, end);
ian@0 560 break;
ian@0 561 case DW_CFA_GNU_negative_offset_extended:
ian@0 562 value = get_uleb128(&ptr.p8, end);
ian@0 563 set_rule(value,
ian@0 564 Memory,
ian@0 565 (uleb128_t)0 - get_uleb128(&ptr.p8, end), state);
ian@0 566 break;
ian@0 567 case DW_CFA_GNU_window_save:
ian@0 568 default:
ian@0 569 result = 0;
ian@0 570 break;
ian@0 571 }
ian@0 572 break;
ian@0 573 case 1:
ian@0 574 result = advance_loc(*ptr.p8++ & 0x3f, state);
ian@0 575 break;
ian@0 576 case 2:
ian@0 577 value = *ptr.p8++ & 0x3f;
ian@0 578 set_rule(value, Memory, get_uleb128(&ptr.p8, end), state);
ian@0 579 break;
ian@0 580 case 3:
ian@0 581 set_rule(*ptr.p8++ & 0x3f, Nowhere, 0, state);
ian@0 582 break;
ian@0 583 }
ian@0 584 if (ptr.p8 > end)
ian@0 585 result = 0;
ian@0 586 if (result && targetLoc != 0 && targetLoc < state->loc)
ian@0 587 return 1;
ian@0 588 }
ian@0 589
ian@0 590 return result
ian@0 591 && ptr.p8 == end
ian@0 592 && (targetLoc == 0
ian@0 593 || (/*todo While in theory this should apply, gcc in practice omits
ian@0 594 everything past the function prolog, and hence the location
ian@0 595 never reaches the end of the function.
ian@0 596 targetLoc < state->loc &&*/ state->label == NULL));
ian@0 597 }
ian@0 598
ian@0 599 /* Unwind to previous to frame. Returns 0 if successful, negative
ian@0 600 * number in case of an error. */
ian@0 601 int unwind(struct unwind_frame_info *frame)
ian@0 602 {
ian@0 603 #define FRAME_REG(r, t) (((t *)frame)[reg_info[r].offs])
ian@0 604 const u32 *fde = NULL, *cie = NULL;
ian@0 605 const u8 *ptr = NULL, *end = NULL;
ian@0 606 unsigned long startLoc = 0, endLoc = 0, cfa;
ian@0 607 unsigned i;
ian@0 608 signed ptrType = -1;
ian@0 609 uleb128_t retAddrReg = 0;
ian@0 610 struct unwind_table *table;
ian@0 611 struct unwind_state state;
ian@0 612
ian@0 613 if (UNW_PC(frame) == 0)
ian@0 614 return -EINVAL;
ian@0 615 if ((table = find_table(UNW_PC(frame))) != NULL
ian@0 616 && !(table->size & (sizeof(*fde) - 1))) {
ian@0 617 unsigned long tableSize = table->size;
ian@0 618
ian@0 619 for (fde = table->address;
ian@0 620 tableSize > sizeof(*fde) && tableSize - sizeof(*fde) >= *fde;
ian@0 621 tableSize -= sizeof(*fde) + *fde,
ian@0 622 fde += 1 + *fde / sizeof(*fde)) {
ian@0 623 if (!*fde || (*fde & (sizeof(*fde) - 1)))
ian@0 624 break;
ian@0 625 if (!fde[1])
ian@0 626 continue; /* this is a CIE */
ian@0 627 if ((fde[1] & (sizeof(*fde) - 1))
ian@0 628 || fde[1] > (unsigned long)(fde + 1)
ian@0 629 - (unsigned long)table->address)
ian@0 630 continue; /* this is not a valid FDE */
ian@0 631 cie = fde + 1 - fde[1] / sizeof(*fde);
ian@0 632 if (*cie <= sizeof(*cie) + 4
ian@0 633 || *cie >= fde[1] - sizeof(*fde)
ian@0 634 || (*cie & (sizeof(*cie) - 1))
ian@0 635 || cie[1]
ian@0 636 || (ptrType = fde_pointer_type(cie)) < 0) {
ian@0 637 cie = NULL; /* this is not a (valid) CIE */
ian@0 638 continue;
ian@0 639 }
ian@0 640 ptr = (const u8 *)(fde + 2);
ian@0 641 startLoc = read_pointer(&ptr,
ian@0 642 (const u8 *)(fde + 1) + *fde,
ian@0 643 ptrType);
ian@0 644 endLoc = startLoc
ian@0 645 + read_pointer(&ptr,
ian@0 646 (const u8 *)(fde + 1) + *fde,
ian@0 647 ptrType & DW_EH_PE_indirect
ian@0 648 ? ptrType
ian@0 649 : ptrType & (DW_EH_PE_FORM|DW_EH_PE_signed));
ian@0 650 if (UNW_PC(frame) >= startLoc && UNW_PC(frame) < endLoc)
ian@0 651 break;
ian@0 652 cie = NULL;
ian@0 653 }
ian@0 654 }
ian@0 655 if (cie != NULL) {
ian@0 656 memset(&state, 0, sizeof(state));
ian@0 657 state.cieEnd = ptr; /* keep here temporarily */
ian@0 658 ptr = (const u8 *)(cie + 2);
ian@0 659 end = (const u8 *)(cie + 1) + *cie;
ian@0 660 if ((state.version = *ptr) != 1)
ian@0 661 cie = NULL; /* unsupported version */
ian@0 662 else if (*++ptr) {
ian@0 663 /* check if augmentation size is first (and thus present) */
ian@0 664 if (*ptr == 'z') {
ian@0 665 /* check for ignorable (or already handled)
ian@0 666 * nul-terminated augmentation string */
ian@0 667 while (++ptr < end && *ptr)
ian@0 668 if (strchr("LPR", *ptr) == NULL)
ian@0 669 break;
ian@0 670 }
ian@0 671 if (ptr >= end || *ptr)
ian@0 672 cie = NULL;
ian@0 673 }
ian@0 674 ++ptr;
ian@0 675 }
ian@0 676 if (cie != NULL) {
ian@0 677 /* get code aligment factor */
ian@0 678 state.codeAlign = get_uleb128(&ptr, end);
ian@0 679 /* get data aligment factor */
ian@0 680 state.dataAlign = get_sleb128(&ptr, end);
ian@0 681 if (state.codeAlign == 0 || state.dataAlign == 0 || ptr >= end)
ian@0 682 cie = NULL;
ian@0 683 else {
ian@0 684 retAddrReg = state.version <= 1 ? *ptr++ : get_uleb128(&ptr, end);
ian@0 685 /* skip augmentation */
ian@0 686 if (((const char *)(cie + 2))[1] == 'z')
ian@0 687 ptr += get_uleb128(&ptr, end);
ian@0 688 if (ptr > end
ian@0 689 || retAddrReg >= ARRAY_SIZE(reg_info)
ian@0 690 || REG_INVALID(retAddrReg)
ian@0 691 || reg_info[retAddrReg].width != sizeof(unsigned long))
ian@0 692 cie = NULL;
ian@0 693 }
ian@0 694 }
ian@0 695 if (cie != NULL) {
ian@0 696 state.cieStart = ptr;
ian@0 697 ptr = state.cieEnd;
ian@0 698 state.cieEnd = end;
ian@0 699 end = (const u8 *)(fde + 1) + *fde;
ian@0 700 /* skip augmentation */
ian@0 701 if (((const char *)(cie + 2))[1] == 'z') {
ian@0 702 uleb128_t augSize = get_uleb128(&ptr, end);
ian@0 703
ian@0 704 if ((ptr += augSize) > end)
ian@0 705 fde = NULL;
ian@0 706 }
ian@0 707 }
ian@0 708 if (cie == NULL || fde == NULL) {
ian@0 709 #ifdef CONFIG_FRAME_POINTER
ian@0 710 unsigned long top, bottom;
ian@0 711 #endif
ian@0 712
ian@0 713 #ifdef CONFIG_FRAME_POINTER
ian@0 714 top = STACK_TOP(frame->task);
ian@0 715 bottom = STACK_BOTTOM(frame->task);
ian@0 716 # if FRAME_RETADDR_OFFSET < 0
ian@0 717 if (UNW_SP(frame) < top
ian@0 718 && UNW_FP(frame) <= UNW_SP(frame)
ian@0 719 && bottom < UNW_FP(frame)
ian@0 720 # else
ian@0 721 if (UNW_SP(frame) > top
ian@0 722 && UNW_FP(frame) >= UNW_SP(frame)
ian@0 723 && bottom > UNW_FP(frame)
ian@0 724 # endif
ian@0 725 && !((UNW_SP(frame) | UNW_FP(frame))
ian@0 726 & (sizeof(unsigned long) - 1))) {
ian@0 727 unsigned long link;
ian@0 728
ian@0 729 if (!__get_user(link,
ian@0 730 (unsigned long *)(UNW_FP(frame)
ian@0 731 + FRAME_LINK_OFFSET))
ian@0 732 # if FRAME_RETADDR_OFFSET < 0
ian@0 733 && link > bottom && link < UNW_FP(frame)
ian@0 734 # else
ian@0 735 && link > UNW_FP(frame) && link < bottom
ian@0 736 # endif
ian@0 737 && !(link & (sizeof(link) - 1))
ian@0 738 && !__get_user(UNW_PC(frame),
ian@0 739 (unsigned long *)(UNW_FP(frame)
ian@0 740 + FRAME_RETADDR_OFFSET))) {
ian@0 741 UNW_SP(frame) = UNW_FP(frame) + FRAME_RETADDR_OFFSET
ian@0 742 # if FRAME_RETADDR_OFFSET < 0
ian@0 743 -
ian@0 744 # else
ian@0 745 +
ian@0 746 # endif
ian@0 747 sizeof(UNW_PC(frame));
ian@0 748 UNW_FP(frame) = link;
ian@0 749 return 0;
ian@0 750 }
ian@0 751 }
ian@0 752 #endif
ian@0 753 return -ENXIO;
ian@0 754 }
ian@0 755 state.org = startLoc;
ian@0 756 memcpy(&state.cfa, &badCFA, sizeof(state.cfa));
ian@0 757 /* process instructions */
ian@0 758 if (!processCFI(ptr, end, UNW_PC(frame), ptrType, &state)
ian@0 759 || state.loc > endLoc
ian@0 760 || state.regs[retAddrReg].where == Nowhere
ian@0 761 || state.cfa.reg >= ARRAY_SIZE(reg_info)
ian@0 762 || reg_info[state.cfa.reg].width != sizeof(unsigned long)
ian@0 763 || state.cfa.offs % sizeof(unsigned long))
ian@0 764 return -EIO;
ian@0 765 /* update frame */
ian@0 766 cfa = FRAME_REG(state.cfa.reg, unsigned long) + state.cfa.offs;
ian@0 767 startLoc = min((unsigned long)UNW_SP(frame), cfa);
ian@0 768 endLoc = max((unsigned long)UNW_SP(frame), cfa);
ian@0 769 if (STACK_LIMIT(startLoc) != STACK_LIMIT(endLoc)) {
ian@0 770 startLoc = min(STACK_LIMIT(cfa), cfa);
ian@0 771 endLoc = max(STACK_LIMIT(cfa), cfa);
ian@0 772 }
ian@0 773 #ifndef CONFIG_64BIT
ian@0 774 # define CASES CASE(8); CASE(16); CASE(32)
ian@0 775 #else
ian@0 776 # define CASES CASE(8); CASE(16); CASE(32); CASE(64)
ian@0 777 #endif
ian@0 778 for (i = 0; i < ARRAY_SIZE(state.regs); ++i) {
ian@0 779 if (REG_INVALID(i)) {
ian@0 780 if (state.regs[i].where == Nowhere)
ian@0 781 continue;
ian@0 782 return -EIO;
ian@0 783 }
ian@0 784 switch(state.regs[i].where) {
ian@0 785 default:
ian@0 786 break;
ian@0 787 case Register:
ian@0 788 if (state.regs[i].value >= ARRAY_SIZE(reg_info)
ian@0 789 || REG_INVALID(state.regs[i].value)
ian@0 790 || reg_info[i].width > reg_info[state.regs[i].value].width)
ian@0 791 return -EIO;
ian@0 792 switch(reg_info[state.regs[i].value].width) {
ian@0 793 #define CASE(n) \
ian@0 794 case sizeof(u##n): \
ian@0 795 state.regs[i].value = FRAME_REG(state.regs[i].value, \
ian@0 796 const u##n); \
ian@0 797 break
ian@0 798 CASES;
ian@0 799 #undef CASE
ian@0 800 default:
ian@0 801 return -EIO;
ian@0 802 }
ian@0 803 break;
ian@0 804 }
ian@0 805 }
ian@0 806 for (i = 0; i < ARRAY_SIZE(state.regs); ++i) {
ian@0 807 if (REG_INVALID(i))
ian@0 808 continue;
ian@0 809 switch(state.regs[i].where) {
ian@0 810 case Nowhere:
ian@0 811 if (reg_info[i].width != sizeof(UNW_SP(frame))
ian@0 812 || &FRAME_REG(i, __typeof__(UNW_SP(frame)))
ian@0 813 != &UNW_SP(frame))
ian@0 814 continue;
ian@0 815 UNW_SP(frame) = cfa;
ian@0 816 break;
ian@0 817 case Register:
ian@0 818 switch(reg_info[i].width) {
ian@0 819 #define CASE(n) case sizeof(u##n): \
ian@0 820 FRAME_REG(i, u##n) = state.regs[i].value; \
ian@0 821 break
ian@0 822 CASES;
ian@0 823 #undef CASE
ian@0 824 default:
ian@0 825 return -EIO;
ian@0 826 }
ian@0 827 break;
ian@0 828 case Value:
ian@0 829 if (reg_info[i].width != sizeof(unsigned long))
ian@0 830 return -EIO;
ian@0 831 FRAME_REG(i, unsigned long) = cfa + state.regs[i].value
ian@0 832 * state.dataAlign;
ian@0 833 break;
ian@0 834 case Memory: {
ian@0 835 unsigned long addr = cfa + state.regs[i].value
ian@0 836 * state.dataAlign;
ian@0 837
ian@0 838 if ((state.regs[i].value * state.dataAlign)
ian@0 839 % sizeof(unsigned long)
ian@0 840 || addr < startLoc
ian@0 841 || addr + sizeof(unsigned long) < addr
ian@0 842 || addr + sizeof(unsigned long) > endLoc)
ian@0 843 return -EIO;
ian@0 844 switch(reg_info[i].width) {
ian@0 845 #define CASE(n) case sizeof(u##n): \
ian@0 846 __get_user(FRAME_REG(i, u##n), (u##n *)addr); \
ian@0 847 break
ian@0 848 CASES;
ian@0 849 #undef CASE
ian@0 850 default:
ian@0 851 return -EIO;
ian@0 852 }
ian@0 853 }
ian@0 854 break;
ian@0 855 }
ian@0 856 }
ian@0 857
ian@0 858 return 0;
ian@0 859 #undef CASES
ian@0 860 #undef FRAME_REG
ian@0 861 }
ian@0 862 EXPORT_SYMBOL(unwind);
ian@0 863
ian@0 864 int unwind_init_frame_info(struct unwind_frame_info *info,
ian@0 865 struct task_struct *tsk,
ian@0 866 /*const*/ struct pt_regs *regs)
ian@0 867 {
ian@0 868 info->task = tsk;
ian@0 869 arch_unw_init_frame_info(info, regs);
ian@0 870
ian@0 871 return 0;
ian@0 872 }
ian@0 873 EXPORT_SYMBOL(unwind_init_frame_info);
ian@0 874
ian@0 875 /*
ian@0 876 * Prepare to unwind a blocked task.
ian@0 877 */
ian@0 878 int unwind_init_blocked(struct unwind_frame_info *info,
ian@0 879 struct task_struct *tsk)
ian@0 880 {
ian@0 881 info->task = tsk;
ian@0 882 arch_unw_init_blocked(info);
ian@0 883
ian@0 884 return 0;
ian@0 885 }
ian@0 886 EXPORT_SYMBOL(unwind_init_blocked);
ian@0 887
ian@0 888 /*
ian@0 889 * Prepare to unwind the currently running thread.
ian@0 890 */
ian@0 891 int unwind_init_running(struct unwind_frame_info *info,
ian@0 892 asmlinkage int (*callback)(struct unwind_frame_info *,
ian@0 893 void *arg),
ian@0 894 void *arg)
ian@0 895 {
ian@0 896 info->task = current;
ian@0 897
ian@0 898 return arch_unwind_init_running(info, callback, arg);
ian@0 899 }
ian@0 900 EXPORT_SYMBOL(unwind_init_running);
ian@0 901
ian@0 902 /*
ian@0 903 * Unwind until the return pointer is in user-land (or until an error
ian@0 904 * occurs). Returns 0 if successful, negative number in case of
ian@0 905 * error.
ian@0 906 */
ian@0 907 int unwind_to_user(struct unwind_frame_info *info)
ian@0 908 {
ian@0 909 while (!arch_unw_user_mode(info)) {
ian@0 910 int err = unwind(info);
ian@0 911
ian@0 912 if (err < 0)
ian@0 913 return err;
ian@0 914 }
ian@0 915
ian@0 916 return 0;
ian@0 917 }
ian@0 918 EXPORT_SYMBOL(unwind_to_user);