diff options
author | Josh Poimboeuf <jpoimboe@redhat.com> | 2017-10-20 12:21:34 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2017-10-23 07:30:36 -0400 |
commit | 58c3862b521ead4f69a24ef009a679cb3c519620 (patch) | |
tree | 46690af4e8076e6a81b61ec2fe275ee7489b7400 | |
parent | 98990a33b77dda9babf91cb235654f6729e5702e (diff) |
x86/unwind: Show function name+offset in ORC error messages
Improve the warning messages to show the relevant function name+offset.
This makes it much easier to diagnose problems with the ORC metadata.
Before:
WARNING: can't dereference iret registers at ffff8801c5f17fe0 for ip ffffffff95f0d94b
After:
WARNING: can't dereference iret registers at ffff880178f5ffe0 for ip int3+0x5b/0x60
Reported-by: Andrei Vagin <avagin@virtuozzo.com>
Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Fixes: ee9f8fce9964 ("x86/unwind: Add the ORC unwinder")
Link: http://lkml.kernel.org/r/6bada6b9eac86017e16bd79e1e77877935cb50bb.1508516398.git.jpoimboe@redhat.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | arch/x86/kernel/unwind_orc.c | 29 |
1 files changed, 15 insertions, 14 deletions
diff --git a/arch/x86/kernel/unwind_orc.c b/arch/x86/kernel/unwind_orc.c index 570b70d3f604..b95007e7c1b3 100644 --- a/arch/x86/kernel/unwind_orc.c +++ b/arch/x86/kernel/unwind_orc.c | |||
@@ -86,8 +86,8 @@ static struct orc_entry *orc_find(unsigned long ip) | |||
86 | idx = (ip - LOOKUP_START_IP) / LOOKUP_BLOCK_SIZE; | 86 | idx = (ip - LOOKUP_START_IP) / LOOKUP_BLOCK_SIZE; |
87 | 87 | ||
88 | if (unlikely((idx >= lookup_num_blocks-1))) { | 88 | if (unlikely((idx >= lookup_num_blocks-1))) { |
89 | orc_warn("WARNING: bad lookup idx: idx=%u num=%u ip=%lx\n", | 89 | orc_warn("WARNING: bad lookup idx: idx=%u num=%u ip=%pB\n", |
90 | idx, lookup_num_blocks, ip); | 90 | idx, lookup_num_blocks, (void *)ip); |
91 | return NULL; | 91 | return NULL; |
92 | } | 92 | } |
93 | 93 | ||
@@ -96,8 +96,8 @@ static struct orc_entry *orc_find(unsigned long ip) | |||
96 | 96 | ||
97 | if (unlikely((__start_orc_unwind + start >= __stop_orc_unwind) || | 97 | if (unlikely((__start_orc_unwind + start >= __stop_orc_unwind) || |
98 | (__start_orc_unwind + stop > __stop_orc_unwind))) { | 98 | (__start_orc_unwind + stop > __stop_orc_unwind))) { |
99 | orc_warn("WARNING: bad lookup value: idx=%u num=%u start=%u stop=%u ip=%lx\n", | 99 | orc_warn("WARNING: bad lookup value: idx=%u num=%u start=%u stop=%u ip=%pB\n", |
100 | idx, lookup_num_blocks, start, stop, ip); | 100 | idx, lookup_num_blocks, start, stop, (void *)ip); |
101 | return NULL; | 101 | return NULL; |
102 | } | 102 | } |
103 | 103 | ||
@@ -373,7 +373,7 @@ bool unwind_next_frame(struct unwind_state *state) | |||
373 | 373 | ||
374 | case ORC_REG_R10: | 374 | case ORC_REG_R10: |
375 | if (!state->regs || !state->full_regs) { | 375 | if (!state->regs || !state->full_regs) { |
376 | orc_warn("missing regs for base reg R10 at ip %p\n", | 376 | orc_warn("missing regs for base reg R10 at ip %pB\n", |
377 | (void *)state->ip); | 377 | (void *)state->ip); |
378 | goto done; | 378 | goto done; |
379 | } | 379 | } |
@@ -382,7 +382,7 @@ bool unwind_next_frame(struct unwind_state *state) | |||
382 | 382 | ||
383 | case ORC_REG_R13: | 383 | case ORC_REG_R13: |
384 | if (!state->regs || !state->full_regs) { | 384 | if (!state->regs || !state->full_regs) { |
385 | orc_warn("missing regs for base reg R13 at ip %p\n", | 385 | orc_warn("missing regs for base reg R13 at ip %pB\n", |
386 | (void *)state->ip); | 386 | (void *)state->ip); |
387 | goto done; | 387 | goto done; |
388 | } | 388 | } |
@@ -391,7 +391,7 @@ bool unwind_next_frame(struct unwind_state *state) | |||
391 | 391 | ||
392 | case ORC_REG_DI: | 392 | case ORC_REG_DI: |
393 | if (!state->regs || !state->full_regs) { | 393 | if (!state->regs || !state->full_regs) { |
394 | orc_warn("missing regs for base reg DI at ip %p\n", | 394 | orc_warn("missing regs for base reg DI at ip %pB\n", |
395 | (void *)state->ip); | 395 | (void *)state->ip); |
396 | goto done; | 396 | goto done; |
397 | } | 397 | } |
@@ -400,7 +400,7 @@ bool unwind_next_frame(struct unwind_state *state) | |||
400 | 400 | ||
401 | case ORC_REG_DX: | 401 | case ORC_REG_DX: |
402 | if (!state->regs || !state->full_regs) { | 402 | if (!state->regs || !state->full_regs) { |
403 | orc_warn("missing regs for base reg DX at ip %p\n", | 403 | orc_warn("missing regs for base reg DX at ip %pB\n", |
404 | (void *)state->ip); | 404 | (void *)state->ip); |
405 | goto done; | 405 | goto done; |
406 | } | 406 | } |
@@ -408,7 +408,7 @@ bool unwind_next_frame(struct unwind_state *state) | |||
408 | break; | 408 | break; |
409 | 409 | ||
410 | default: | 410 | default: |
411 | orc_warn("unknown SP base reg %d for ip %p\n", | 411 | orc_warn("unknown SP base reg %d for ip %pB\n", |
412 | orc->sp_reg, (void *)state->ip); | 412 | orc->sp_reg, (void *)state->ip); |
413 | goto done; | 413 | goto done; |
414 | } | 414 | } |
@@ -436,7 +436,7 @@ bool unwind_next_frame(struct unwind_state *state) | |||
436 | 436 | ||
437 | case ORC_TYPE_REGS: | 437 | case ORC_TYPE_REGS: |
438 | if (!deref_stack_regs(state, sp, &state->ip, &state->sp, true)) { | 438 | if (!deref_stack_regs(state, sp, &state->ip, &state->sp, true)) { |
439 | orc_warn("can't dereference registers at %p for ip %p\n", | 439 | orc_warn("can't dereference registers at %p for ip %pB\n", |
440 | (void *)sp, (void *)orig_ip); | 440 | (void *)sp, (void *)orig_ip); |
441 | goto done; | 441 | goto done; |
442 | } | 442 | } |
@@ -448,7 +448,7 @@ bool unwind_next_frame(struct unwind_state *state) | |||
448 | 448 | ||
449 | case ORC_TYPE_REGS_IRET: | 449 | case ORC_TYPE_REGS_IRET: |
450 | if (!deref_stack_regs(state, sp, &state->ip, &state->sp, false)) { | 450 | if (!deref_stack_regs(state, sp, &state->ip, &state->sp, false)) { |
451 | orc_warn("can't dereference iret registers at %p for ip %p\n", | 451 | orc_warn("can't dereference iret registers at %p for ip %pB\n", |
452 | (void *)sp, (void *)orig_ip); | 452 | (void *)sp, (void *)orig_ip); |
453 | goto done; | 453 | goto done; |
454 | } | 454 | } |
@@ -465,7 +465,8 @@ bool unwind_next_frame(struct unwind_state *state) | |||
465 | break; | 465 | break; |
466 | 466 | ||
467 | default: | 467 | default: |
468 | orc_warn("unknown .orc_unwind entry type %d\n", orc->type); | 468 | orc_warn("unknown .orc_unwind entry type %d for ip %pB\n", |
469 | orc->type, (void *)orig_ip); | ||
469 | break; | 470 | break; |
470 | } | 471 | } |
471 | 472 | ||
@@ -487,7 +488,7 @@ bool unwind_next_frame(struct unwind_state *state) | |||
487 | break; | 488 | break; |
488 | 489 | ||
489 | default: | 490 | default: |
490 | orc_warn("unknown BP base reg %d for ip %p\n", | 491 | orc_warn("unknown BP base reg %d for ip %pB\n", |
491 | orc->bp_reg, (void *)orig_ip); | 492 | orc->bp_reg, (void *)orig_ip); |
492 | goto done; | 493 | goto done; |
493 | } | 494 | } |
@@ -496,7 +497,7 @@ bool unwind_next_frame(struct unwind_state *state) | |||
496 | if (state->stack_info.type == prev_type && | 497 | if (state->stack_info.type == prev_type && |
497 | on_stack(&state->stack_info, (void *)state->sp, sizeof(long)) && | 498 | on_stack(&state->stack_info, (void *)state->sp, sizeof(long)) && |
498 | state->sp <= prev_sp) { | 499 | state->sp <= prev_sp) { |
499 | orc_warn("stack going in the wrong direction? ip=%p\n", | 500 | orc_warn("stack going in the wrong direction? ip=%pB\n", |
500 | (void *)orig_ip); | 501 | (void *)orig_ip); |
501 | goto done; | 502 | goto done; |
502 | } | 503 | } |