diff options
| author | Ingo Molnar <mingo@kernel.org> | 2017-08-18 04:29:54 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2017-08-18 04:29:54 -0400 |
| commit | 0c2364791343e4b04cd1f097ff2abc2799062448 (patch) | |
| tree | beb9d94252d42d35b2066bf23383576b0beeebeb | |
| parent | e26f34a407aec9c65bce2bc0c838fabe4f051fc6 (diff) | |
| parent | aa5d1b81500e6059190f18fe25a7617682321910 (diff) | |
Merge branch 'x86/asm' into locking/core
We need the ASM_UNREACHABLE() macro for a dependent patch.
Signed-off-by: Ingo Molnar <mingo@kernel.org>
32 files changed, 1616 insertions, 212 deletions
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug index cd20ca0b4043..1fc519f3c49e 100644 --- a/arch/x86/Kconfig.debug +++ b/arch/x86/Kconfig.debug | |||
| @@ -305,8 +305,6 @@ config DEBUG_ENTRY | |||
| 305 | Some of these sanity checks may slow down kernel entries and | 305 | Some of these sanity checks may slow down kernel entries and |
| 306 | exits or otherwise impact performance. | 306 | exits or otherwise impact performance. |
| 307 | 307 | ||
| 308 | This is currently used to help test NMI code. | ||
| 309 | |||
| 310 | If unsure, say N. | 308 | If unsure, say N. |
| 311 | 309 | ||
| 312 | config DEBUG_NMI_SELFTEST | 310 | config DEBUG_NMI_SELFTEST |
diff --git a/arch/x86/entry/Makefile b/arch/x86/entry/Makefile index 9976fcecd17e..af28a8a24366 100644 --- a/arch/x86/entry/Makefile +++ b/arch/x86/entry/Makefile | |||
| @@ -2,7 +2,6 @@ | |||
| 2 | # Makefile for the x86 low level entry code | 2 | # Makefile for the x86 low level entry code |
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | OBJECT_FILES_NON_STANDARD_entry_$(BITS).o := y | ||
| 6 | OBJECT_FILES_NON_STANDARD_entry_64_compat.o := y | 5 | OBJECT_FILES_NON_STANDARD_entry_64_compat.o := y |
| 7 | 6 | ||
| 8 | CFLAGS_syscall_64.o += $(call cc-option,-Wno-override-init,) | 7 | CFLAGS_syscall_64.o += $(call cc-option,-Wno-override-init,) |
diff --git a/arch/x86/entry/calling.h b/arch/x86/entry/calling.h index 05ed3d393da7..640aafebdc00 100644 --- a/arch/x86/entry/calling.h +++ b/arch/x86/entry/calling.h | |||
| @@ -1,4 +1,5 @@ | |||
| 1 | #include <linux/jump_label.h> | 1 | #include <linux/jump_label.h> |
| 2 | #include <asm/unwind_hints.h> | ||
| 2 | 3 | ||
| 3 | /* | 4 | /* |
| 4 | 5 | ||
| @@ -112,6 +113,7 @@ For 32-bit we have the following conventions - kernel is built with | |||
| 112 | movq %rdx, 12*8+\offset(%rsp) | 113 | movq %rdx, 12*8+\offset(%rsp) |
| 113 | movq %rsi, 13*8+\offset(%rsp) | 114 | movq %rsi, 13*8+\offset(%rsp) |
| 114 | movq %rdi, 14*8+\offset(%rsp) | 115 | movq %rdi, 14*8+\offset(%rsp) |
| 116 | UNWIND_HINT_REGS offset=\offset extra=0 | ||
| 115 | .endm | 117 | .endm |
| 116 | .macro SAVE_C_REGS offset=0 | 118 | .macro SAVE_C_REGS offset=0 |
| 117 | SAVE_C_REGS_HELPER \offset, 1, 1, 1, 1 | 119 | SAVE_C_REGS_HELPER \offset, 1, 1, 1, 1 |
| @@ -136,6 +138,7 @@ For 32-bit we have the following conventions - kernel is built with | |||
| 136 | movq %r12, 3*8+\offset(%rsp) | 138 | movq %r12, 3*8+\offset(%rsp) |
| 137 | movq %rbp, 4*8+\offset(%rsp) | 139 | movq %rbp, 4*8+\offset(%rsp) |
| 138 | movq %rbx, 5*8+\offset(%rsp) | 140 | movq %rbx, 5*8+\offset(%rsp) |
| 141 | UNWIND_HINT_REGS offset=\offset | ||
| 139 | .endm | 142 | .endm |
| 140 | 143 | ||
| 141 | .macro RESTORE_EXTRA_REGS offset=0 | 144 | .macro RESTORE_EXTRA_REGS offset=0 |
| @@ -145,6 +148,7 @@ For 32-bit we have the following conventions - kernel is built with | |||
| 145 | movq 3*8+\offset(%rsp), %r12 | 148 | movq 3*8+\offset(%rsp), %r12 |
| 146 | movq 4*8+\offset(%rsp), %rbp | 149 | movq 4*8+\offset(%rsp), %rbp |
| 147 | movq 5*8+\offset(%rsp), %rbx | 150 | movq 5*8+\offset(%rsp), %rbx |
| 151 | UNWIND_HINT_REGS offset=\offset extra=0 | ||
| 148 | .endm | 152 | .endm |
| 149 | 153 | ||
| 150 | .macro RESTORE_C_REGS_HELPER rstor_rax=1, rstor_rcx=1, rstor_r11=1, rstor_r8910=1, rstor_rdx=1 | 154 | .macro RESTORE_C_REGS_HELPER rstor_rax=1, rstor_rcx=1, rstor_r11=1, rstor_r8910=1, rstor_rdx=1 |
| @@ -167,6 +171,7 @@ For 32-bit we have the following conventions - kernel is built with | |||
| 167 | .endif | 171 | .endif |
| 168 | movq 13*8(%rsp), %rsi | 172 | movq 13*8(%rsp), %rsi |
| 169 | movq 14*8(%rsp), %rdi | 173 | movq 14*8(%rsp), %rdi |
| 174 | UNWIND_HINT_IRET_REGS offset=16*8 | ||
| 170 | .endm | 175 | .endm |
| 171 | .macro RESTORE_C_REGS | 176 | .macro RESTORE_C_REGS |
| 172 | RESTORE_C_REGS_HELPER 1,1,1,1,1 | 177 | RESTORE_C_REGS_HELPER 1,1,1,1,1 |
diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S index d271fb79248f..daf8936d0628 100644 --- a/arch/x86/entry/entry_64.S +++ b/arch/x86/entry/entry_64.S | |||
| @@ -36,6 +36,7 @@ | |||
| 36 | #include <asm/smap.h> | 36 | #include <asm/smap.h> |
| 37 | #include <asm/pgtable_types.h> | 37 | #include <asm/pgtable_types.h> |
| 38 | #include <asm/export.h> | 38 | #include <asm/export.h> |
| 39 | #include <asm/frame.h> | ||
| 39 | #include <linux/err.h> | 40 | #include <linux/err.h> |
| 40 | 41 | ||
| 41 | .code64 | 42 | .code64 |
| @@ -43,9 +44,10 @@ | |||
| 43 | 44 | ||
| 44 | #ifdef CONFIG_PARAVIRT | 45 | #ifdef CONFIG_PARAVIRT |
| 45 | ENTRY(native_usergs_sysret64) | 46 | ENTRY(native_usergs_sysret64) |
| 47 | UNWIND_HINT_EMPTY | ||
| 46 | swapgs | 48 | swapgs |
| 47 | sysretq | 49 | sysretq |
| 48 | ENDPROC(native_usergs_sysret64) | 50 | END(native_usergs_sysret64) |
| 49 | #endif /* CONFIG_PARAVIRT */ | 51 | #endif /* CONFIG_PARAVIRT */ |
| 50 | 52 | ||
| 51 | .macro TRACE_IRQS_IRETQ | 53 | .macro TRACE_IRQS_IRETQ |
| @@ -134,6 +136,7 @@ ENDPROC(native_usergs_sysret64) | |||
| 134 | */ | 136 | */ |
| 135 | 137 | ||
| 136 | ENTRY(entry_SYSCALL_64) | 138 | ENTRY(entry_SYSCALL_64) |
| 139 | UNWIND_HINT_EMPTY | ||
| 137 | /* | 140 | /* |
| 138 | * Interrupts are off on entry. | 141 | * Interrupts are off on entry. |
| 139 | * We do not frame this tiny irq-off block with TRACE_IRQS_OFF/ON, | 142 | * We do not frame this tiny irq-off block with TRACE_IRQS_OFF/ON, |
| @@ -169,6 +172,7 @@ GLOBAL(entry_SYSCALL_64_after_swapgs) | |||
| 169 | pushq %r10 /* pt_regs->r10 */ | 172 | pushq %r10 /* pt_regs->r10 */ |
| 170 | pushq %r11 /* pt_regs->r11 */ | 173 | pushq %r11 /* pt_regs->r11 */ |
| 171 | sub $(6*8), %rsp /* pt_regs->bp, bx, r12-15 not saved */ | 174 | sub $(6*8), %rsp /* pt_regs->bp, bx, r12-15 not saved */ |
| 175 | UNWIND_HINT_REGS extra=0 | ||
| 172 | 176 | ||
| 173 | /* | 177 | /* |
| 174 | * If we need to do entry work or if we guess we'll need to do | 178 | * If we need to do entry work or if we guess we'll need to do |
| @@ -223,6 +227,7 @@ entry_SYSCALL_64_fastpath: | |||
| 223 | movq EFLAGS(%rsp), %r11 | 227 | movq EFLAGS(%rsp), %r11 |
| 224 | RESTORE_C_REGS_EXCEPT_RCX_R11 | 228 | RESTORE_C_REGS_EXCEPT_RCX_R11 |
| 225 | movq RSP(%rsp), %rsp | 229 | movq RSP(%rsp), %rsp |
| 230 | UNWIND_HINT_EMPTY | ||
| 226 | USERGS_SYSRET64 | 231 | USERGS_SYSRET64 |
| 227 | 232 | ||
| 228 | 1: | 233 | 1: |
| @@ -316,6 +321,7 @@ syscall_return_via_sysret: | |||
| 316 | /* rcx and r11 are already restored (see code above) */ | 321 | /* rcx and r11 are already restored (see code above) */ |
| 317 | RESTORE_C_REGS_EXCEPT_RCX_R11 | 322 | RESTORE_C_REGS_EXCEPT_RCX_R11 |
| 318 | movq RSP(%rsp), %rsp | 323 | movq RSP(%rsp), %rsp |
| 324 | UNWIND_HINT_EMPTY | ||
| 319 | USERGS_SYSRET64 | 325 | USERGS_SYSRET64 |
| 320 | 326 | ||
| 321 | opportunistic_sysret_failed: | 327 | opportunistic_sysret_failed: |
| @@ -343,6 +349,7 @@ ENTRY(stub_ptregs_64) | |||
| 343 | DISABLE_INTERRUPTS(CLBR_ANY) | 349 | DISABLE_INTERRUPTS(CLBR_ANY) |
| 344 | TRACE_IRQS_OFF | 350 | TRACE_IRQS_OFF |
| 345 | popq %rax | 351 | popq %rax |
| 352 | UNWIND_HINT_REGS extra=0 | ||
| 346 | jmp entry_SYSCALL64_slow_path | 353 | jmp entry_SYSCALL64_slow_path |
| 347 | 354 | ||
| 348 | 1: | 355 | 1: |
| @@ -351,6 +358,7 @@ END(stub_ptregs_64) | |||
| 351 | 358 | ||
| 352 | .macro ptregs_stub func | 359 | .macro ptregs_stub func |
| 353 | ENTRY(ptregs_\func) | 360 | ENTRY(ptregs_\func) |
| 361 | UNWIND_HINT_FUNC | ||
| 354 | leaq \func(%rip), %rax | 362 | leaq \func(%rip), %rax |
| 355 | jmp stub_ptregs_64 | 363 | jmp stub_ptregs_64 |
| 356 | END(ptregs_\func) | 364 | END(ptregs_\func) |
| @@ -367,6 +375,7 @@ END(ptregs_\func) | |||
| 367 | * %rsi: next task | 375 | * %rsi: next task |
| 368 | */ | 376 | */ |
| 369 | ENTRY(__switch_to_asm) | 377 | ENTRY(__switch_to_asm) |
| 378 | UNWIND_HINT_FUNC | ||
| 370 | /* | 379 | /* |
| 371 | * Save callee-saved registers | 380 | * Save callee-saved registers |
| 372 | * This must match the order in inactive_task_frame | 381 | * This must match the order in inactive_task_frame |
| @@ -406,6 +415,7 @@ END(__switch_to_asm) | |||
| 406 | * r12: kernel thread arg | 415 | * r12: kernel thread arg |
| 407 | */ | 416 | */ |
| 408 | ENTRY(ret_from_fork) | 417 | ENTRY(ret_from_fork) |
| 418 | UNWIND_HINT_EMPTY | ||
| 409 | movq %rax, %rdi | 419 | movq %rax, %rdi |
| 410 | call schedule_tail /* rdi: 'prev' task parameter */ | 420 | call schedule_tail /* rdi: 'prev' task parameter */ |
| 411 | 421 | ||
| @@ -413,6 +423,7 @@ ENTRY(ret_from_fork) | |||
| 413 | jnz 1f /* kernel threads are uncommon */ | 423 | jnz 1f /* kernel threads are uncommon */ |
| 414 | 424 | ||
| 415 | 2: | 425 | 2: |
| 426 | UNWIND_HINT_REGS | ||
| 416 | movq %rsp, %rdi | 427 | movq %rsp, %rdi |
| 417 | call syscall_return_slowpath /* returns with IRQs disabled */ | 428 | call syscall_return_slowpath /* returns with IRQs disabled */ |
| 418 | TRACE_IRQS_ON /* user mode is traced as IRQS on */ | 429 | TRACE_IRQS_ON /* user mode is traced as IRQS on */ |
| @@ -440,13 +451,102 @@ END(ret_from_fork) | |||
| 440 | ENTRY(irq_entries_start) | 451 | ENTRY(irq_entries_start) |
| 441 | vector=FIRST_EXTERNAL_VECTOR | 452 | vector=FIRST_EXTERNAL_VECTOR |
| 442 | .rept (FIRST_SYSTEM_VECTOR - FIRST_EXTERNAL_VECTOR) | 453 | .rept (FIRST_SYSTEM_VECTOR - FIRST_EXTERNAL_VECTOR) |
| 454 | UNWIND_HINT_IRET_REGS | ||
| 443 | pushq $(~vector+0x80) /* Note: always in signed byte range */ | 455 | pushq $(~vector+0x80) /* Note: always in signed byte range */ |
| 444 | vector=vector+1 | ||
| 445 | jmp common_interrupt | 456 | jmp common_interrupt |
| 446 | .align 8 | 457 | .align 8 |
| 458 | vector=vector+1 | ||
| 447 | .endr | 459 | .endr |
| 448 | END(irq_entries_start) | 460 | END(irq_entries_start) |
| 449 | 461 | ||
| 462 | .macro DEBUG_ENTRY_ASSERT_IRQS_OFF | ||
| 463 | #ifdef CONFIG_DEBUG_ENTRY | ||
| 464 | pushfq | ||
| 465 | testl $X86_EFLAGS_IF, (%rsp) | ||
| 466 | jz .Lokay_\@ | ||
| 467 | ud2 | ||
| 468 | .Lokay_\@: | ||
| 469 | addq $8, %rsp | ||
| 470 | #endif | ||
| 471 | .endm | ||
| 472 | |||
| 473 | /* | ||
| 474 | * Enters the IRQ stack if we're not already using it. NMI-safe. Clobbers | ||
| 475 | * flags and puts old RSP into old_rsp, and leaves all other GPRs alone. | ||
| 476 | * Requires kernel GSBASE. | ||
| 477 | * | ||
| 478 | * The invariant is that, if irq_count != -1, then the IRQ stack is in use. | ||
| 479 | */ | ||
| 480 | .macro ENTER_IRQ_STACK regs=1 old_rsp | ||
| 481 | DEBUG_ENTRY_ASSERT_IRQS_OFF | ||
| 482 | movq %rsp, \old_rsp | ||
| 483 | |||
| 484 | .if \regs | ||
| 485 | UNWIND_HINT_REGS base=\old_rsp | ||
| 486 | .endif | ||
| 487 | |||
| 488 | incl PER_CPU_VAR(irq_count) | ||
| 489 | jnz .Lirq_stack_push_old_rsp_\@ | ||
| 490 | |||
| 491 | /* | ||
| 492 | * Right now, if we just incremented irq_count to zero, we've | ||
| 493 | * claimed the IRQ stack but we haven't switched to it yet. | ||
| 494 | * | ||
| 495 | * If anything is added that can interrupt us here without using IST, | ||
| 496 | * it must be *extremely* careful to limit its stack usage. This | ||
| 497 | * could include kprobes and a hypothetical future IST-less #DB | ||
| 498 | * handler. | ||
| 499 | * | ||
| 500 | * The OOPS unwinder relies on the word at the top of the IRQ | ||
| 501 | * stack linking back to the previous RSP for the entire time we're | ||
| 502 | * on the IRQ stack. For this to work reliably, we need to write | ||
| 503 | * it before we actually move ourselves to the IRQ stack. | ||
| 504 | */ | ||
| 505 | |||
| 506 | movq \old_rsp, PER_CPU_VAR(irq_stack_union + IRQ_STACK_SIZE - 8) | ||
| 507 | movq PER_CPU_VAR(irq_stack_ptr), %rsp | ||
| 508 | |||
| 509 | #ifdef CONFIG_DEBUG_ENTRY | ||
| 510 | /* | ||
| 511 | * If the first movq above becomes wrong due to IRQ stack layout | ||
| 512 | * changes, the only way we'll notice is if we try to unwind right | ||
| 513 | * here. Assert that we set up the stack right to catch this type | ||
| 514 | * of bug quickly. | ||
| 515 | */ | ||
| 516 | cmpq -8(%rsp), \old_rsp | ||
| 517 | je .Lirq_stack_okay\@ | ||
| 518 | ud2 | ||
| 519 | .Lirq_stack_okay\@: | ||
| 520 | #endif | ||
| 521 | |||
| 522 | .Lirq_stack_push_old_rsp_\@: | ||
| 523 | pushq \old_rsp | ||
| 524 | |||
| 525 | .if \regs | ||
| 526 | UNWIND_HINT_REGS indirect=1 | ||
| 527 | .endif | ||
| 528 | .endm | ||
| 529 | |||
| 530 | /* | ||
| 531 | * Undoes ENTER_IRQ_STACK. | ||
| 532 | */ | ||
| 533 | .macro LEAVE_IRQ_STACK regs=1 | ||
| 534 | DEBUG_ENTRY_ASSERT_IRQS_OFF | ||
| 535 | /* We need to be off the IRQ stack before decrementing irq_count. */ | ||
| 536 | popq %rsp | ||
| 537 | |||
| 538 | .if \regs | ||
| 539 | UNWIND_HINT_REGS | ||
| 540 | .endif | ||
| 541 | |||
| 542 | /* | ||
| 543 | * As in ENTER_IRQ_STACK, irq_count == 0, we are still claiming | ||
| 544 | * the irq stack but we're not on it. | ||
| 545 | */ | ||
| 546 | |||
| 547 | decl PER_CPU_VAR(irq_count) | ||
| 548 | .endm | ||
| 549 | |||
| 450 | /* | 550 | /* |
| 451 | * Interrupt entry/exit. | 551 | * Interrupt entry/exit. |
| 452 | * | 552 | * |
| @@ -485,17 +585,7 @@ END(irq_entries_start) | |||
| 485 | CALL_enter_from_user_mode | 585 | CALL_enter_from_user_mode |
| 486 | 586 | ||
| 487 | 1: | 587 | 1: |
| 488 | /* | 588 | ENTER_IRQ_STACK old_rsp=%rdi |
| 489 | * Save previous stack pointer, optionally switch to interrupt stack. | ||
| 490 | * irq_count is used to check if a CPU is already on an interrupt stack | ||
| 491 | * or not. While this is essentially redundant with preempt_count it is | ||
| 492 | * a little cheaper to use a separate counter in the PDA (short of | ||
| 493 | * moving irq_enter into assembly, which would be too much work) | ||
| 494 | */ | ||
| 495 | movq %rsp, %rdi | ||
| 496 | incl PER_CPU_VAR(irq_count) | ||
| 497 | cmovzq PER_CPU_VAR(irq_stack_ptr), %rsp | ||
| 498 | pushq %rdi | ||
| 499 | /* We entered an interrupt context - irqs are off: */ | 589 | /* We entered an interrupt context - irqs are off: */ |
| 500 | TRACE_IRQS_OFF | 590 | TRACE_IRQS_OFF |
| 501 | 591 | ||
| @@ -515,10 +605,8 @@ common_interrupt: | |||
| 515 | ret_from_intr: | 605 | ret_from_intr: |
| 516 | DISABLE_INTERRUPTS(CLBR_ANY) | 606 | DISABLE_INTERRUPTS(CLBR_ANY) |
| 517 | TRACE_IRQS_OFF | 607 | TRACE_IRQS_OFF |
| 518 | decl PER_CPU_VAR(irq_count) | ||
| 519 | 608 | ||
| 520 | /* Restore saved previous stack */ | 609 | LEAVE_IRQ_STACK |
| 521 | popq %rsp | ||
| 522 | 610 | ||
| 523 | testb $3, CS(%rsp) | 611 | testb $3, CS(%rsp) |
| 524 | jz retint_kernel | 612 | jz retint_kernel |
| @@ -561,6 +649,7 @@ restore_c_regs_and_iret: | |||
| 561 | INTERRUPT_RETURN | 649 | INTERRUPT_RETURN |
| 562 | 650 | ||
| 563 | ENTRY(native_iret) | 651 | ENTRY(native_iret) |
| 652 | UNWIND_HINT_IRET_REGS | ||
| 564 | /* | 653 | /* |
| 565 | * Are we returning to a stack segment from the LDT? Note: in | 654 | * Are we returning to a stack segment from the LDT? Note: in |
| 566 | * 64-bit mode SS:RSP on the exception stack is always valid. | 655 | * 64-bit mode SS:RSP on the exception stack is always valid. |
| @@ -633,6 +722,7 @@ native_irq_return_ldt: | |||
| 633 | orq PER_CPU_VAR(espfix_stack), %rax | 722 | orq PER_CPU_VAR(espfix_stack), %rax |
| 634 | SWAPGS | 723 | SWAPGS |
| 635 | movq %rax, %rsp | 724 | movq %rax, %rsp |
| 725 | UNWIND_HINT_IRET_REGS offset=8 | ||
| 636 | 726 | ||
| 637 | /* | 727 | /* |
| 638 | * At this point, we cannot write to the stack any more, but we can | 728 | * At this point, we cannot write to the stack any more, but we can |
| @@ -654,6 +744,7 @@ END(common_interrupt) | |||
| 654 | */ | 744 | */ |
| 655 | .macro apicinterrupt3 num sym do_sym | 745 | .macro apicinterrupt3 num sym do_sym |
| 656 | ENTRY(\sym) | 746 | ENTRY(\sym) |
| 747 | UNWIND_HINT_IRET_REGS | ||
| 657 | ASM_CLAC | 748 | ASM_CLAC |
| 658 | pushq $~(\num) | 749 | pushq $~(\num) |
| 659 | .Lcommon_\sym: | 750 | .Lcommon_\sym: |
| @@ -740,6 +831,8 @@ apicinterrupt IRQ_WORK_VECTOR irq_work_interrupt smp_irq_work_interrupt | |||
| 740 | 831 | ||
| 741 | .macro idtentry sym do_sym has_error_code:req paranoid=0 shift_ist=-1 | 832 | .macro idtentry sym do_sym has_error_code:req paranoid=0 shift_ist=-1 |
| 742 | ENTRY(\sym) | 833 | ENTRY(\sym) |
| 834 | UNWIND_HINT_IRET_REGS offset=8 | ||
| 835 | |||
| 743 | /* Sanity check */ | 836 | /* Sanity check */ |
| 744 | .if \shift_ist != -1 && \paranoid == 0 | 837 | .if \shift_ist != -1 && \paranoid == 0 |
| 745 | .error "using shift_ist requires paranoid=1" | 838 | .error "using shift_ist requires paranoid=1" |
| @@ -763,6 +856,7 @@ ENTRY(\sym) | |||
| 763 | .else | 856 | .else |
| 764 | call error_entry | 857 | call error_entry |
| 765 | .endif | 858 | .endif |
| 859 | UNWIND_HINT_REGS | ||
| 766 | /* returned flag: ebx=0: need swapgs on exit, ebx=1: don't need it */ | 860 | /* returned flag: ebx=0: need swapgs on exit, ebx=1: don't need it */ |
| 767 | 861 | ||
| 768 | .if \paranoid | 862 | .if \paranoid |
| @@ -860,6 +954,7 @@ idtentry simd_coprocessor_error do_simd_coprocessor_error has_error_code=0 | |||
| 860 | * edi: new selector | 954 | * edi: new selector |
| 861 | */ | 955 | */ |
| 862 | ENTRY(native_load_gs_index) | 956 | ENTRY(native_load_gs_index) |
| 957 | FRAME_BEGIN | ||
| 863 | pushfq | 958 | pushfq |
| 864 | DISABLE_INTERRUPTS(CLBR_ANY & ~CLBR_RDI) | 959 | DISABLE_INTERRUPTS(CLBR_ANY & ~CLBR_RDI) |
| 865 | SWAPGS | 960 | SWAPGS |
| @@ -868,8 +963,9 @@ ENTRY(native_load_gs_index) | |||
| 868 | 2: ALTERNATIVE "", "mfence", X86_BUG_SWAPGS_FENCE | 963 | 2: ALTERNATIVE "", "mfence", X86_BUG_SWAPGS_FENCE |
| 869 | SWAPGS | 964 | SWAPGS |
| 870 | popfq | 965 | popfq |
| 966 | FRAME_END | ||
| 871 | ret | 967 | ret |
| 872 | END(native_load_gs_index) | 968 | ENDPROC(native_load_gs_index) |
| 873 | EXPORT_SYMBOL(native_load_gs_index) | 969 | EXPORT_SYMBOL(native_load_gs_index) |
| 874 | 970 | ||
| 875 | _ASM_EXTABLE(.Lgs_change, bad_gs) | 971 | _ASM_EXTABLE(.Lgs_change, bad_gs) |
| @@ -892,14 +988,12 @@ bad_gs: | |||
| 892 | ENTRY(do_softirq_own_stack) | 988 | ENTRY(do_softirq_own_stack) |
| 893 | pushq %rbp | 989 | pushq %rbp |
| 894 | mov %rsp, %rbp | 990 | mov %rsp, %rbp |
| 895 | incl PER_CPU_VAR(irq_count) | 991 | ENTER_IRQ_STACK regs=0 old_rsp=%r11 |
| 896 | cmove PER_CPU_VAR(irq_stack_ptr), %rsp | ||
| 897 | push %rbp /* frame pointer backlink */ | ||
| 898 | call __do_softirq | 992 | call __do_softirq |
| 993 | LEAVE_IRQ_STACK regs=0 | ||
| 899 | leaveq | 994 | leaveq |
| 900 | decl PER_CPU_VAR(irq_count) | ||
| 901 | ret | 995 | ret |
| 902 | END(do_softirq_own_stack) | 996 | ENDPROC(do_softirq_own_stack) |
| 903 | 997 | ||
| 904 | #ifdef CONFIG_XEN | 998 | #ifdef CONFIG_XEN |
| 905 | idtentry xen_hypervisor_callback xen_do_hypervisor_callback has_error_code=0 | 999 | idtentry xen_hypervisor_callback xen_do_hypervisor_callback has_error_code=0 |
| @@ -923,14 +1017,14 @@ ENTRY(xen_do_hypervisor_callback) /* do_hypervisor_callback(struct *pt_regs) */ | |||
| 923 | * Since we don't modify %rdi, evtchn_do_upall(struct *pt_regs) will | 1017 | * Since we don't modify %rdi, evtchn_do_upall(struct *pt_regs) will |
| 924 | * see the correct pointer to the pt_regs | 1018 | * see the correct pointer to the pt_regs |
| 925 | */ | 1019 | */ |
| 1020 | UNWIND_HINT_FUNC | ||
| 926 | movq %rdi, %rsp /* we don't return, adjust the stack frame */ | 1021 | movq %rdi, %rsp /* we don't return, adjust the stack frame */ |
| 927 | 11: incl PER_CPU_VAR(irq_count) | 1022 | UNWIND_HINT_REGS |
| 928 | movq %rsp, %rbp | 1023 | |
| 929 | cmovzq PER_CPU_VAR(irq_stack_ptr), %rsp | 1024 | ENTER_IRQ_STACK old_rsp=%r10 |
| 930 | pushq %rbp /* frame pointer backlink */ | ||
| 931 | call xen_evtchn_do_upcall | 1025 | call xen_evtchn_do_upcall |
| 932 | popq %rsp | 1026 | LEAVE_IRQ_STACK |
| 933 | decl PER_CPU_VAR(irq_count) | 1027 | |
| 934 | #ifndef CONFIG_PREEMPT | 1028 | #ifndef CONFIG_PREEMPT |
| 935 | call xen_maybe_preempt_hcall | 1029 | call xen_maybe_preempt_hcall |
| 936 | #endif | 1030 | #endif |
| @@ -951,6 +1045,7 @@ END(xen_do_hypervisor_callback) | |||
| 951 | * with its current contents: any discrepancy means we in category 1. | 1045 | * with its current contents: any discrepancy means we in category 1. |
| 952 | */ | 1046 | */ |
| 953 | ENTRY(xen_failsafe_callback) | 1047 | ENTRY(xen_failsafe_callback) |
| 1048 | UNWIND_HINT_EMPTY | ||
| 954 | movl %ds, %ecx | 1049 | movl %ds, %ecx |
| 955 | cmpw %cx, 0x10(%rsp) | 1050 | cmpw %cx, 0x10(%rsp) |
| 956 | jne 1f | 1051 | jne 1f |
| @@ -970,11 +1065,13 @@ ENTRY(xen_failsafe_callback) | |||
| 970 | pushq $0 /* RIP */ | 1065 | pushq $0 /* RIP */ |
| 971 | pushq %r11 | 1066 | pushq %r11 |
| 972 | pushq %rcx | 1067 | pushq %rcx |
| 1068 | UNWIND_HINT_IRET_REGS offset=8 | ||
| 973 | jmp general_protection | 1069 | jmp general_protection |
| 974 | 1: /* Segment mismatch => Category 1 (Bad segment). Retry the IRET. */ | 1070 | 1: /* Segment mismatch => Category 1 (Bad segment). Retry the IRET. */ |
| 975 | movq (%rsp), %rcx | 1071 | movq (%rsp), %rcx |
| 976 | movq 8(%rsp), %r11 | 1072 | movq 8(%rsp), %r11 |
| 977 | addq $0x30, %rsp | 1073 | addq $0x30, %rsp |
| 1074 | UNWIND_HINT_IRET_REGS | ||
| 978 | pushq $-1 /* orig_ax = -1 => not a system call */ | 1075 | pushq $-1 /* orig_ax = -1 => not a system call */ |
| 979 | ALLOC_PT_GPREGS_ON_STACK | 1076 | ALLOC_PT_GPREGS_ON_STACK |
| 980 | SAVE_C_REGS | 1077 | SAVE_C_REGS |
| @@ -1020,6 +1117,7 @@ idtentry machine_check has_error_code=0 paranoid=1 do_sym=*machine_check_vec | |||
| 1020 | * Return: ebx=0: need swapgs on exit, ebx=1: otherwise | 1117 | * Return: ebx=0: need swapgs on exit, ebx=1: otherwise |
| 1021 | */ | 1118 | */ |
| 1022 | ENTRY(paranoid_entry) | 1119 | ENTRY(paranoid_entry) |
| 1120 | UNWIND_HINT_FUNC | ||
| 1023 | cld | 1121 | cld |
| 1024 | SAVE_C_REGS 8 | 1122 | SAVE_C_REGS 8 |
| 1025 | SAVE_EXTRA_REGS 8 | 1123 | SAVE_EXTRA_REGS 8 |
| @@ -1047,6 +1145,7 @@ END(paranoid_entry) | |||
| 1047 | * On entry, ebx is "no swapgs" flag (1: don't need swapgs, 0: need it) | 1145 | * On entry, ebx is "no swapgs" flag (1: don't need swapgs, 0: need it) |
| 1048 | */ | 1146 | */ |
| 1049 | ENTRY(paranoid_exit) | 1147 | ENTRY(paranoid_exit) |
| 1148 | UNWIND_HINT_REGS | ||
| 1050 | DISABLE_INTERRUPTS(CLBR_ANY) | 1149 | DISABLE_INTERRUPTS(CLBR_ANY) |
| 1051 | TRACE_IRQS_OFF_DEBUG | 1150 | TRACE_IRQS_OFF_DEBUG |
| 1052 | testl %ebx, %ebx /* swapgs needed? */ | 1151 | testl %ebx, %ebx /* swapgs needed? */ |
| @@ -1068,6 +1167,7 @@ END(paranoid_exit) | |||
| 1068 | * Return: EBX=0: came from user mode; EBX=1: otherwise | 1167 | * Return: EBX=0: came from user mode; EBX=1: otherwise |
| 1069 | */ | 1168 | */ |
| 1070 | ENTRY(error_entry) | 1169 | ENTRY(error_entry) |
| 1170 | UNWIND_HINT_FUNC | ||
| 1071 | cld | 1171 | cld |
| 1072 | SAVE_C_REGS 8 | 1172 | SAVE_C_REGS 8 |
| 1073 | SAVE_EXTRA_REGS 8 | 1173 | SAVE_EXTRA_REGS 8 |
| @@ -1152,6 +1252,7 @@ END(error_entry) | |||
| 1152 | * 0: user gsbase is loaded, we need SWAPGS and standard preparation for return to usermode | 1252 | * 0: user gsbase is loaded, we need SWAPGS and standard preparation for return to usermode |
| 1153 | */ | 1253 | */ |
| 1154 | ENTRY(error_exit) | 1254 | ENTRY(error_exit) |
| 1255 | UNWIND_HINT_REGS | ||
| 1155 | DISABLE_INTERRUPTS(CLBR_ANY) | 1256 | DISABLE_INTERRUPTS(CLBR_ANY) |
| 1156 | TRACE_IRQS_OFF | 1257 | TRACE_IRQS_OFF |
| 1157 | testl %ebx, %ebx | 1258 | testl %ebx, %ebx |
| @@ -1161,6 +1262,7 @@ END(error_exit) | |||
| 1161 | 1262 | ||
| 1162 | /* Runs on exception stack */ | 1263 | /* Runs on exception stack */ |
| 1163 | ENTRY(nmi) | 1264 | ENTRY(nmi) |
| 1265 | UNWIND_HINT_IRET_REGS | ||
| 1164 | /* | 1266 | /* |
| 1165 | * Fix up the exception frame if we're on Xen. | 1267 | * Fix up the exception frame if we're on Xen. |
| 1166 | * PARAVIRT_ADJUST_EXCEPTION_FRAME is guaranteed to push at most | 1268 | * PARAVIRT_ADJUST_EXCEPTION_FRAME is guaranteed to push at most |
| @@ -1232,11 +1334,13 @@ ENTRY(nmi) | |||
| 1232 | cld | 1334 | cld |
| 1233 | movq %rsp, %rdx | 1335 | movq %rsp, %rdx |
| 1234 | movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp | 1336 | movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp |
| 1337 | UNWIND_HINT_IRET_REGS base=%rdx offset=8 | ||
| 1235 | pushq 5*8(%rdx) /* pt_regs->ss */ | 1338 | pushq 5*8(%rdx) /* pt_regs->ss */ |
| 1236 | pushq 4*8(%rdx) /* pt_regs->rsp */ | 1339 | pushq 4*8(%rdx) /* pt_regs->rsp */ |
| 1237 | pushq 3*8(%rdx) /* pt_regs->flags */ | 1340 | pushq 3*8(%rdx) /* pt_regs->flags */ |
| 1238 | pushq 2*8(%rdx) /* pt_regs->cs */ | 1341 | pushq 2*8(%rdx) /* pt_regs->cs */ |
| 1239 | pushq 1*8(%rdx) /* pt_regs->rip */ | 1342 | pushq 1*8(%rdx) /* pt_regs->rip */ |
| 1343 | UNWIND_HINT_IRET_REGS | ||
| 1240 | pushq $-1 /* pt_regs->orig_ax */ | 1344 | pushq $-1 /* pt_regs->orig_ax */ |
| 1241 | pushq %rdi /* pt_regs->di */ | 1345 | pushq %rdi /* pt_regs->di */ |
| 1242 | pushq %rsi /* pt_regs->si */ | 1346 | pushq %rsi /* pt_regs->si */ |
| @@ -1253,6 +1357,7 @@ ENTRY(nmi) | |||
| 1253 | pushq %r13 /* pt_regs->r13 */ | 1357 | pushq %r13 /* pt_regs->r13 */ |
| 1254 | pushq %r14 /* pt_regs->r14 */ | 1358 | pushq %r14 /* pt_regs->r14 */ |
| 1255 | pushq %r15 /* pt_regs->r15 */ | 1359 | pushq %r15 /* pt_regs->r15 */ |
| 1360 | UNWIND_HINT_REGS | ||
| 1256 | ENCODE_FRAME_POINTER | 1361 | ENCODE_FRAME_POINTER |
| 1257 | 1362 | ||
| 1258 | /* | 1363 | /* |
| @@ -1407,6 +1512,7 @@ first_nmi: | |||
| 1407 | .rept 5 | 1512 | .rept 5 |
| 1408 | pushq 11*8(%rsp) | 1513 | pushq 11*8(%rsp) |
| 1409 | .endr | 1514 | .endr |
| 1515 | UNWIND_HINT_IRET_REGS | ||
| 1410 | 1516 | ||
| 1411 | /* Everything up to here is safe from nested NMIs */ | 1517 | /* Everything up to here is safe from nested NMIs */ |
| 1412 | 1518 | ||
| @@ -1422,6 +1528,7 @@ first_nmi: | |||
| 1422 | pushq $__KERNEL_CS /* CS */ | 1528 | pushq $__KERNEL_CS /* CS */ |
| 1423 | pushq $1f /* RIP */ | 1529 | pushq $1f /* RIP */ |
| 1424 | INTERRUPT_RETURN /* continues at repeat_nmi below */ | 1530 | INTERRUPT_RETURN /* continues at repeat_nmi below */ |
| 1531 | UNWIND_HINT_IRET_REGS | ||
| 1425 | 1: | 1532 | 1: |
| 1426 | #endif | 1533 | #endif |
| 1427 | 1534 | ||
| @@ -1471,6 +1578,7 @@ end_repeat_nmi: | |||
| 1471 | * exceptions might do. | 1578 | * exceptions might do. |
| 1472 | */ | 1579 | */ |
| 1473 | call paranoid_entry | 1580 | call paranoid_entry |
| 1581 | UNWIND_HINT_REGS | ||
| 1474 | 1582 | ||
| 1475 | /* paranoidentry do_nmi, 0; without TRACE_IRQS_OFF */ | 1583 | /* paranoidentry do_nmi, 0; without TRACE_IRQS_OFF */ |
| 1476 | movq %rsp, %rdi | 1584 | movq %rsp, %rdi |
| @@ -1508,17 +1616,19 @@ nmi_restore: | |||
| 1508 | END(nmi) | 1616 | END(nmi) |
| 1509 | 1617 | ||
| 1510 | ENTRY(ignore_sysret) | 1618 | ENTRY(ignore_sysret) |
| 1619 | UNWIND_HINT_EMPTY | ||
| 1511 | mov $-ENOSYS, %eax | 1620 | mov $-ENOSYS, %eax |
| 1512 | sysret | 1621 | sysret |
| 1513 | END(ignore_sysret) | 1622 | END(ignore_sysret) |
| 1514 | 1623 | ||
| 1515 | ENTRY(rewind_stack_do_exit) | 1624 | ENTRY(rewind_stack_do_exit) |
| 1625 | UNWIND_HINT_FUNC | ||
| 1516 | /* Prevent any naive code from trying to unwind to our caller. */ | 1626 | /* Prevent any naive code from trying to unwind to our caller. */ |
| 1517 | xorl %ebp, %ebp | 1627 | xorl %ebp, %ebp |
| 1518 | 1628 | ||
| 1519 | movq PER_CPU_VAR(cpu_current_top_of_stack), %rax | 1629 | movq PER_CPU_VAR(cpu_current_top_of_stack), %rax |
| 1520 | leaq -TOP_OF_KERNEL_STACK_PADDING-PTREGS_SIZE(%rax), %rsp | 1630 | leaq -PTREGS_SIZE(%rax), %rsp |
| 1631 | UNWIND_HINT_FUNC sp_offset=PTREGS_SIZE | ||
| 1521 | 1632 | ||
| 1522 | call do_exit | 1633 | call do_exit |
| 1523 | 1: jmp 1b | ||
| 1524 | END(rewind_stack_do_exit) | 1634 | END(rewind_stack_do_exit) |
diff --git a/arch/x86/include/asm/io.h b/arch/x86/include/asm/io.h index 48febf07e828..1310e1f1cd65 100644 --- a/arch/x86/include/asm/io.h +++ b/arch/x86/include/asm/io.h | |||
| @@ -69,6 +69,9 @@ build_mmio_write(__writeb, "b", unsigned char, "q", ) | |||
| 69 | build_mmio_write(__writew, "w", unsigned short, "r", ) | 69 | build_mmio_write(__writew, "w", unsigned short, "r", ) |
| 70 | build_mmio_write(__writel, "l", unsigned int, "r", ) | 70 | build_mmio_write(__writel, "l", unsigned int, "r", ) |
| 71 | 71 | ||
| 72 | #define readb readb | ||
| 73 | #define readw readw | ||
| 74 | #define readl readl | ||
| 72 | #define readb_relaxed(a) __readb(a) | 75 | #define readb_relaxed(a) __readb(a) |
| 73 | #define readw_relaxed(a) __readw(a) | 76 | #define readw_relaxed(a) __readw(a) |
| 74 | #define readl_relaxed(a) __readl(a) | 77 | #define readl_relaxed(a) __readl(a) |
| @@ -76,6 +79,9 @@ build_mmio_write(__writel, "l", unsigned int, "r", ) | |||
| 76 | #define __raw_readw __readw | 79 | #define __raw_readw __readw |
| 77 | #define __raw_readl __readl | 80 | #define __raw_readl __readl |
| 78 | 81 | ||
| 82 | #define writeb writeb | ||
| 83 | #define writew writew | ||
| 84 | #define writel writel | ||
| 79 | #define writeb_relaxed(v, a) __writeb(v, a) | 85 | #define writeb_relaxed(v, a) __writeb(v, a) |
| 80 | #define writew_relaxed(v, a) __writew(v, a) | 86 | #define writew_relaxed(v, a) __writew(v, a) |
| 81 | #define writel_relaxed(v, a) __writel(v, a) | 87 | #define writel_relaxed(v, a) __writel(v, a) |
| @@ -88,13 +94,15 @@ build_mmio_write(__writel, "l", unsigned int, "r", ) | |||
| 88 | #ifdef CONFIG_X86_64 | 94 | #ifdef CONFIG_X86_64 |
| 89 | 95 | ||
| 90 | build_mmio_read(readq, "q", unsigned long, "=r", :"memory") | 96 | build_mmio_read(readq, "q", unsigned long, "=r", :"memory") |
| 97 | build_mmio_read(__readq, "q", unsigned long, "=r", ) | ||
| 91 | build_mmio_write(writeq, "q", unsigned long, "r", :"memory") | 98 | build_mmio_write(writeq, "q", unsigned long, "r", :"memory") |
| 99 | build_mmio_write(__writeq, "q", unsigned long, "r", ) | ||
| 92 | 100 | ||
| 93 | #define readq_relaxed(a) readq(a) | 101 | #define readq_relaxed(a) __readq(a) |
| 94 | #define writeq_relaxed(v, a) writeq(v, a) | 102 | #define writeq_relaxed(v, a) __writeq(v, a) |
| 95 | 103 | ||
| 96 | #define __raw_readq(a) readq(a) | 104 | #define __raw_readq __readq |
| 97 | #define __raw_writeq(val, addr) writeq(val, addr) | 105 | #define __raw_writeq __writeq |
| 98 | 106 | ||
| 99 | /* Let people know that we have them */ | 107 | /* Let people know that we have them */ |
| 100 | #define readq readq | 108 | #define readq readq |
| @@ -119,6 +127,7 @@ static inline phys_addr_t virt_to_phys(volatile void *address) | |||
| 119 | { | 127 | { |
| 120 | return __pa(address); | 128 | return __pa(address); |
| 121 | } | 129 | } |
| 130 | #define virt_to_phys virt_to_phys | ||
| 122 | 131 | ||
| 123 | /** | 132 | /** |
| 124 | * phys_to_virt - map physical address to virtual | 133 | * phys_to_virt - map physical address to virtual |
| @@ -137,6 +146,7 @@ static inline void *phys_to_virt(phys_addr_t address) | |||
| 137 | { | 146 | { |
| 138 | return __va(address); | 147 | return __va(address); |
| 139 | } | 148 | } |
| 149 | #define phys_to_virt phys_to_virt | ||
| 140 | 150 | ||
| 141 | /* | 151 | /* |
| 142 | * Change "struct page" to physical address. | 152 | * Change "struct page" to physical address. |
| @@ -169,11 +179,14 @@ static inline unsigned int isa_virt_to_bus(volatile void *address) | |||
| 169 | * else, you probably want one of the following. | 179 | * else, you probably want one of the following. |
| 170 | */ | 180 | */ |
| 171 | extern void __iomem *ioremap_nocache(resource_size_t offset, unsigned long size); | 181 | extern void __iomem *ioremap_nocache(resource_size_t offset, unsigned long size); |
| 182 | #define ioremap_nocache ioremap_nocache | ||
| 172 | extern void __iomem *ioremap_uc(resource_size_t offset, unsigned long size); | 183 | extern void __iomem *ioremap_uc(resource_size_t offset, unsigned long size); |
| 173 | #define ioremap_uc ioremap_uc | 184 | #define ioremap_uc ioremap_uc |
| 174 | 185 | ||
| 175 | extern void __iomem *ioremap_cache(resource_size_t offset, unsigned long size); | 186 | extern void __iomem *ioremap_cache(resource_size_t offset, unsigned long size); |
| 187 | #define ioremap_cache ioremap_cache | ||
| 176 | extern void __iomem *ioremap_prot(resource_size_t offset, unsigned long size, unsigned long prot_val); | 188 | extern void __iomem *ioremap_prot(resource_size_t offset, unsigned long size, unsigned long prot_val); |
| 189 | #define ioremap_prot ioremap_prot | ||
| 177 | 190 | ||
| 178 | /** | 191 | /** |
| 179 | * ioremap - map bus memory into CPU space | 192 | * ioremap - map bus memory into CPU space |
| @@ -193,8 +206,10 @@ static inline void __iomem *ioremap(resource_size_t offset, unsigned long size) | |||
| 193 | { | 206 | { |
| 194 | return ioremap_nocache(offset, size); | 207 | return ioremap_nocache(offset, size); |
| 195 | } | 208 | } |
| 209 | #define ioremap ioremap | ||
| 196 | 210 | ||
| 197 | extern void iounmap(volatile void __iomem *addr); | 211 | extern void iounmap(volatile void __iomem *addr); |
| 212 | #define iounmap iounmap | ||
| 198 | 213 | ||
| 199 | extern void set_iounmap_nonlazy(void); | 214 | extern void set_iounmap_nonlazy(void); |
| 200 | 215 | ||
| @@ -203,53 +218,6 @@ extern void set_iounmap_nonlazy(void); | |||
| 203 | #include <asm-generic/iomap.h> | 218 | #include <asm-generic/iomap.h> |
| 204 | 219 | ||
| 205 | /* | 220 | /* |
| 206 | * Convert a virtual cached pointer to an uncached pointer | ||
| 207 | */ | ||
| 208 | #define xlate_dev_kmem_ptr(p) p | ||
| 209 | |||
| 210 | /** | ||
| 211 | * memset_io Set a range of I/O memory to a constant value | ||
| 212 | * @addr: The beginning of the I/O-memory range to set | ||
| 213 | * @val: The value to set the memory to | ||
| 214 | * @count: The number of bytes to set | ||
| 215 | * | ||
| 216 | * Set a range of I/O memory to a given value. | ||
| 217 | */ | ||
| 218 | static inline void | ||
| 219 | memset_io(volatile void __iomem *addr, unsigned char val, size_t count) | ||
| 220 | { | ||
| 221 | memset((void __force *)addr, val, count); | ||
| 222 | } | ||
| 223 | |||
| 224 | /** | ||
| 225 | * memcpy_fromio Copy a block of data from I/O memory | ||
| 226 | * @dst: The (RAM) destination for the copy | ||
| 227 | * @src: The (I/O memory) source for the data | ||
| 228 | * @count: The number of bytes to copy | ||
| 229 | * | ||
| 230 | * Copy a block of data from I/O memory. | ||
| 231 | */ | ||
| 232 | static inline void | ||
| 233 | memcpy_fromio(void *dst, const volatile void __iomem *src, size_t count) | ||
| 234 | { | ||
| 235 | memcpy(dst, (const void __force *)src, count); | ||
| 236 | } | ||
| 237 | |||
| 238 | /** | ||
| 239 | * memcpy_toio Copy a block of data into I/O memory | ||
| 240 | * @dst: The (I/O memory) destination for the copy | ||
| 241 | * @src: The (RAM) source for the data | ||
| 242 | * @count: The number of bytes to copy | ||
| 243 | * | ||
| 244 | * Copy a block of data to I/O memory. | ||
| 245 | */ | ||
| 246 | static inline void | ||
| 247 | memcpy_toio(volatile void __iomem *dst, const void *src, size_t count) | ||
| 248 | { | ||
| 249 | memcpy((void __force *)dst, src, count); | ||
| 250 | } | ||
| 251 | |||
| 252 | /* | ||
| 253 | * ISA space is 'always mapped' on a typical x86 system, no need to | 221 | * ISA space is 'always mapped' on a typical x86 system, no need to |
| 254 | * explicitly ioremap() it. The fact that the ISA IO space is mapped | 222 | * explicitly ioremap() it. The fact that the ISA IO space is mapped |
| 255 | * to PAGE_OFFSET is pure coincidence - it does not mean ISA values | 223 | * to PAGE_OFFSET is pure coincidence - it does not mean ISA values |
| @@ -341,13 +309,38 @@ BUILDIO(b, b, char) | |||
| 341 | BUILDIO(w, w, short) | 309 | BUILDIO(w, w, short) |
| 342 | BUILDIO(l, , int) | 310 | BUILDIO(l, , int) |
| 343 | 311 | ||
| 312 | #define inb inb | ||
| 313 | #define inw inw | ||
| 314 | #define inl inl | ||
| 315 | #define inb_p inb_p | ||
| 316 | #define inw_p inw_p | ||
| 317 | #define inl_p inl_p | ||
| 318 | #define insb insb | ||
| 319 | #define insw insw | ||
| 320 | #define insl insl | ||
| 321 | |||
| 322 | #define outb outb | ||
| 323 | #define outw outw | ||
| 324 | #define outl outl | ||
| 325 | #define outb_p outb_p | ||
| 326 | #define outw_p outw_p | ||
| 327 | #define outl_p outl_p | ||
| 328 | #define outsb outsb | ||
| 329 | #define outsw outsw | ||
| 330 | #define outsl outsl | ||
| 331 | |||
| 344 | extern void *xlate_dev_mem_ptr(phys_addr_t phys); | 332 | extern void *xlate_dev_mem_ptr(phys_addr_t phys); |
| 345 | extern void unxlate_dev_mem_ptr(phys_addr_t phys, void *addr); | 333 | extern void unxlate_dev_mem_ptr(phys_addr_t phys, void *addr); |
| 346 | 334 | ||
| 335 | #define xlate_dev_mem_ptr xlate_dev_mem_ptr | ||
| 336 | #define unxlate_dev_mem_ptr unxlate_dev_mem_ptr | ||
| 337 | |||
| 347 | extern int ioremap_change_attr(unsigned long vaddr, unsigned long size, | 338 | extern int ioremap_change_attr(unsigned long vaddr, unsigned long size, |
| 348 | enum page_cache_mode pcm); | 339 | enum page_cache_mode pcm); |
| 349 | extern void __iomem *ioremap_wc(resource_size_t offset, unsigned long size); | 340 | extern void __iomem *ioremap_wc(resource_size_t offset, unsigned long size); |
| 341 | #define ioremap_wc ioremap_wc | ||
| 350 | extern void __iomem *ioremap_wt(resource_size_t offset, unsigned long size); | 342 | extern void __iomem *ioremap_wt(resource_size_t offset, unsigned long size); |
| 343 | #define ioremap_wt ioremap_wt | ||
| 351 | 344 | ||
| 352 | extern bool is_early_ioremap_ptep(pte_t *ptep); | 345 | extern bool is_early_ioremap_ptep(pte_t *ptep); |
| 353 | 346 | ||
| @@ -365,6 +358,9 @@ extern bool xen_biovec_phys_mergeable(const struct bio_vec *vec1, | |||
| 365 | 358 | ||
| 366 | #define IO_SPACE_LIMIT 0xffff | 359 | #define IO_SPACE_LIMIT 0xffff |
| 367 | 360 | ||
| 361 | #include <asm-generic/io.h> | ||
| 362 | #undef PCI_IOBASE | ||
| 363 | |||
| 368 | #ifdef CONFIG_MTRR | 364 | #ifdef CONFIG_MTRR |
| 369 | extern int __must_check arch_phys_wc_index(int handle); | 365 | extern int __must_check arch_phys_wc_index(int handle); |
| 370 | #define arch_phys_wc_index arch_phys_wc_index | 366 | #define arch_phys_wc_index arch_phys_wc_index |
diff --git a/arch/x86/include/asm/orc_types.h b/arch/x86/include/asm/orc_types.h new file mode 100644 index 000000000000..7dc777a6cb40 --- /dev/null +++ b/arch/x86/include/asm/orc_types.h | |||
| @@ -0,0 +1,107 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com> | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU General Public License | ||
| 6 | * as published by the Free Software Foundation; either version 2 | ||
| 7 | * of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #ifndef _ORC_TYPES_H | ||
| 19 | #define _ORC_TYPES_H | ||
| 20 | |||
| 21 | #include <linux/types.h> | ||
| 22 | #include <linux/compiler.h> | ||
| 23 | |||
| 24 | /* | ||
| 25 | * The ORC_REG_* registers are base registers which are used to find other | ||
| 26 | * registers on the stack. | ||
| 27 | * | ||
| 28 | * ORC_REG_PREV_SP, also known as DWARF Call Frame Address (CFA), is the | ||
| 29 | * address of the previous frame: the caller's SP before it called the current | ||
| 30 | * function. | ||
| 31 | * | ||
| 32 | * ORC_REG_UNDEFINED means the corresponding register's value didn't change in | ||
| 33 | * the current frame. | ||
| 34 | * | ||
| 35 | * The most commonly used base registers are SP and BP -- which the previous SP | ||
| 36 | * is usually based on -- and PREV_SP and UNDEFINED -- which the previous BP is | ||
| 37 | * usually based on. | ||
| 38 | * | ||
| 39 | * The rest of the base registers are needed for special cases like entry code | ||
| 40 | * and GCC realigned stacks. | ||
| 41 | */ | ||
| 42 | #define ORC_REG_UNDEFINED 0 | ||
| 43 | #define ORC_REG_PREV_SP 1 | ||
| 44 | #define ORC_REG_DX 2 | ||
| 45 | #define ORC_REG_DI 3 | ||
| 46 | #define ORC_REG_BP 4 | ||
| 47 | #define ORC_REG_SP 5 | ||
| 48 | #define ORC_REG_R10 6 | ||
| 49 | #define ORC_REG_R13 7 | ||
| 50 | #define ORC_REG_BP_INDIRECT 8 | ||
| 51 | #define ORC_REG_SP_INDIRECT 9 | ||
| 52 | #define ORC_REG_MAX 15 | ||
| 53 | |||
| 54 | /* | ||
| 55 | * ORC_TYPE_CALL: Indicates that sp_reg+sp_offset resolves to PREV_SP (the | ||
| 56 | * caller's SP right before it made the call). Used for all callable | ||
| 57 | * functions, i.e. all C code and all callable asm functions. | ||
| 58 | * | ||
| 59 | * ORC_TYPE_REGS: Used in entry code to indicate that sp_reg+sp_offset points | ||
| 60 | * to a fully populated pt_regs from a syscall, interrupt, or exception. | ||
| 61 | * | ||
| 62 | * ORC_TYPE_REGS_IRET: Used in entry code to indicate that sp_reg+sp_offset | ||
| 63 | * points to the iret return frame. | ||
| 64 | * | ||
| 65 | * The UNWIND_HINT macros are used only for the unwind_hint struct. They | ||
| 66 | * aren't used in struct orc_entry due to size and complexity constraints. | ||
| 67 | * Objtool converts them to real types when it converts the hints to orc | ||
| 68 | * entries. | ||
| 69 | */ | ||
| 70 | #define ORC_TYPE_CALL 0 | ||
| 71 | #define ORC_TYPE_REGS 1 | ||
| 72 | #define ORC_TYPE_REGS_IRET 2 | ||
| 73 | #define UNWIND_HINT_TYPE_SAVE 3 | ||
| 74 | #define UNWIND_HINT_TYPE_RESTORE 4 | ||
| 75 | |||
| 76 | #ifndef __ASSEMBLY__ | ||
| 77 | /* | ||
| 78 | * This struct is more or less a vastly simplified version of the DWARF Call | ||
| 79 | * Frame Information standard. It contains only the necessary parts of DWARF | ||
| 80 | * CFI, simplified for ease of access by the in-kernel unwinder. It tells the | ||
| 81 | * unwinder how to find the previous SP and BP (and sometimes entry regs) on | ||
| 82 | * the stack for a given code address. Each instance of the struct corresponds | ||
| 83 | * to one or more code locations. | ||
| 84 | */ | ||
| 85 | struct orc_entry { | ||
| 86 | s16 sp_offset; | ||
| 87 | s16 bp_offset; | ||
| 88 | unsigned sp_reg:4; | ||
| 89 | unsigned bp_reg:4; | ||
| 90 | unsigned type:2; | ||
| 91 | }; | ||
| 92 | |||
| 93 | /* | ||
| 94 | * This struct is used by asm and inline asm code to manually annotate the | ||
| 95 | * location of registers on the stack for the ORC unwinder. | ||
| 96 | * | ||
| 97 | * Type can be either ORC_TYPE_* or UNWIND_HINT_TYPE_*. | ||
| 98 | */ | ||
| 99 | struct unwind_hint { | ||
| 100 | u32 ip; | ||
| 101 | s16 sp_offset; | ||
| 102 | u8 sp_reg; | ||
| 103 | u8 type; | ||
| 104 | }; | ||
| 105 | #endif /* __ASSEMBLY__ */ | ||
| 106 | |||
| 107 | #endif /* _ORC_TYPES_H */ | ||
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 028245e1c42b..0b03d655db7c 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h | |||
| @@ -22,6 +22,7 @@ struct vm86; | |||
| 22 | #include <asm/nops.h> | 22 | #include <asm/nops.h> |
| 23 | #include <asm/special_insns.h> | 23 | #include <asm/special_insns.h> |
| 24 | #include <asm/fpu/types.h> | 24 | #include <asm/fpu/types.h> |
| 25 | #include <asm/unwind_hints.h> | ||
| 25 | 26 | ||
| 26 | #include <linux/personality.h> | 27 | #include <linux/personality.h> |
| 27 | #include <linux/cache.h> | 28 | #include <linux/cache.h> |
| @@ -684,6 +685,7 @@ static inline void sync_core(void) | |||
| 684 | unsigned int tmp; | 685 | unsigned int tmp; |
| 685 | 686 | ||
| 686 | asm volatile ( | 687 | asm volatile ( |
| 688 | UNWIND_HINT_SAVE | ||
| 687 | "mov %%ss, %0\n\t" | 689 | "mov %%ss, %0\n\t" |
| 688 | "pushq %q0\n\t" | 690 | "pushq %q0\n\t" |
| 689 | "pushq %%rsp\n\t" | 691 | "pushq %%rsp\n\t" |
| @@ -693,6 +695,7 @@ static inline void sync_core(void) | |||
| 693 | "pushq %q0\n\t" | 695 | "pushq %q0\n\t" |
| 694 | "pushq $1f\n\t" | 696 | "pushq $1f\n\t" |
| 695 | "iretq\n\t" | 697 | "iretq\n\t" |
| 698 | UNWIND_HINT_RESTORE | ||
| 696 | "1:" | 699 | "1:" |
| 697 | : "=&r" (tmp), "+r" (__sp) : : "cc", "memory"); | 700 | : "=&r" (tmp), "+r" (__sp) : : "cc", "memory"); |
| 698 | #endif | 701 | #endif |
diff --git a/arch/x86/include/asm/rmwcc.h b/arch/x86/include/asm/rmwcc.h index 661dd305694a..045f99211a99 100644 --- a/arch/x86/include/asm/rmwcc.h +++ b/arch/x86/include/asm/rmwcc.h | |||
| @@ -1,45 +1,56 @@ | |||
| 1 | #ifndef _ASM_X86_RMWcc | 1 | #ifndef _ASM_X86_RMWcc |
| 2 | #define _ASM_X86_RMWcc | 2 | #define _ASM_X86_RMWcc |
| 3 | 3 | ||
| 4 | #define __CLOBBERS_MEM "memory" | ||
| 5 | #define __CLOBBERS_MEM_CC_CX "memory", "cc", "cx" | ||
| 6 | |||
| 4 | #if !defined(__GCC_ASM_FLAG_OUTPUTS__) && defined(CC_HAVE_ASM_GOTO) | 7 | #if !defined(__GCC_ASM_FLAG_OUTPUTS__) && defined(CC_HAVE_ASM_GOTO) |
| 5 | 8 | ||
| 6 | /* Use asm goto */ | 9 | /* Use asm goto */ |
| 7 | 10 | ||
| 8 | #define __GEN_RMWcc(fullop, var, cc, ...) \ | 11 | #define __GEN_RMWcc(fullop, var, cc, clobbers, ...) \ |
| 9 | do { \ | 12 | do { \ |
| 10 | asm_volatile_goto (fullop "; j" #cc " %l[cc_label]" \ | 13 | asm_volatile_goto (fullop "; j" #cc " %l[cc_label]" \ |
| 11 | : : "m" (var), ## __VA_ARGS__ \ | 14 | : : [counter] "m" (var), ## __VA_ARGS__ \ |
| 12 | : "memory" : cc_label); \ | 15 | : clobbers : cc_label); \ |
| 13 | return 0; \ | 16 | return 0; \ |
| 14 | cc_label: \ | 17 | cc_label: \ |
| 15 | return 1; \ | 18 | return 1; \ |
| 16 | } while (0) | 19 | } while (0) |
| 17 | 20 | ||
| 18 | #define GEN_UNARY_RMWcc(op, var, arg0, cc) \ | 21 | #define __BINARY_RMWcc_ARG " %1, " |
| 19 | __GEN_RMWcc(op " " arg0, var, cc) | ||
| 20 | 22 | ||
| 21 | #define GEN_BINARY_RMWcc(op, var, vcon, val, arg0, cc) \ | ||
| 22 | __GEN_RMWcc(op " %1, " arg0, var, cc, vcon (val)) | ||
| 23 | 23 | ||
| 24 | #else /* defined(__GCC_ASM_FLAG_OUTPUTS__) || !defined(CC_HAVE_ASM_GOTO) */ | 24 | #else /* defined(__GCC_ASM_FLAG_OUTPUTS__) || !defined(CC_HAVE_ASM_GOTO) */ |
| 25 | 25 | ||
| 26 | /* Use flags output or a set instruction */ | 26 | /* Use flags output or a set instruction */ |
| 27 | 27 | ||
| 28 | #define __GEN_RMWcc(fullop, var, cc, ...) \ | 28 | #define __GEN_RMWcc(fullop, var, cc, clobbers, ...) \ |
| 29 | do { \ | 29 | do { \ |
| 30 | bool c; \ | 30 | bool c; \ |
| 31 | asm volatile (fullop ";" CC_SET(cc) \ | 31 | asm volatile (fullop ";" CC_SET(cc) \ |
| 32 | : "+m" (var), CC_OUT(cc) (c) \ | 32 | : [counter] "+m" (var), CC_OUT(cc) (c) \ |
| 33 | : __VA_ARGS__ : "memory"); \ | 33 | : __VA_ARGS__ : clobbers); \ |
| 34 | return c; \ | 34 | return c; \ |
| 35 | } while (0) | 35 | } while (0) |
| 36 | 36 | ||
| 37 | #define __BINARY_RMWcc_ARG " %2, " | ||
| 38 | |||
| 39 | #endif /* defined(__GCC_ASM_FLAG_OUTPUTS__) || !defined(CC_HAVE_ASM_GOTO) */ | ||
| 40 | |||
| 37 | #define GEN_UNARY_RMWcc(op, var, arg0, cc) \ | 41 | #define GEN_UNARY_RMWcc(op, var, arg0, cc) \ |
| 38 | __GEN_RMWcc(op " " arg0, var, cc) | 42 | __GEN_RMWcc(op " " arg0, var, cc, __CLOBBERS_MEM) |
| 43 | |||
| 44 | #define GEN_UNARY_SUFFIXED_RMWcc(op, suffix, var, arg0, cc) \ | ||
| 45 | __GEN_RMWcc(op " " arg0 "\n\t" suffix, var, cc, \ | ||
| 46 | __CLOBBERS_MEM_CC_CX) | ||
| 39 | 47 | ||
| 40 | #define GEN_BINARY_RMWcc(op, var, vcon, val, arg0, cc) \ | 48 | #define GEN_BINARY_RMWcc(op, var, vcon, val, arg0, cc) \ |
| 41 | __GEN_RMWcc(op " %2, " arg0, var, cc, vcon (val)) | 49 | __GEN_RMWcc(op __BINARY_RMWcc_ARG arg0, var, cc, \ |
| 50 | __CLOBBERS_MEM, vcon (val)) | ||
| 42 | 51 | ||
| 43 | #endif /* defined(__GCC_ASM_FLAG_OUTPUTS__) || !defined(CC_HAVE_ASM_GOTO) */ | 52 | #define GEN_BINARY_SUFFIXED_RMWcc(op, suffix, var, vcon, val, arg0, cc) \ |
| 53 | __GEN_RMWcc(op __BINARY_RMWcc_ARG arg0 "\n\t" suffix, var, cc, \ | ||
| 54 | __CLOBBERS_MEM_CC_CX, vcon (val)) | ||
| 44 | 55 | ||
| 45 | #endif /* _ASM_X86_RMWcc */ | 56 | #endif /* _ASM_X86_RMWcc */ |
diff --git a/arch/x86/include/asm/unwind_hints.h b/arch/x86/include/asm/unwind_hints.h new file mode 100644 index 000000000000..5e02b11c9b86 --- /dev/null +++ b/arch/x86/include/asm/unwind_hints.h | |||
| @@ -0,0 +1,103 @@ | |||
| 1 | #ifndef _ASM_X86_UNWIND_HINTS_H | ||
| 2 | #define _ASM_X86_UNWIND_HINTS_H | ||
| 3 | |||
| 4 | #include "orc_types.h" | ||
| 5 | |||
| 6 | #ifdef __ASSEMBLY__ | ||
| 7 | |||
| 8 | /* | ||
| 9 | * In asm, there are two kinds of code: normal C-type callable functions and | ||
| 10 | * the rest. The normal callable functions can be called by other code, and | ||
| 11 | * don't do anything unusual with the stack. Such normal callable functions | ||
| 12 | * are annotated with the ENTRY/ENDPROC macros. Most asm code falls in this | ||
| 13 | * category. In this case, no special debugging annotations are needed because | ||
| 14 | * objtool can automatically generate the ORC data for the ORC unwinder to read | ||
| 15 | * at runtime. | ||
| 16 | * | ||
| 17 | * Anything which doesn't fall into the above category, such as syscall and | ||
| 18 | * interrupt handlers, tends to not be called directly by other functions, and | ||
| 19 | * often does unusual non-C-function-type things with the stack pointer. Such | ||
| 20 | * code needs to be annotated such that objtool can understand it. The | ||
| 21 | * following CFI hint macros are for this type of code. | ||
| 22 | * | ||
| 23 | * These macros provide hints to objtool about the state of the stack at each | ||
| 24 | * instruction. Objtool starts from the hints and follows the code flow, | ||
| 25 | * making automatic CFI adjustments when it sees pushes and pops, filling out | ||
| 26 | * the debuginfo as necessary. It will also warn if it sees any | ||
| 27 | * inconsistencies. | ||
| 28 | */ | ||
| 29 | .macro UNWIND_HINT sp_reg=ORC_REG_SP sp_offset=0 type=ORC_TYPE_CALL | ||
| 30 | #ifdef CONFIG_STACK_VALIDATION | ||
| 31 | .Lunwind_hint_ip_\@: | ||
| 32 | .pushsection .discard.unwind_hints | ||
| 33 | /* struct unwind_hint */ | ||
| 34 | .long .Lunwind_hint_ip_\@ - . | ||
| 35 | .short \sp_offset | ||
| 36 | .byte \sp_reg | ||
| 37 | .byte \type | ||
| 38 | .popsection | ||
| 39 | #endif | ||
| 40 | .endm | ||
| 41 | |||
| 42 | .macro UNWIND_HINT_EMPTY | ||
| 43 | UNWIND_HINT sp_reg=ORC_REG_UNDEFINED | ||
| 44 | .endm | ||
| 45 | |||
| 46 | .macro UNWIND_HINT_REGS base=%rsp offset=0 indirect=0 extra=1 iret=0 | ||
| 47 | .if \base == %rsp && \indirect | ||
| 48 | .set sp_reg, ORC_REG_SP_INDIRECT | ||
| 49 | .elseif \base == %rsp | ||
| 50 | .set sp_reg, ORC_REG_SP | ||
| 51 | .elseif \base == %rbp | ||
| 52 | .set sp_reg, ORC_REG_BP | ||
| 53 | .elseif \base == %rdi | ||
| 54 | .set sp_reg, ORC_REG_DI | ||
| 55 | .elseif \base == %rdx | ||
| 56 | .set sp_reg, ORC_REG_DX | ||
| 57 | .elseif \base == %r10 | ||
| 58 | .set sp_reg, ORC_REG_R10 | ||
| 59 | .else | ||
| 60 | .error "UNWIND_HINT_REGS: bad base register" | ||
| 61 | .endif | ||
| 62 | |||
| 63 | .set sp_offset, \offset | ||
| 64 | |||
| 65 | .if \iret | ||
| 66 | .set type, ORC_TYPE_REGS_IRET | ||
| 67 | .elseif \extra == 0 | ||
| 68 | .set type, ORC_TYPE_REGS_IRET | ||
| 69 | .set sp_offset, \offset + (16*8) | ||
| 70 | .else | ||
| 71 | .set type, ORC_TYPE_REGS | ||
| 72 | .endif | ||
| 73 | |||
| 74 | UNWIND_HINT sp_reg=sp_reg sp_offset=sp_offset type=type | ||
| 75 | .endm | ||
| 76 | |||
| 77 | .macro UNWIND_HINT_IRET_REGS base=%rsp offset=0 | ||
| 78 | UNWIND_HINT_REGS base=\base offset=\offset iret=1 | ||
| 79 | .endm | ||
| 80 | |||
| 81 | .macro UNWIND_HINT_FUNC sp_offset=8 | ||
| 82 | UNWIND_HINT sp_offset=\sp_offset | ||
| 83 | .endm | ||
| 84 | |||
| 85 | #else /* !__ASSEMBLY__ */ | ||
| 86 | |||
| 87 | #define UNWIND_HINT(sp_reg, sp_offset, type) \ | ||
| 88 | "987: \n\t" \ | ||
| 89 | ".pushsection .discard.unwind_hints\n\t" \ | ||
| 90 | /* struct unwind_hint */ \ | ||
| 91 | ".long 987b - .\n\t" \ | ||
| 92 | ".short " __stringify(sp_offset) "\n\t" \ | ||
| 93 | ".byte " __stringify(sp_reg) "\n\t" \ | ||
| 94 | ".byte " __stringify(type) "\n\t" \ | ||
| 95 | ".popsection\n\t" | ||
| 96 | |||
| 97 | #define UNWIND_HINT_SAVE UNWIND_HINT(0, 0, UNWIND_HINT_TYPE_SAVE) | ||
| 98 | |||
| 99 | #define UNWIND_HINT_RESTORE UNWIND_HINT(0, 0, UNWIND_HINT_TYPE_RESTORE) | ||
| 100 | |||
| 101 | #endif /* __ASSEMBLY__ */ | ||
| 102 | |||
| 103 | #endif /* _ASM_X86_UNWIND_HINTS_H */ | ||
diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c index dbce3cca94cb..bd265a4cf108 100644 --- a/arch/x86/kernel/dumpstack.c +++ b/arch/x86/kernel/dumpstack.c | |||
| @@ -94,6 +94,9 @@ void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, | |||
| 94 | if (stack_name) | 94 | if (stack_name) |
| 95 | printk("%s <%s>\n", log_lvl, stack_name); | 95 | printk("%s <%s>\n", log_lvl, stack_name); |
| 96 | 96 | ||
| 97 | if (regs && on_stack(&stack_info, regs, sizeof(*regs))) | ||
| 98 | __show_regs(regs, 0); | ||
| 99 | |||
| 97 | /* | 100 | /* |
| 98 | * Scan the stack, printing any text addresses we find. At the | 101 | * Scan the stack, printing any text addresses we find. At the |
| 99 | * same time, follow proper stack frames with the unwinder. | 102 | * same time, follow proper stack frames with the unwinder. |
| @@ -118,10 +121,8 @@ void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, | |||
| 118 | * Don't print regs->ip again if it was already printed | 121 | * Don't print regs->ip again if it was already printed |
| 119 | * by __show_regs() below. | 122 | * by __show_regs() below. |
| 120 | */ | 123 | */ |
| 121 | if (regs && stack == ®s->ip) { | 124 | if (regs && stack == ®s->ip) |
| 122 | unwind_next_frame(&state); | 125 | goto next; |
| 123 | continue; | ||
| 124 | } | ||
| 125 | 126 | ||
| 126 | if (stack == ret_addr_p) | 127 | if (stack == ret_addr_p) |
| 127 | reliable = 1; | 128 | reliable = 1; |
| @@ -144,6 +145,7 @@ void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, | |||
| 144 | if (!reliable) | 145 | if (!reliable) |
| 145 | continue; | 146 | continue; |
| 146 | 147 | ||
| 148 | next: | ||
| 147 | /* | 149 | /* |
| 148 | * Get the next frame from the unwinder. No need to | 150 | * Get the next frame from the unwinder. No need to |
| 149 | * check for an error: if anything goes wrong, the rest | 151 | * check for an error: if anything goes wrong, the rest |
| @@ -153,7 +155,7 @@ void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, | |||
| 153 | 155 | ||
| 154 | /* if the frame has entry regs, print them */ | 156 | /* if the frame has entry regs, print them */ |
| 155 | regs = unwind_get_entry_regs(&state); | 157 | regs = unwind_get_entry_regs(&state); |
| 156 | if (regs) | 158 | if (regs && on_stack(&stack_info, regs, sizeof(*regs))) |
| 157 | __show_regs(regs, 0); | 159 | __show_regs(regs, 0); |
| 158 | } | 160 | } |
| 159 | 161 | ||
diff --git a/arch/x86/kernel/dumpstack_32.c b/arch/x86/kernel/dumpstack_32.c index e5f0b40e66d2..4f0481474903 100644 --- a/arch/x86/kernel/dumpstack_32.c +++ b/arch/x86/kernel/dumpstack_32.c | |||
| @@ -37,7 +37,7 @@ static bool in_hardirq_stack(unsigned long *stack, struct stack_info *info) | |||
| 37 | * This is a software stack, so 'end' can be a valid stack pointer. | 37 | * This is a software stack, so 'end' can be a valid stack pointer. |
| 38 | * It just means the stack is empty. | 38 | * It just means the stack is empty. |
| 39 | */ | 39 | */ |
| 40 | if (stack < begin || stack > end) | 40 | if (stack <= begin || stack > end) |
| 41 | return false; | 41 | return false; |
| 42 | 42 | ||
| 43 | info->type = STACK_TYPE_IRQ; | 43 | info->type = STACK_TYPE_IRQ; |
| @@ -62,7 +62,7 @@ static bool in_softirq_stack(unsigned long *stack, struct stack_info *info) | |||
| 62 | * This is a software stack, so 'end' can be a valid stack pointer. | 62 | * This is a software stack, so 'end' can be a valid stack pointer. |
| 63 | * It just means the stack is empty. | 63 | * It just means the stack is empty. |
| 64 | */ | 64 | */ |
| 65 | if (stack < begin || stack > end) | 65 | if (stack <= begin || stack > end) |
| 66 | return false; | 66 | return false; |
| 67 | 67 | ||
| 68 | info->type = STACK_TYPE_SOFTIRQ; | 68 | info->type = STACK_TYPE_SOFTIRQ; |
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c index 3e1471d57487..225af4184f06 100644 --- a/arch/x86/kernel/dumpstack_64.c +++ b/arch/x86/kernel/dumpstack_64.c | |||
| @@ -55,7 +55,7 @@ static bool in_exception_stack(unsigned long *stack, struct stack_info *info) | |||
| 55 | begin = end - (exception_stack_sizes[k] / sizeof(long)); | 55 | begin = end - (exception_stack_sizes[k] / sizeof(long)); |
| 56 | regs = (struct pt_regs *)end - 1; | 56 | regs = (struct pt_regs *)end - 1; |
| 57 | 57 | ||
| 58 | if (stack < begin || stack >= end) | 58 | if (stack <= begin || stack >= end) |
| 59 | continue; | 59 | continue; |
| 60 | 60 | ||
| 61 | info->type = STACK_TYPE_EXCEPTION + k; | 61 | info->type = STACK_TYPE_EXCEPTION + k; |
| @@ -78,7 +78,7 @@ static bool in_irq_stack(unsigned long *stack, struct stack_info *info) | |||
| 78 | * This is a software stack, so 'end' can be a valid stack pointer. | 78 | * This is a software stack, so 'end' can be a valid stack pointer. |
| 79 | * It just means the stack is empty. | 79 | * It just means the stack is empty. |
| 80 | */ | 80 | */ |
| 81 | if (stack < begin || stack > end) | 81 | if (stack <= begin || stack > end) |
| 82 | return false; | 82 | return false; |
| 83 | 83 | ||
| 84 | info->type = STACK_TYPE_IRQ; | 84 | info->type = STACK_TYPE_IRQ; |
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index c3169be4c596..2987e3991c2b 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c | |||
| @@ -279,6 +279,9 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) | |||
| 279 | struct tss_struct *tss = &per_cpu(cpu_tss, cpu); | 279 | struct tss_struct *tss = &per_cpu(cpu_tss, cpu); |
| 280 | unsigned prev_fsindex, prev_gsindex; | 280 | unsigned prev_fsindex, prev_gsindex; |
| 281 | 281 | ||
| 282 | WARN_ON_ONCE(IS_ENABLED(CONFIG_DEBUG_ENTRY) && | ||
| 283 | this_cpu_read(irq_count) != -1); | ||
| 284 | |||
| 282 | switch_fpu_prepare(prev_fpu, cpu); | 285 | switch_fpu_prepare(prev_fpu, cpu); |
| 283 | 286 | ||
| 284 | /* We must save %fs and %gs before load_TLS() because | 287 | /* We must save %fs and %gs before load_TLS() because |
diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h index 7ef015eb3403..b4531e3b2120 100644 --- a/include/asm-generic/io.h +++ b/include/asm-generic/io.h | |||
| @@ -915,6 +915,9 @@ extern void ioport_unmap(void __iomem *p); | |||
| 915 | #endif /* CONFIG_GENERIC_IOMAP */ | 915 | #endif /* CONFIG_GENERIC_IOMAP */ |
| 916 | #endif /* CONFIG_HAS_IOPORT_MAP */ | 916 | #endif /* CONFIG_HAS_IOPORT_MAP */ |
| 917 | 917 | ||
| 918 | /* | ||
| 919 | * Convert a virtual cached pointer to an uncached pointer | ||
| 920 | */ | ||
| 918 | #ifndef xlate_dev_kmem_ptr | 921 | #ifndef xlate_dev_kmem_ptr |
| 919 | #define xlate_dev_kmem_ptr xlate_dev_kmem_ptr | 922 | #define xlate_dev_kmem_ptr xlate_dev_kmem_ptr |
| 920 | static inline void *xlate_dev_kmem_ptr(void *addr) | 923 | static inline void *xlate_dev_kmem_ptr(void *addr) |
| @@ -954,6 +957,14 @@ static inline void *bus_to_virt(unsigned long address) | |||
| 954 | 957 | ||
| 955 | #ifndef memset_io | 958 | #ifndef memset_io |
| 956 | #define memset_io memset_io | 959 | #define memset_io memset_io |
| 960 | /** | ||
| 961 | * memset_io Set a range of I/O memory to a constant value | ||
| 962 | * @addr: The beginning of the I/O-memory range to set | ||
| 963 | * @val: The value to set the memory to | ||
| 964 | * @count: The number of bytes to set | ||
| 965 | * | ||
| 966 | * Set a range of I/O memory to a given value. | ||
| 967 | */ | ||
| 957 | static inline void memset_io(volatile void __iomem *addr, int value, | 968 | static inline void memset_io(volatile void __iomem *addr, int value, |
| 958 | size_t size) | 969 | size_t size) |
| 959 | { | 970 | { |
| @@ -963,6 +974,14 @@ static inline void memset_io(volatile void __iomem *addr, int value, | |||
| 963 | 974 | ||
| 964 | #ifndef memcpy_fromio | 975 | #ifndef memcpy_fromio |
| 965 | #define memcpy_fromio memcpy_fromio | 976 | #define memcpy_fromio memcpy_fromio |
| 977 | /** | ||
| 978 | * memcpy_fromio Copy a block of data from I/O memory | ||
| 979 | * @dst: The (RAM) destination for the copy | ||
| 980 | * @src: The (I/O memory) source for the data | ||
| 981 | * @count: The number of bytes to copy | ||
| 982 | * | ||
| 983 | * Copy a block of data from I/O memory. | ||
| 984 | */ | ||
| 966 | static inline void memcpy_fromio(void *buffer, | 985 | static inline void memcpy_fromio(void *buffer, |
| 967 | const volatile void __iomem *addr, | 986 | const volatile void __iomem *addr, |
| 968 | size_t size) | 987 | size_t size) |
| @@ -973,6 +992,14 @@ static inline void memcpy_fromio(void *buffer, | |||
| 973 | 992 | ||
| 974 | #ifndef memcpy_toio | 993 | #ifndef memcpy_toio |
| 975 | #define memcpy_toio memcpy_toio | 994 | #define memcpy_toio memcpy_toio |
| 995 | /** | ||
| 996 | * memcpy_toio Copy a block of data into I/O memory | ||
| 997 | * @dst: The (I/O memory) destination for the copy | ||
| 998 | * @src: The (RAM) source for the data | ||
| 999 | * @count: The number of bytes to copy | ||
| 1000 | * | ||
| 1001 | * Copy a block of data to I/O memory. | ||
| 1002 | */ | ||
| 976 | static inline void memcpy_toio(volatile void __iomem *addr, const void *buffer, | 1003 | static inline void memcpy_toio(volatile void __iomem *addr, const void *buffer, |
| 977 | size_t size) | 1004 | size_t size) |
| 978 | { | 1005 | { |
diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h index bdb80c4aef6e..10825052b03f 100644 --- a/include/linux/compiler-gcc.h +++ b/include/linux/compiler-gcc.h | |||
| @@ -203,11 +203,16 @@ | |||
| 203 | 203 | ||
| 204 | #ifdef CONFIG_STACK_VALIDATION | 204 | #ifdef CONFIG_STACK_VALIDATION |
| 205 | #define annotate_unreachable() ({ \ | 205 | #define annotate_unreachable() ({ \ |
| 206 | asm("%c0:\t\n" \ | 206 | asm("%c0:\n\t" \ |
| 207 | ".pushsection .discard.unreachable\t\n" \ | 207 | ".pushsection .discard.unreachable\n\t" \ |
| 208 | ".long %c0b - .\t\n" \ | 208 | ".long %c0b - .\n\t" \ |
| 209 | ".popsection\t\n" : : "i" (__LINE__)); \ | 209 | ".popsection\n\t" : : "i" (__LINE__)); \ |
| 210 | }) | 210 | }) |
| 211 | #define ASM_UNREACHABLE \ | ||
| 212 | "999:\n\t" \ | ||
| 213 | ".pushsection .discard.unreachable\n\t" \ | ||
| 214 | ".long 999b - .\n\t" \ | ||
| 215 | ".popsection\n\t" | ||
| 211 | #else | 216 | #else |
| 212 | #define annotate_unreachable() | 217 | #define annotate_unreachable() |
| 213 | #endif | 218 | #endif |
diff --git a/include/linux/compiler.h b/include/linux/compiler.h index eca8ad75e28b..e25746d88697 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h | |||
| @@ -185,6 +185,9 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val, | |||
| 185 | #endif | 185 | #endif |
| 186 | 186 | ||
| 187 | /* Unreachable code */ | 187 | /* Unreachable code */ |
| 188 | #ifndef ASM_UNREACHABLE | ||
| 189 | # define ASM_UNREACHABLE | ||
| 190 | #endif | ||
| 188 | #ifndef unreachable | 191 | #ifndef unreachable |
| 189 | # define unreachable() do { } while (1) | 192 | # define unreachable() do { } while (1) |
| 190 | #endif | 193 | #endif |
diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 4a9a2cec0a1b..854608d42e85 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build | |||
| @@ -262,6 +262,9 @@ objtool_args = check | |||
| 262 | ifndef CONFIG_FRAME_POINTER | 262 | ifndef CONFIG_FRAME_POINTER |
| 263 | objtool_args += --no-fp | 263 | objtool_args += --no-fp |
| 264 | endif | 264 | endif |
| 265 | ifdef CONFIG_GCOV_KERNEL | ||
| 266 | objtool_args += --no-unreachable | ||
| 267 | endif | ||
| 265 | 268 | ||
| 266 | # 'OBJECT_FILES_NON_STANDARD := y': skip objtool checking for a directory | 269 | # 'OBJECT_FILES_NON_STANDARD := y': skip objtool checking for a directory |
| 267 | # 'OBJECT_FILES_NON_STANDARD_foo.o := 'y': skip objtool checking for a file | 270 | # 'OBJECT_FILES_NON_STANDARD_foo.o := 'y': skip objtool checking for a file |
diff --git a/tools/objtool/Build b/tools/objtool/Build index 6f2e1987c4d9..749becdf5b90 100644 --- a/tools/objtool/Build +++ b/tools/objtool/Build | |||
| @@ -1,6 +1,9 @@ | |||
| 1 | objtool-y += arch/$(SRCARCH)/ | 1 | objtool-y += arch/$(SRCARCH)/ |
| 2 | objtool-y += builtin-check.o | 2 | objtool-y += builtin-check.o |
| 3 | objtool-y += builtin-orc.o | ||
| 3 | objtool-y += check.o | 4 | objtool-y += check.o |
| 5 | objtool-y += orc_gen.o | ||
| 6 | objtool-y += orc_dump.o | ||
| 4 | objtool-y += elf.o | 7 | objtool-y += elf.o |
| 5 | objtool-y += special.o | 8 | objtool-y += special.o |
| 6 | objtool-y += objtool.o | 9 | objtool-y += objtool.o |
diff --git a/tools/objtool/Documentation/stack-validation.txt b/tools/objtool/Documentation/stack-validation.txt index 17c1195f11f4..6a1af43862df 100644 --- a/tools/objtool/Documentation/stack-validation.txt +++ b/tools/objtool/Documentation/stack-validation.txt | |||
| @@ -11,9 +11,6 @@ analyzes every .o file and ensures the validity of its stack metadata. | |||
| 11 | It enforces a set of rules on asm code and C inline assembly code so | 11 | It enforces a set of rules on asm code and C inline assembly code so |
| 12 | that stack traces can be reliable. | 12 | that stack traces can be reliable. |
| 13 | 13 | ||
| 14 | Currently it only checks frame pointer usage, but there are plans to add | ||
| 15 | CFI validation for C files and CFI generation for asm files. | ||
| 16 | |||
| 17 | For each function, it recursively follows all possible code paths and | 14 | For each function, it recursively follows all possible code paths and |
| 18 | validates the correct frame pointer state at each instruction. | 15 | validates the correct frame pointer state at each instruction. |
| 19 | 16 | ||
| @@ -23,6 +20,10 @@ alternative execution paths to a given instruction (or set of | |||
| 23 | instructions). Similarly, it knows how to follow switch statements, for | 20 | instructions). Similarly, it knows how to follow switch statements, for |
| 24 | which gcc sometimes uses jump tables. | 21 | which gcc sometimes uses jump tables. |
| 25 | 22 | ||
| 23 | (Objtool also has an 'orc generate' subcommand which generates debuginfo | ||
| 24 | for the ORC unwinder. See Documentation/x86/orc-unwinder.txt in the | ||
| 25 | kernel tree for more details.) | ||
| 26 | |||
| 26 | 27 | ||
| 27 | Why do we need stack metadata validation? | 28 | Why do we need stack metadata validation? |
| 28 | ----------------------------------------- | 29 | ----------------------------------------- |
| @@ -93,37 +94,14 @@ a) More reliable stack traces for frame pointer enabled kernels | |||
| 93 | or at the very end of the function after the stack frame has been | 94 | or at the very end of the function after the stack frame has been |
| 94 | destroyed. This is an inherent limitation of frame pointers. | 95 | destroyed. This is an inherent limitation of frame pointers. |
| 95 | 96 | ||
| 96 | b) 100% reliable stack traces for DWARF enabled kernels | 97 | b) ORC (Oops Rewind Capability) unwind table generation |
| 97 | |||
| 98 | (NOTE: This is not yet implemented) | ||
| 99 | |||
| 100 | As an alternative to frame pointers, DWARF Call Frame Information | ||
| 101 | (CFI) metadata can be used to walk the stack. Unlike frame pointers, | ||
| 102 | CFI metadata is out of band. So it doesn't affect runtime | ||
| 103 | performance and it can be reliable even when interrupts or exceptions | ||
| 104 | are involved. | ||
| 105 | |||
| 106 | For C code, gcc automatically generates DWARF CFI metadata. But for | ||
| 107 | asm code, generating CFI is a tedious manual approach which requires | ||
| 108 | manually placed .cfi assembler macros to be scattered throughout the | ||
| 109 | code. It's clumsy and very easy to get wrong, and it makes the real | ||
| 110 | code harder to read. | ||
| 111 | |||
| 112 | Stacktool will improve this situation in several ways. For code | ||
| 113 | which already has CFI annotations, it will validate them. For code | ||
| 114 | which doesn't have CFI annotations, it will generate them. So an | ||
| 115 | architecture can opt to strip out all the manual .cfi annotations | ||
| 116 | from their asm code and have objtool generate them instead. | ||
| 117 | 98 | ||
| 118 | We might also add a runtime stack validation debug option where we | 99 | An alternative to frame pointers and DWARF, ORC unwind data can be |
| 119 | periodically walk the stack from schedule() and/or an NMI to ensure | 100 | used to walk the stack. Unlike frame pointers, ORC data is out of |
| 120 | that the stack metadata is sane and that we reach the bottom of the | 101 | band. So it doesn't affect runtime performance and it can be |
| 121 | stack. | 102 | reliable even when interrupts or exceptions are involved. |
| 122 | 103 | ||
| 123 | So the benefit of objtool here will be that external tooling should | 104 | For more details, see Documentation/x86/orc-unwinder.txt. |
| 124 | always show perfect stack traces. And the same will be true for | ||
| 125 | kernel warning/oops traces if the architecture has a runtime DWARF | ||
| 126 | unwinder. | ||
| 127 | 105 | ||
| 128 | c) Higher live patching compatibility rate | 106 | c) Higher live patching compatibility rate |
| 129 | 107 | ||
| @@ -211,7 +189,7 @@ they mean, and suggestions for how to fix them. | |||
| 211 | function, add proper frame pointer logic using the FRAME_BEGIN and | 189 | function, add proper frame pointer logic using the FRAME_BEGIN and |
| 212 | FRAME_END macros. Otherwise, if it's not a callable function, remove | 190 | FRAME_END macros. Otherwise, if it's not a callable function, remove |
| 213 | its ELF function annotation by changing ENDPROC to END, and instead | 191 | its ELF function annotation by changing ENDPROC to END, and instead |
| 214 | use the manual CFI hint macros in asm/undwarf.h. | 192 | use the manual unwind hint macros in asm/unwind_hints.h. |
| 215 | 193 | ||
| 216 | If it's a GCC-compiled .c file, the error may be because the function | 194 | If it's a GCC-compiled .c file, the error may be because the function |
| 217 | uses an inline asm() statement which has a "call" instruction. An | 195 | uses an inline asm() statement which has a "call" instruction. An |
| @@ -231,8 +209,8 @@ they mean, and suggestions for how to fix them. | |||
| 231 | If the error is for an asm file, and the instruction is inside (or | 209 | If the error is for an asm file, and the instruction is inside (or |
| 232 | reachable from) a callable function, the function should be annotated | 210 | reachable from) a callable function, the function should be annotated |
| 233 | with the ENTRY/ENDPROC macros (ENDPROC is the important one). | 211 | with the ENTRY/ENDPROC macros (ENDPROC is the important one). |
| 234 | Otherwise, the code should probably be annotated with the CFI hint | 212 | Otherwise, the code should probably be annotated with the unwind hint |
| 235 | macros in asm/undwarf.h so objtool and the unwinder can know the | 213 | macros in asm/unwind_hints.h so objtool and the unwinder can know the |
| 236 | stack state associated with the code. | 214 | stack state associated with the code. |
| 237 | 215 | ||
| 238 | If you're 100% sure the code won't affect stack traces, or if you're | 216 | If you're 100% sure the code won't affect stack traces, or if you're |
| @@ -258,7 +236,7 @@ they mean, and suggestions for how to fix them. | |||
| 258 | instructions aren't allowed in a callable function, and are most | 236 | instructions aren't allowed in a callable function, and are most |
| 259 | likely part of the kernel entry code. They should usually not have | 237 | likely part of the kernel entry code. They should usually not have |
| 260 | the callable function annotation (ENDPROC) and should always be | 238 | the callable function annotation (ENDPROC) and should always be |
| 261 | annotated with the CFI hint macros in asm/undwarf.h. | 239 | annotated with the unwind hint macros in asm/unwind_hints.h. |
| 262 | 240 | ||
| 263 | 241 | ||
| 264 | 6. file.o: warning: objtool: func()+0x26: sibling call from callable instruction with modified stack frame | 242 | 6. file.o: warning: objtool: func()+0x26: sibling call from callable instruction with modified stack frame |
| @@ -272,7 +250,7 @@ they mean, and suggestions for how to fix them. | |||
| 272 | 250 | ||
| 273 | If the instruction is not actually in a callable function (e.g. | 251 | If the instruction is not actually in a callable function (e.g. |
| 274 | kernel entry code), change ENDPROC to END and annotate manually with | 252 | kernel entry code), change ENDPROC to END and annotate manually with |
| 275 | the CFI hint macros in asm/undwarf.h. | 253 | the unwind hint macros in asm/unwind_hints.h. |
| 276 | 254 | ||
| 277 | 255 | ||
| 278 | 7. file: warning: objtool: func()+0x5c: stack state mismatch | 256 | 7. file: warning: objtool: func()+0x5c: stack state mismatch |
| @@ -288,8 +266,8 @@ they mean, and suggestions for how to fix them. | |||
| 288 | 266 | ||
| 289 | Another possibility is that the code has some asm or inline asm which | 267 | Another possibility is that the code has some asm or inline asm which |
| 290 | does some unusual things to the stack or the frame pointer. In such | 268 | does some unusual things to the stack or the frame pointer. In such |
| 291 | cases it's probably appropriate to use the CFI hint macros in | 269 | cases it's probably appropriate to use the unwind hint macros in |
| 292 | asm/undwarf.h. | 270 | asm/unwind_hints.h. |
| 293 | 271 | ||
| 294 | 272 | ||
| 295 | 8. file.o: warning: objtool: funcA() falls through to next function funcB() | 273 | 8. file.o: warning: objtool: funcA() falls through to next function funcB() |
diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile index 0e2765e243c0..3a6425fefc43 100644 --- a/tools/objtool/Makefile +++ b/tools/objtool/Makefile | |||
| @@ -52,6 +52,9 @@ $(OBJTOOL): $(LIBSUBCMD) $(OBJTOOL_IN) | |||
| 52 | diff -I'^#include' arch/x86/insn/inat.h ../../arch/x86/include/asm/inat.h >/dev/null && \ | 52 | diff -I'^#include' arch/x86/insn/inat.h ../../arch/x86/include/asm/inat.h >/dev/null && \ |
| 53 | diff -I'^#include' arch/x86/insn/inat_types.h ../../arch/x86/include/asm/inat_types.h >/dev/null) \ | 53 | diff -I'^#include' arch/x86/insn/inat_types.h ../../arch/x86/include/asm/inat_types.h >/dev/null) \ |
| 54 | || echo "warning: objtool: x86 instruction decoder differs from kernel" >&2 )) || true | 54 | || echo "warning: objtool: x86 instruction decoder differs from kernel" >&2 )) || true |
| 55 | @(test -d ../../kernel -a -d ../../tools -a -d ../objtool && (( \ | ||
| 56 | diff ../../arch/x86/include/asm/orc_types.h orc_types.h >/dev/null) \ | ||
| 57 | || echo "warning: objtool: orc_types.h differs from kernel" >&2 )) || true | ||
| 55 | $(QUIET_LINK)$(CC) $(OBJTOOL_IN) $(LDFLAGS) -o $@ | 58 | $(QUIET_LINK)$(CC) $(OBJTOOL_IN) $(LDFLAGS) -o $@ |
| 56 | 59 | ||
| 57 | 60 | ||
diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c index 365c34ecab26..57254f5b2779 100644 --- a/tools/objtool/builtin-check.c +++ b/tools/objtool/builtin-check.c | |||
| @@ -29,7 +29,7 @@ | |||
| 29 | #include "builtin.h" | 29 | #include "builtin.h" |
| 30 | #include "check.h" | 30 | #include "check.h" |
| 31 | 31 | ||
| 32 | bool nofp; | 32 | bool no_fp, no_unreachable; |
| 33 | 33 | ||
| 34 | static const char * const check_usage[] = { | 34 | static const char * const check_usage[] = { |
| 35 | "objtool check [<options>] file.o", | 35 | "objtool check [<options>] file.o", |
| @@ -37,7 +37,8 @@ static const char * const check_usage[] = { | |||
| 37 | }; | 37 | }; |
| 38 | 38 | ||
| 39 | const struct option check_options[] = { | 39 | const struct option check_options[] = { |
| 40 | OPT_BOOLEAN('f', "no-fp", &nofp, "Skip frame pointer validation"), | 40 | OPT_BOOLEAN('f', "no-fp", &no_fp, "Skip frame pointer validation"), |
| 41 | OPT_BOOLEAN('u', "no-unreachable", &no_unreachable, "Skip 'unreachable instruction' warnings"), | ||
| 41 | OPT_END(), | 42 | OPT_END(), |
| 42 | }; | 43 | }; |
| 43 | 44 | ||
| @@ -52,5 +53,5 @@ int cmd_check(int argc, const char **argv) | |||
| 52 | 53 | ||
| 53 | objname = argv[0]; | 54 | objname = argv[0]; |
| 54 | 55 | ||
| 55 | return check(objname, nofp); | 56 | return check(objname, no_fp, no_unreachable, false); |
| 56 | } | 57 | } |
diff --git a/tools/objtool/builtin-orc.c b/tools/objtool/builtin-orc.c new file mode 100644 index 000000000000..4c6b5c9ef073 --- /dev/null +++ b/tools/objtool/builtin-orc.c | |||
| @@ -0,0 +1,70 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com> | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU General Public License | ||
| 6 | * as published by the Free Software Foundation; either version 2 | ||
| 7 | * of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | ||
| 17 | |||
| 18 | /* | ||
| 19 | * objtool orc: | ||
| 20 | * | ||
| 21 | * This command analyzes a .o file and adds .orc_unwind and .orc_unwind_ip | ||
| 22 | * sections to it, which is used by the in-kernel ORC unwinder. | ||
| 23 | * | ||
| 24 | * This command is a superset of "objtool check". | ||
| 25 | */ | ||
| 26 | |||
| 27 | #include <string.h> | ||
| 28 | #include <subcmd/parse-options.h> | ||
| 29 | #include "builtin.h" | ||
| 30 | #include "check.h" | ||
| 31 | |||
| 32 | |||
| 33 | static const char *orc_usage[] = { | ||
| 34 | "objtool orc generate [<options>] file.o", | ||
| 35 | "objtool orc dump file.o", | ||
| 36 | NULL, | ||
| 37 | }; | ||
| 38 | |||
| 39 | extern const struct option check_options[]; | ||
| 40 | extern bool no_fp, no_unreachable; | ||
| 41 | |||
| 42 | int cmd_orc(int argc, const char **argv) | ||
| 43 | { | ||
| 44 | const char *objname; | ||
| 45 | |||
| 46 | argc--; argv++; | ||
| 47 | if (!strncmp(argv[0], "gen", 3)) { | ||
| 48 | argc = parse_options(argc, argv, check_options, orc_usage, 0); | ||
| 49 | if (argc != 1) | ||
| 50 | usage_with_options(orc_usage, check_options); | ||
| 51 | |||
| 52 | objname = argv[0]; | ||
| 53 | |||
| 54 | return check(objname, no_fp, no_unreachable, true); | ||
| 55 | |||
| 56 | } | ||
| 57 | |||
| 58 | if (!strcmp(argv[0], "dump")) { | ||
| 59 | if (argc != 2) | ||
| 60 | usage_with_options(orc_usage, check_options); | ||
| 61 | |||
| 62 | objname = argv[1]; | ||
| 63 | |||
| 64 | return orc_dump(objname); | ||
| 65 | } | ||
| 66 | |||
| 67 | usage_with_options(orc_usage, check_options); | ||
| 68 | |||
| 69 | return 0; | ||
| 70 | } | ||
diff --git a/tools/objtool/builtin.h b/tools/objtool/builtin.h index 34d2ba78a616..dd526067fed5 100644 --- a/tools/objtool/builtin.h +++ b/tools/objtool/builtin.h | |||
| @@ -18,5 +18,6 @@ | |||
| 18 | #define _BUILTIN_H | 18 | #define _BUILTIN_H |
| 19 | 19 | ||
| 20 | extern int cmd_check(int argc, const char **argv); | 20 | extern int cmd_check(int argc, const char **argv); |
| 21 | extern int cmd_orc(int argc, const char **argv); | ||
| 21 | 22 | ||
| 22 | #endif /* _BUILTIN_H */ | 23 | #endif /* _BUILTIN_H */ |
diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 2c6d74880403..3436a942b606 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c | |||
| @@ -33,11 +33,11 @@ struct alternative { | |||
| 33 | }; | 33 | }; |
| 34 | 34 | ||
| 35 | const char *objname; | 35 | const char *objname; |
| 36 | static bool nofp; | 36 | static bool no_fp; |
| 37 | struct cfi_state initial_func_cfi; | 37 | struct cfi_state initial_func_cfi; |
| 38 | 38 | ||
| 39 | static struct instruction *find_insn(struct objtool_file *file, | 39 | struct instruction *find_insn(struct objtool_file *file, |
| 40 | struct section *sec, unsigned long offset) | 40 | struct section *sec, unsigned long offset) |
| 41 | { | 41 | { |
| 42 | struct instruction *insn; | 42 | struct instruction *insn; |
| 43 | 43 | ||
| @@ -59,19 +59,6 @@ static struct instruction *next_insn_same_sec(struct objtool_file *file, | |||
| 59 | return next; | 59 | return next; |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | static bool gcov_enabled(struct objtool_file *file) | ||
| 63 | { | ||
| 64 | struct section *sec; | ||
| 65 | struct symbol *sym; | ||
| 66 | |||
| 67 | for_each_sec(file, sec) | ||
| 68 | list_for_each_entry(sym, &sec->symbol_list, list) | ||
| 69 | if (!strncmp(sym->name, "__gcov_.", 8)) | ||
| 70 | return true; | ||
| 71 | |||
| 72 | return false; | ||
| 73 | } | ||
| 74 | |||
| 75 | #define func_for_each_insn(file, func, insn) \ | 62 | #define func_for_each_insn(file, func, insn) \ |
| 76 | for (insn = find_insn(file, func->sec, func->offset); \ | 63 | for (insn = find_insn(file, func->sec, func->offset); \ |
| 77 | insn && &insn->list != &file->insn_list && \ | 64 | insn && &insn->list != &file->insn_list && \ |
| @@ -100,7 +87,6 @@ static bool gcov_enabled(struct objtool_file *file) | |||
| 100 | static bool ignore_func(struct objtool_file *file, struct symbol *func) | 87 | static bool ignore_func(struct objtool_file *file, struct symbol *func) |
| 101 | { | 88 | { |
| 102 | struct rela *rela; | 89 | struct rela *rela; |
| 103 | struct instruction *insn; | ||
| 104 | 90 | ||
| 105 | /* check for STACK_FRAME_NON_STANDARD */ | 91 | /* check for STACK_FRAME_NON_STANDARD */ |
| 106 | if (file->whitelist && file->whitelist->rela) | 92 | if (file->whitelist && file->whitelist->rela) |
| @@ -113,11 +99,6 @@ static bool ignore_func(struct objtool_file *file, struct symbol *func) | |||
| 113 | return true; | 99 | return true; |
| 114 | } | 100 | } |
| 115 | 101 | ||
| 116 | /* check if it has a context switching instruction */ | ||
| 117 | func_for_each_insn(file, func, insn) | ||
| 118 | if (insn->type == INSN_CONTEXT_SWITCH) | ||
| 119 | return true; | ||
| 120 | |||
| 121 | return false; | 102 | return false; |
| 122 | } | 103 | } |
| 123 | 104 | ||
| @@ -259,6 +240,11 @@ static int decode_instructions(struct objtool_file *file) | |||
| 259 | if (!(sec->sh.sh_flags & SHF_EXECINSTR)) | 240 | if (!(sec->sh.sh_flags & SHF_EXECINSTR)) |
| 260 | continue; | 241 | continue; |
| 261 | 242 | ||
| 243 | if (strcmp(sec->name, ".altinstr_replacement") && | ||
| 244 | strcmp(sec->name, ".altinstr_aux") && | ||
| 245 | strncmp(sec->name, ".discard.", 9)) | ||
| 246 | sec->text = true; | ||
| 247 | |||
| 262 | for (offset = 0; offset < sec->len; offset += insn->len) { | 248 | for (offset = 0; offset < sec->len; offset += insn->len) { |
| 263 | insn = malloc(sizeof(*insn)); | 249 | insn = malloc(sizeof(*insn)); |
| 264 | if (!insn) { | 250 | if (!insn) { |
| @@ -874,6 +860,99 @@ static int add_switch_table_alts(struct objtool_file *file) | |||
| 874 | return 0; | 860 | return 0; |
| 875 | } | 861 | } |
| 876 | 862 | ||
| 863 | static int read_unwind_hints(struct objtool_file *file) | ||
| 864 | { | ||
| 865 | struct section *sec, *relasec; | ||
| 866 | struct rela *rela; | ||
| 867 | struct unwind_hint *hint; | ||
| 868 | struct instruction *insn; | ||
| 869 | struct cfi_reg *cfa; | ||
| 870 | int i; | ||
| 871 | |||
| 872 | sec = find_section_by_name(file->elf, ".discard.unwind_hints"); | ||
| 873 | if (!sec) | ||
| 874 | return 0; | ||
| 875 | |||
| 876 | relasec = sec->rela; | ||
| 877 | if (!relasec) { | ||
| 878 | WARN("missing .rela.discard.unwind_hints section"); | ||
| 879 | return -1; | ||
| 880 | } | ||
| 881 | |||
| 882 | if (sec->len % sizeof(struct unwind_hint)) { | ||
| 883 | WARN("struct unwind_hint size mismatch"); | ||
| 884 | return -1; | ||
| 885 | } | ||
| 886 | |||
| 887 | file->hints = true; | ||
| 888 | |||
| 889 | for (i = 0; i < sec->len / sizeof(struct unwind_hint); i++) { | ||
| 890 | hint = (struct unwind_hint *)sec->data->d_buf + i; | ||
| 891 | |||
| 892 | rela = find_rela_by_dest(sec, i * sizeof(*hint)); | ||
| 893 | if (!rela) { | ||
| 894 | WARN("can't find rela for unwind_hints[%d]", i); | ||
| 895 | return -1; | ||
| 896 | } | ||
| 897 | |||
| 898 | insn = find_insn(file, rela->sym->sec, rela->addend); | ||
| 899 | if (!insn) { | ||
| 900 | WARN("can't find insn for unwind_hints[%d]", i); | ||
| 901 | return -1; | ||
| 902 | } | ||
| 903 | |||
| 904 | cfa = &insn->state.cfa; | ||
| 905 | |||
| 906 | if (hint->type == UNWIND_HINT_TYPE_SAVE) { | ||
| 907 | insn->save = true; | ||
| 908 | continue; | ||
| 909 | |||
| 910 | } else if (hint->type == UNWIND_HINT_TYPE_RESTORE) { | ||
| 911 | insn->restore = true; | ||
| 912 | insn->hint = true; | ||
| 913 | continue; | ||
| 914 | } | ||
| 915 | |||
| 916 | insn->hint = true; | ||
| 917 | |||
| 918 | switch (hint->sp_reg) { | ||
| 919 | case ORC_REG_UNDEFINED: | ||
| 920 | cfa->base = CFI_UNDEFINED; | ||
| 921 | break; | ||
| 922 | case ORC_REG_SP: | ||
| 923 | cfa->base = CFI_SP; | ||
| 924 | break; | ||
| 925 | case ORC_REG_BP: | ||
| 926 | cfa->base = CFI_BP; | ||
| 927 | break; | ||
| 928 | case ORC_REG_SP_INDIRECT: | ||
| 929 | cfa->base = CFI_SP_INDIRECT; | ||
| 930 | break; | ||
| 931 | case ORC_REG_R10: | ||
| 932 | cfa->base = CFI_R10; | ||
| 933 | break; | ||
| 934 | case ORC_REG_R13: | ||
| 935 | cfa->base = CFI_R13; | ||
| 936 | break; | ||
| 937 | case ORC_REG_DI: | ||
| 938 | cfa->base = CFI_DI; | ||
| 939 | break; | ||
| 940 | case ORC_REG_DX: | ||
| 941 | cfa->base = CFI_DX; | ||
| 942 | break; | ||
| 943 | default: | ||
| 944 | WARN_FUNC("unsupported unwind_hint sp base reg %d", | ||
| 945 | insn->sec, insn->offset, hint->sp_reg); | ||
| 946 | return -1; | ||
| 947 | } | ||
| 948 | |||
| 949 | cfa->offset = hint->sp_offset; | ||
| 950 | insn->state.type = hint->type; | ||
| 951 | } | ||
| 952 | |||
| 953 | return 0; | ||
| 954 | } | ||
| 955 | |||
| 877 | static int decode_sections(struct objtool_file *file) | 956 | static int decode_sections(struct objtool_file *file) |
| 878 | { | 957 | { |
| 879 | int ret; | 958 | int ret; |
| @@ -904,6 +983,10 @@ static int decode_sections(struct objtool_file *file) | |||
| 904 | if (ret) | 983 | if (ret) |
| 905 | return ret; | 984 | return ret; |
| 906 | 985 | ||
| 986 | ret = read_unwind_hints(file); | ||
| 987 | if (ret) | ||
| 988 | return ret; | ||
| 989 | |||
| 907 | return 0; | 990 | return 0; |
| 908 | } | 991 | } |
| 909 | 992 | ||
| @@ -947,6 +1030,30 @@ static bool has_valid_stack_frame(struct insn_state *state) | |||
| 947 | return false; | 1030 | return false; |
| 948 | } | 1031 | } |
| 949 | 1032 | ||
| 1033 | static int update_insn_state_regs(struct instruction *insn, struct insn_state *state) | ||
| 1034 | { | ||
| 1035 | struct cfi_reg *cfa = &state->cfa; | ||
| 1036 | struct stack_op *op = &insn->stack_op; | ||
| 1037 | |||
| 1038 | if (cfa->base != CFI_SP) | ||
| 1039 | return 0; | ||
| 1040 | |||
| 1041 | /* push */ | ||
| 1042 | if (op->dest.type == OP_DEST_PUSH) | ||
| 1043 | cfa->offset += 8; | ||
| 1044 | |||
| 1045 | /* pop */ | ||
| 1046 | if (op->src.type == OP_SRC_POP) | ||
| 1047 | cfa->offset -= 8; | ||
| 1048 | |||
| 1049 | /* add immediate to sp */ | ||
| 1050 | if (op->dest.type == OP_DEST_REG && op->src.type == OP_SRC_ADD && | ||
| 1051 | op->dest.reg == CFI_SP && op->src.reg == CFI_SP) | ||
| 1052 | cfa->offset -= op->src.offset; | ||
| 1053 | |||
| 1054 | return 0; | ||
| 1055 | } | ||
| 1056 | |||
| 950 | static void save_reg(struct insn_state *state, unsigned char reg, int base, | 1057 | static void save_reg(struct insn_state *state, unsigned char reg, int base, |
| 951 | int offset) | 1058 | int offset) |
| 952 | { | 1059 | { |
| @@ -1032,6 +1139,9 @@ static int update_insn_state(struct instruction *insn, struct insn_state *state) | |||
| 1032 | return 0; | 1139 | return 0; |
| 1033 | } | 1140 | } |
| 1034 | 1141 | ||
| 1142 | if (state->type == ORC_TYPE_REGS || state->type == ORC_TYPE_REGS_IRET) | ||
| 1143 | return update_insn_state_regs(insn, state); | ||
| 1144 | |||
| 1035 | switch (op->dest.type) { | 1145 | switch (op->dest.type) { |
| 1036 | 1146 | ||
| 1037 | case OP_DEST_REG: | 1147 | case OP_DEST_REG: |
| @@ -1051,7 +1161,7 @@ static int update_insn_state(struct instruction *insn, struct insn_state *state) | |||
| 1051 | regs[CFI_BP].base = CFI_BP; | 1161 | regs[CFI_BP].base = CFI_BP; |
| 1052 | regs[CFI_BP].offset = -state->stack_size; | 1162 | regs[CFI_BP].offset = -state->stack_size; |
| 1053 | state->bp_scratch = false; | 1163 | state->bp_scratch = false; |
| 1054 | } else if (!nofp) { | 1164 | } else if (!no_fp) { |
| 1055 | 1165 | ||
| 1056 | WARN_FUNC("unknown stack-related register move", | 1166 | WARN_FUNC("unknown stack-related register move", |
| 1057 | insn->sec, insn->offset); | 1167 | insn->sec, insn->offset); |
| @@ -1222,7 +1332,7 @@ static int update_insn_state(struct instruction *insn, struct insn_state *state) | |||
| 1222 | } | 1332 | } |
| 1223 | 1333 | ||
| 1224 | /* detect when asm code uses rbp as a scratch register */ | 1334 | /* detect when asm code uses rbp as a scratch register */ |
| 1225 | if (!nofp && insn->func && op->src.reg == CFI_BP && | 1335 | if (!no_fp && insn->func && op->src.reg == CFI_BP && |
| 1226 | cfa->base != CFI_BP) | 1336 | cfa->base != CFI_BP) |
| 1227 | state->bp_scratch = true; | 1337 | state->bp_scratch = true; |
| 1228 | break; | 1338 | break; |
| @@ -1323,6 +1433,10 @@ static bool insn_state_match(struct instruction *insn, struct insn_state *state) | |||
| 1323 | break; | 1433 | break; |
| 1324 | } | 1434 | } |
| 1325 | 1435 | ||
| 1436 | } else if (state1->type != state2->type) { | ||
| 1437 | WARN_FUNC("stack state mismatch: type1=%d type2=%d", | ||
| 1438 | insn->sec, insn->offset, state1->type, state2->type); | ||
| 1439 | |||
| 1326 | } else if (state1->drap != state2->drap || | 1440 | } else if (state1->drap != state2->drap || |
| 1327 | (state1->drap && state1->drap_reg != state2->drap_reg)) { | 1441 | (state1->drap && state1->drap_reg != state2->drap_reg)) { |
| 1328 | WARN_FUNC("stack state mismatch: drap1=%d(%d) drap2=%d(%d)", | 1442 | WARN_FUNC("stack state mismatch: drap1=%d(%d) drap2=%d(%d)", |
| @@ -1346,7 +1460,7 @@ static int validate_branch(struct objtool_file *file, struct instruction *first, | |||
| 1346 | struct insn_state state) | 1460 | struct insn_state state) |
| 1347 | { | 1461 | { |
| 1348 | struct alternative *alt; | 1462 | struct alternative *alt; |
| 1349 | struct instruction *insn; | 1463 | struct instruction *insn, *next_insn; |
| 1350 | struct section *sec; | 1464 | struct section *sec; |
| 1351 | struct symbol *func = NULL; | 1465 | struct symbol *func = NULL; |
| 1352 | int ret; | 1466 | int ret; |
| @@ -1361,6 +1475,8 @@ static int validate_branch(struct objtool_file *file, struct instruction *first, | |||
| 1361 | } | 1475 | } |
| 1362 | 1476 | ||
| 1363 | while (1) { | 1477 | while (1) { |
| 1478 | next_insn = next_insn_same_sec(file, insn); | ||
| 1479 | |||
| 1364 | if (file->c_file && insn->func) { | 1480 | if (file->c_file && insn->func) { |
| 1365 | if (func && func != insn->func) { | 1481 | if (func && func != insn->func) { |
| 1366 | WARN("%s() falls through to next function %s()", | 1482 | WARN("%s() falls through to next function %s()", |
| @@ -1378,13 +1494,54 @@ static int validate_branch(struct objtool_file *file, struct instruction *first, | |||
| 1378 | } | 1494 | } |
| 1379 | 1495 | ||
| 1380 | if (insn->visited) { | 1496 | if (insn->visited) { |
| 1381 | if (!!insn_state_match(insn, &state)) | 1497 | if (!insn->hint && !insn_state_match(insn, &state)) |
| 1382 | return 1; | 1498 | return 1; |
| 1383 | 1499 | ||
| 1384 | return 0; | 1500 | return 0; |
| 1385 | } | 1501 | } |
| 1386 | 1502 | ||
| 1387 | insn->state = state; | 1503 | if (insn->hint) { |
| 1504 | if (insn->restore) { | ||
| 1505 | struct instruction *save_insn, *i; | ||
| 1506 | |||
| 1507 | i = insn; | ||
| 1508 | save_insn = NULL; | ||
| 1509 | func_for_each_insn_continue_reverse(file, func, i) { | ||
| 1510 | if (i->save) { | ||
| 1511 | save_insn = i; | ||
| 1512 | break; | ||
| 1513 | } | ||
| 1514 | } | ||
| 1515 | |||
| 1516 | if (!save_insn) { | ||
| 1517 | WARN_FUNC("no corresponding CFI save for CFI restore", | ||
| 1518 | sec, insn->offset); | ||
| 1519 | return 1; | ||
| 1520 | } | ||
| 1521 | |||
| 1522 | if (!save_insn->visited) { | ||
| 1523 | /* | ||
| 1524 | * Oops, no state to copy yet. | ||
| 1525 | * Hopefully we can reach this | ||
| 1526 | * instruction from another branch | ||
| 1527 | * after the save insn has been | ||
| 1528 | * visited. | ||
| 1529 | */ | ||
| 1530 | if (insn == first) | ||
| 1531 | return 0; | ||
| 1532 | |||
| 1533 | WARN_FUNC("objtool isn't smart enough to handle this CFI save/restore combo", | ||
| 1534 | sec, insn->offset); | ||
| 1535 | return 1; | ||
| 1536 | } | ||
| 1537 | |||
| 1538 | insn->state = save_insn->state; | ||
| 1539 | } | ||
| 1540 | |||
| 1541 | state = insn->state; | ||
| 1542 | |||
| 1543 | } else | ||
| 1544 | insn->state = state; | ||
| 1388 | 1545 | ||
| 1389 | insn->visited = true; | 1546 | insn->visited = true; |
| 1390 | 1547 | ||
| @@ -1423,7 +1580,7 @@ static int validate_branch(struct objtool_file *file, struct instruction *first, | |||
| 1423 | 1580 | ||
| 1424 | /* fallthrough */ | 1581 | /* fallthrough */ |
| 1425 | case INSN_CALL_DYNAMIC: | 1582 | case INSN_CALL_DYNAMIC: |
| 1426 | if (!nofp && func && !has_valid_stack_frame(&state)) { | 1583 | if (!no_fp && func && !has_valid_stack_frame(&state)) { |
| 1427 | WARN_FUNC("call without frame pointer save/setup", | 1584 | WARN_FUNC("call without frame pointer save/setup", |
| 1428 | sec, insn->offset); | 1585 | sec, insn->offset); |
| 1429 | return 1; | 1586 | return 1; |
| @@ -1461,6 +1618,14 @@ static int validate_branch(struct objtool_file *file, struct instruction *first, | |||
| 1461 | 1618 | ||
| 1462 | return 0; | 1619 | return 0; |
| 1463 | 1620 | ||
| 1621 | case INSN_CONTEXT_SWITCH: | ||
| 1622 | if (func && (!next_insn || !next_insn->hint)) { | ||
| 1623 | WARN_FUNC("unsupported instruction in callable function", | ||
| 1624 | sec, insn->offset); | ||
| 1625 | return 1; | ||
| 1626 | } | ||
| 1627 | return 0; | ||
| 1628 | |||
| 1464 | case INSN_STACK: | 1629 | case INSN_STACK: |
| 1465 | if (update_insn_state(insn, &state)) | 1630 | if (update_insn_state(insn, &state)) |
| 1466 | return -1; | 1631 | return -1; |
| @@ -1474,7 +1639,7 @@ static int validate_branch(struct objtool_file *file, struct instruction *first, | |||
| 1474 | if (insn->dead_end) | 1639 | if (insn->dead_end) |
| 1475 | return 0; | 1640 | return 0; |
| 1476 | 1641 | ||
| 1477 | insn = next_insn_same_sec(file, insn); | 1642 | insn = next_insn; |
| 1478 | if (!insn) { | 1643 | if (!insn) { |
| 1479 | WARN("%s: unexpected end of section", sec->name); | 1644 | WARN("%s: unexpected end of section", sec->name); |
| 1480 | return 1; | 1645 | return 1; |
| @@ -1484,6 +1649,27 @@ static int validate_branch(struct objtool_file *file, struct instruction *first, | |||
| 1484 | return 0; | 1649 | return 0; |
| 1485 | } | 1650 | } |
| 1486 | 1651 | ||
| 1652 | static int validate_unwind_hints(struct objtool_file *file) | ||
| 1653 | { | ||
| 1654 | struct instruction *insn; | ||
| 1655 | int ret, warnings = 0; | ||
| 1656 | struct insn_state state; | ||
| 1657 | |||
| 1658 | if (!file->hints) | ||
| 1659 | return 0; | ||
| 1660 | |||
| 1661 | clear_insn_state(&state); | ||
| 1662 | |||
| 1663 | for_each_insn(file, insn) { | ||
| 1664 | if (insn->hint && !insn->visited) { | ||
| 1665 | ret = validate_branch(file, insn, state); | ||
| 1666 | warnings += ret; | ||
| 1667 | } | ||
| 1668 | } | ||
| 1669 | |||
| 1670 | return warnings; | ||
| 1671 | } | ||
| 1672 | |||
| 1487 | static bool is_kasan_insn(struct instruction *insn) | 1673 | static bool is_kasan_insn(struct instruction *insn) |
| 1488 | { | 1674 | { |
| 1489 | return (insn->type == INSN_CALL && | 1675 | return (insn->type == INSN_CALL && |
| @@ -1580,15 +1766,6 @@ static int validate_reachable_instructions(struct objtool_file *file) | |||
| 1580 | if (insn->visited || ignore_unreachable_insn(insn)) | 1766 | if (insn->visited || ignore_unreachable_insn(insn)) |
| 1581 | continue; | 1767 | continue; |
| 1582 | 1768 | ||
| 1583 | /* | ||
| 1584 | * gcov produces a lot of unreachable instructions. If we get | ||
| 1585 | * an unreachable warning and the file has gcov enabled, just | ||
| 1586 | * ignore it, and all other such warnings for the file. Do | ||
| 1587 | * this here because this is an expensive function. | ||
| 1588 | */ | ||
| 1589 | if (gcov_enabled(file)) | ||
| 1590 | return 0; | ||
| 1591 | |||
| 1592 | WARN_FUNC("unreachable instruction", insn->sec, insn->offset); | 1769 | WARN_FUNC("unreachable instruction", insn->sec, insn->offset); |
| 1593 | return 1; | 1770 | return 1; |
| 1594 | } | 1771 | } |
| @@ -1613,15 +1790,15 @@ static void cleanup(struct objtool_file *file) | |||
| 1613 | elf_close(file->elf); | 1790 | elf_close(file->elf); |
| 1614 | } | 1791 | } |
| 1615 | 1792 | ||
| 1616 | int check(const char *_objname, bool _nofp) | 1793 | int check(const char *_objname, bool _no_fp, bool no_unreachable, bool orc) |
| 1617 | { | 1794 | { |
| 1618 | struct objtool_file file; | 1795 | struct objtool_file file; |
| 1619 | int ret, warnings = 0; | 1796 | int ret, warnings = 0; |
| 1620 | 1797 | ||
| 1621 | objname = _objname; | 1798 | objname = _objname; |
| 1622 | nofp = _nofp; | 1799 | no_fp = _no_fp; |
| 1623 | 1800 | ||
| 1624 | file.elf = elf_open(objname); | 1801 | file.elf = elf_open(objname, orc ? O_RDWR : O_RDONLY); |
| 1625 | if (!file.elf) | 1802 | if (!file.elf) |
| 1626 | return 1; | 1803 | return 1; |
| 1627 | 1804 | ||
| @@ -1629,8 +1806,9 @@ int check(const char *_objname, bool _nofp) | |||
| 1629 | hash_init(file.insn_hash); | 1806 | hash_init(file.insn_hash); |
| 1630 | file.whitelist = find_section_by_name(file.elf, ".discard.func_stack_frame_non_standard"); | 1807 | file.whitelist = find_section_by_name(file.elf, ".discard.func_stack_frame_non_standard"); |
| 1631 | file.rodata = find_section_by_name(file.elf, ".rodata"); | 1808 | file.rodata = find_section_by_name(file.elf, ".rodata"); |
| 1632 | file.ignore_unreachables = false; | ||
| 1633 | file.c_file = find_section_by_name(file.elf, ".comment"); | 1809 | file.c_file = find_section_by_name(file.elf, ".comment"); |
| 1810 | file.ignore_unreachables = no_unreachable; | ||
| 1811 | file.hints = false; | ||
| 1634 | 1812 | ||
| 1635 | arch_initial_func_cfi_state(&initial_func_cfi); | 1813 | arch_initial_func_cfi_state(&initial_func_cfi); |
| 1636 | 1814 | ||
| @@ -1647,6 +1825,11 @@ int check(const char *_objname, bool _nofp) | |||
| 1647 | goto out; | 1825 | goto out; |
| 1648 | warnings += ret; | 1826 | warnings += ret; |
| 1649 | 1827 | ||
| 1828 | ret = validate_unwind_hints(&file); | ||
| 1829 | if (ret < 0) | ||
| 1830 | goto out; | ||
| 1831 | warnings += ret; | ||
| 1832 | |||
| 1650 | if (!warnings) { | 1833 | if (!warnings) { |
| 1651 | ret = validate_reachable_instructions(&file); | 1834 | ret = validate_reachable_instructions(&file); |
| 1652 | if (ret < 0) | 1835 | if (ret < 0) |
| @@ -1654,6 +1837,20 @@ int check(const char *_objname, bool _nofp) | |||
| 1654 | warnings += ret; | 1837 | warnings += ret; |
| 1655 | } | 1838 | } |
| 1656 | 1839 | ||
| 1840 | if (orc) { | ||
| 1841 | ret = create_orc(&file); | ||
| 1842 | if (ret < 0) | ||
| 1843 | goto out; | ||
| 1844 | |||
| 1845 | ret = create_orc_sections(&file); | ||
| 1846 | if (ret < 0) | ||
| 1847 | goto out; | ||
| 1848 | |||
| 1849 | ret = elf_write(file.elf); | ||
| 1850 | if (ret < 0) | ||
| 1851 | goto out; | ||
| 1852 | } | ||
| 1853 | |||
| 1657 | out: | 1854 | out: |
| 1658 | cleanup(&file); | 1855 | cleanup(&file); |
| 1659 | 1856 | ||
diff --git a/tools/objtool/check.h b/tools/objtool/check.h index da85f5b00ec6..c9af11f0c8af 100644 --- a/tools/objtool/check.h +++ b/tools/objtool/check.h | |||
| @@ -22,12 +22,14 @@ | |||
| 22 | #include "elf.h" | 22 | #include "elf.h" |
| 23 | #include "cfi.h" | 23 | #include "cfi.h" |
| 24 | #include "arch.h" | 24 | #include "arch.h" |
| 25 | #include "orc.h" | ||
| 25 | #include <linux/hashtable.h> | 26 | #include <linux/hashtable.h> |
| 26 | 27 | ||
| 27 | struct insn_state { | 28 | struct insn_state { |
| 28 | struct cfi_reg cfa; | 29 | struct cfi_reg cfa; |
| 29 | struct cfi_reg regs[CFI_NUM_REGS]; | 30 | struct cfi_reg regs[CFI_NUM_REGS]; |
| 30 | int stack_size; | 31 | int stack_size; |
| 32 | unsigned char type; | ||
| 31 | bool bp_scratch; | 33 | bool bp_scratch; |
| 32 | bool drap; | 34 | bool drap; |
| 33 | int drap_reg; | 35 | int drap_reg; |
| @@ -41,13 +43,14 @@ struct instruction { | |||
| 41 | unsigned int len; | 43 | unsigned int len; |
| 42 | unsigned char type; | 44 | unsigned char type; |
| 43 | unsigned long immediate; | 45 | unsigned long immediate; |
| 44 | bool alt_group, visited, dead_end, ignore; | 46 | bool alt_group, visited, dead_end, ignore, hint, save, restore; |
| 45 | struct symbol *call_dest; | 47 | struct symbol *call_dest; |
| 46 | struct instruction *jump_dest; | 48 | struct instruction *jump_dest; |
| 47 | struct list_head alts; | 49 | struct list_head alts; |
| 48 | struct symbol *func; | 50 | struct symbol *func; |
| 49 | struct stack_op stack_op; | 51 | struct stack_op stack_op; |
| 50 | struct insn_state state; | 52 | struct insn_state state; |
| 53 | struct orc_entry orc; | ||
| 51 | }; | 54 | }; |
| 52 | 55 | ||
| 53 | struct objtool_file { | 56 | struct objtool_file { |
| @@ -55,12 +58,22 @@ struct objtool_file { | |||
| 55 | struct list_head insn_list; | 58 | struct list_head insn_list; |
| 56 | DECLARE_HASHTABLE(insn_hash, 16); | 59 | DECLARE_HASHTABLE(insn_hash, 16); |
| 57 | struct section *rodata, *whitelist; | 60 | struct section *rodata, *whitelist; |
| 58 | bool ignore_unreachables, c_file; | 61 | bool ignore_unreachables, c_file, hints; |
| 59 | }; | 62 | }; |
| 60 | 63 | ||
| 61 | int check(const char *objname, bool nofp); | 64 | int check(const char *objname, bool no_fp, bool no_unreachable, bool orc); |
| 65 | |||
| 66 | struct instruction *find_insn(struct objtool_file *file, | ||
| 67 | struct section *sec, unsigned long offset); | ||
| 62 | 68 | ||
| 63 | #define for_each_insn(file, insn) \ | 69 | #define for_each_insn(file, insn) \ |
| 64 | list_for_each_entry(insn, &file->insn_list, list) | 70 | list_for_each_entry(insn, &file->insn_list, list) |
| 65 | 71 | ||
| 72 | #define sec_for_each_insn(file, sec, insn) \ | ||
| 73 | for (insn = find_insn(file, sec, 0); \ | ||
| 74 | insn && &insn->list != &file->insn_list && \ | ||
| 75 | insn->sec == sec; \ | ||
| 76 | insn = list_next_entry(insn, list)) | ||
| 77 | |||
| 78 | |||
| 66 | #endif /* _CHECK_H */ | 79 | #endif /* _CHECK_H */ |
diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 1a7e8aa2af58..6e9f980a7d26 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c | |||
| @@ -30,16 +30,6 @@ | |||
| 30 | #include "elf.h" | 30 | #include "elf.h" |
| 31 | #include "warn.h" | 31 | #include "warn.h" |
| 32 | 32 | ||
| 33 | /* | ||
| 34 | * Fallback for systems without this "read, mmaping if possible" cmd. | ||
| 35 | */ | ||
| 36 | #ifndef ELF_C_READ_MMAP | ||
| 37 | #define ELF_C_READ_MMAP ELF_C_READ | ||
| 38 | #endif | ||
| 39 | |||
| 40 | #define WARN_ELF(format, ...) \ | ||
| 41 | WARN(format ": %s", ##__VA_ARGS__, elf_errmsg(-1)) | ||
| 42 | |||
| 43 | struct section *find_section_by_name(struct elf *elf, const char *name) | 33 | struct section *find_section_by_name(struct elf *elf, const char *name) |
| 44 | { | 34 | { |
| 45 | struct section *sec; | 35 | struct section *sec; |
| @@ -349,9 +339,10 @@ static int read_relas(struct elf *elf) | |||
| 349 | return 0; | 339 | return 0; |
| 350 | } | 340 | } |
| 351 | 341 | ||
| 352 | struct elf *elf_open(const char *name) | 342 | struct elf *elf_open(const char *name, int flags) |
| 353 | { | 343 | { |
| 354 | struct elf *elf; | 344 | struct elf *elf; |
| 345 | Elf_Cmd cmd; | ||
| 355 | 346 | ||
| 356 | elf_version(EV_CURRENT); | 347 | elf_version(EV_CURRENT); |
| 357 | 348 | ||
| @@ -364,13 +355,20 @@ struct elf *elf_open(const char *name) | |||
| 364 | 355 | ||
| 365 | INIT_LIST_HEAD(&elf->sections); | 356 | INIT_LIST_HEAD(&elf->sections); |
| 366 | 357 | ||
| 367 | elf->fd = open(name, O_RDONLY); | 358 | elf->fd = open(name, flags); |
| 368 | if (elf->fd == -1) { | 359 | if (elf->fd == -1) { |
| 369 | perror("open"); | 360 | perror("open"); |
| 370 | goto err; | 361 | goto err; |
| 371 | } | 362 | } |
| 372 | 363 | ||
| 373 | elf->elf = elf_begin(elf->fd, ELF_C_READ_MMAP, NULL); | 364 | if ((flags & O_ACCMODE) == O_RDONLY) |
| 365 | cmd = ELF_C_READ_MMAP; | ||
| 366 | else if ((flags & O_ACCMODE) == O_RDWR) | ||
| 367 | cmd = ELF_C_RDWR; | ||
| 368 | else /* O_WRONLY */ | ||
| 369 | cmd = ELF_C_WRITE; | ||
| 370 | |||
| 371 | elf->elf = elf_begin(elf->fd, cmd, NULL); | ||
| 374 | if (!elf->elf) { | 372 | if (!elf->elf) { |
| 375 | WARN_ELF("elf_begin"); | 373 | WARN_ELF("elf_begin"); |
| 376 | goto err; | 374 | goto err; |
| @@ -397,6 +395,194 @@ err: | |||
| 397 | return NULL; | 395 | return NULL; |
| 398 | } | 396 | } |
| 399 | 397 | ||
| 398 | struct section *elf_create_section(struct elf *elf, const char *name, | ||
| 399 | size_t entsize, int nr) | ||
| 400 | { | ||
| 401 | struct section *sec, *shstrtab; | ||
| 402 | size_t size = entsize * nr; | ||
| 403 | struct Elf_Scn *s; | ||
| 404 | Elf_Data *data; | ||
| 405 | |||
| 406 | sec = malloc(sizeof(*sec)); | ||
| 407 | if (!sec) { | ||
| 408 | perror("malloc"); | ||
| 409 | return NULL; | ||
| 410 | } | ||
| 411 | memset(sec, 0, sizeof(*sec)); | ||
| 412 | |||
| 413 | INIT_LIST_HEAD(&sec->symbol_list); | ||
| 414 | INIT_LIST_HEAD(&sec->rela_list); | ||
| 415 | hash_init(sec->rela_hash); | ||
| 416 | hash_init(sec->symbol_hash); | ||
| 417 | |||
| 418 | list_add_tail(&sec->list, &elf->sections); | ||
| 419 | |||
| 420 | s = elf_newscn(elf->elf); | ||
| 421 | if (!s) { | ||
| 422 | WARN_ELF("elf_newscn"); | ||
| 423 | return NULL; | ||
| 424 | } | ||
| 425 | |||
| 426 | sec->name = strdup(name); | ||
| 427 | if (!sec->name) { | ||
| 428 | perror("strdup"); | ||
| 429 | return NULL; | ||
| 430 | } | ||
| 431 | |||
| 432 | sec->idx = elf_ndxscn(s); | ||
| 433 | sec->len = size; | ||
| 434 | sec->changed = true; | ||
| 435 | |||
| 436 | sec->data = elf_newdata(s); | ||
| 437 | if (!sec->data) { | ||
| 438 | WARN_ELF("elf_newdata"); | ||
| 439 | return NULL; | ||
| 440 | } | ||
| 441 | |||
| 442 | sec->data->d_size = size; | ||
| 443 | sec->data->d_align = 1; | ||
| 444 | |||
| 445 | if (size) { | ||
| 446 | sec->data->d_buf = malloc(size); | ||
| 447 | if (!sec->data->d_buf) { | ||
| 448 | perror("malloc"); | ||
| 449 | return NULL; | ||
| 450 | } | ||
| 451 | memset(sec->data->d_buf, 0, size); | ||
| 452 | } | ||
| 453 | |||
| 454 | if (!gelf_getshdr(s, &sec->sh)) { | ||
| 455 | WARN_ELF("gelf_getshdr"); | ||
| 456 | return NULL; | ||
| 457 | } | ||
| 458 | |||
| 459 | sec->sh.sh_size = size; | ||
| 460 | sec->sh.sh_entsize = entsize; | ||
| 461 | sec->sh.sh_type = SHT_PROGBITS; | ||
| 462 | sec->sh.sh_addralign = 1; | ||
| 463 | sec->sh.sh_flags = SHF_ALLOC; | ||
| 464 | |||
| 465 | |||
| 466 | /* Add section name to .shstrtab */ | ||
| 467 | shstrtab = find_section_by_name(elf, ".shstrtab"); | ||
| 468 | if (!shstrtab) { | ||
| 469 | WARN("can't find .shstrtab section"); | ||
| 470 | return NULL; | ||
| 471 | } | ||
| 472 | |||
| 473 | s = elf_getscn(elf->elf, shstrtab->idx); | ||
| 474 | if (!s) { | ||
| 475 | WARN_ELF("elf_getscn"); | ||
| 476 | return NULL; | ||
| 477 | } | ||
| 478 | |||
| 479 | data = elf_newdata(s); | ||
| 480 | if (!data) { | ||
| 481 | WARN_ELF("elf_newdata"); | ||
| 482 | return NULL; | ||
| 483 | } | ||
| 484 | |||
| 485 | data->d_buf = sec->name; | ||
| 486 | data->d_size = strlen(name) + 1; | ||
| 487 | data->d_align = 1; | ||
| 488 | |||
| 489 | sec->sh.sh_name = shstrtab->len; | ||
| 490 | |||
| 491 | shstrtab->len += strlen(name) + 1; | ||
| 492 | shstrtab->changed = true; | ||
| 493 | |||
| 494 | return sec; | ||
| 495 | } | ||
| 496 | |||
| 497 | struct section *elf_create_rela_section(struct elf *elf, struct section *base) | ||
| 498 | { | ||
| 499 | char *relaname; | ||
| 500 | struct section *sec; | ||
| 501 | |||
| 502 | relaname = malloc(strlen(base->name) + strlen(".rela") + 1); | ||
| 503 | if (!relaname) { | ||
| 504 | perror("malloc"); | ||
| 505 | return NULL; | ||
| 506 | } | ||
| 507 | strcpy(relaname, ".rela"); | ||
| 508 | strcat(relaname, base->name); | ||
| 509 | |||
| 510 | sec = elf_create_section(elf, relaname, sizeof(GElf_Rela), 0); | ||
| 511 | if (!sec) | ||
| 512 | return NULL; | ||
| 513 | |||
| 514 | base->rela = sec; | ||
| 515 | sec->base = base; | ||
| 516 | |||
| 517 | sec->sh.sh_type = SHT_RELA; | ||
| 518 | sec->sh.sh_addralign = 8; | ||
| 519 | sec->sh.sh_link = find_section_by_name(elf, ".symtab")->idx; | ||
| 520 | sec->sh.sh_info = base->idx; | ||
| 521 | sec->sh.sh_flags = SHF_INFO_LINK; | ||
| 522 | |||
| 523 | return sec; | ||
| 524 | } | ||
| 525 | |||
| 526 | int elf_rebuild_rela_section(struct section *sec) | ||
| 527 | { | ||
| 528 | struct rela *rela; | ||
| 529 | int nr, idx = 0, size; | ||
| 530 | GElf_Rela *relas; | ||
| 531 | |||
| 532 | nr = 0; | ||
| 533 | list_for_each_entry(rela, &sec->rela_list, list) | ||
| 534 | nr++; | ||
| 535 | |||
| 536 | size = nr * sizeof(*relas); | ||
| 537 | relas = malloc(size); | ||
| 538 | if (!relas) { | ||
| 539 | perror("malloc"); | ||
| 540 | return -1; | ||
| 541 | } | ||
| 542 | |||
| 543 | sec->data->d_buf = relas; | ||
| 544 | sec->data->d_size = size; | ||
| 545 | |||
| 546 | sec->sh.sh_size = size; | ||
| 547 | |||
| 548 | idx = 0; | ||
| 549 | list_for_each_entry(rela, &sec->rela_list, list) { | ||
| 550 | relas[idx].r_offset = rela->offset; | ||
| 551 | relas[idx].r_addend = rela->addend; | ||
| 552 | relas[idx].r_info = GELF_R_INFO(rela->sym->idx, rela->type); | ||
| 553 | idx++; | ||
| 554 | } | ||
| 555 | |||
| 556 | return 0; | ||
| 557 | } | ||
| 558 | |||
| 559 | int elf_write(struct elf *elf) | ||
| 560 | { | ||
| 561 | struct section *sec; | ||
| 562 | Elf_Scn *s; | ||
| 563 | |||
| 564 | list_for_each_entry(sec, &elf->sections, list) { | ||
| 565 | if (sec->changed) { | ||
| 566 | s = elf_getscn(elf->elf, sec->idx); | ||
| 567 | if (!s) { | ||
| 568 | WARN_ELF("elf_getscn"); | ||
| 569 | return -1; | ||
| 570 | } | ||
| 571 | if (!gelf_update_shdr (s, &sec->sh)) { | ||
| 572 | WARN_ELF("gelf_update_shdr"); | ||
| 573 | return -1; | ||
| 574 | } | ||
| 575 | } | ||
| 576 | } | ||
| 577 | |||
| 578 | if (elf_update(elf->elf, ELF_C_WRITE) < 0) { | ||
| 579 | WARN_ELF("elf_update"); | ||
| 580 | return -1; | ||
| 581 | } | ||
| 582 | |||
| 583 | return 0; | ||
| 584 | } | ||
| 585 | |||
| 400 | void elf_close(struct elf *elf) | 586 | void elf_close(struct elf *elf) |
| 401 | { | 587 | { |
| 402 | struct section *sec, *tmpsec; | 588 | struct section *sec, *tmpsec; |
diff --git a/tools/objtool/elf.h b/tools/objtool/elf.h index 343968b778cb..d86e2ff14466 100644 --- a/tools/objtool/elf.h +++ b/tools/objtool/elf.h | |||
| @@ -28,6 +28,13 @@ | |||
| 28 | # define elf_getshdrstrndx elf_getshstrndx | 28 | # define elf_getshdrstrndx elf_getshstrndx |
| 29 | #endif | 29 | #endif |
| 30 | 30 | ||
| 31 | /* | ||
| 32 | * Fallback for systems without this "read, mmaping if possible" cmd. | ||
| 33 | */ | ||
| 34 | #ifndef ELF_C_READ_MMAP | ||
| 35 | #define ELF_C_READ_MMAP ELF_C_READ | ||
| 36 | #endif | ||
| 37 | |||
| 31 | struct section { | 38 | struct section { |
| 32 | struct list_head list; | 39 | struct list_head list; |
| 33 | GElf_Shdr sh; | 40 | GElf_Shdr sh; |
| @@ -41,6 +48,7 @@ struct section { | |||
| 41 | char *name; | 48 | char *name; |
| 42 | int idx; | 49 | int idx; |
| 43 | unsigned int len; | 50 | unsigned int len; |
| 51 | bool changed, text; | ||
| 44 | }; | 52 | }; |
| 45 | 53 | ||
| 46 | struct symbol { | 54 | struct symbol { |
| @@ -75,7 +83,7 @@ struct elf { | |||
| 75 | }; | 83 | }; |
| 76 | 84 | ||
| 77 | 85 | ||
| 78 | struct elf *elf_open(const char *name); | 86 | struct elf *elf_open(const char *name, int flags); |
| 79 | struct section *find_section_by_name(struct elf *elf, const char *name); | 87 | struct section *find_section_by_name(struct elf *elf, const char *name); |
| 80 | struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset); | 88 | struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset); |
| 81 | struct symbol *find_symbol_containing(struct section *sec, unsigned long offset); | 89 | struct symbol *find_symbol_containing(struct section *sec, unsigned long offset); |
| @@ -83,6 +91,11 @@ struct rela *find_rela_by_dest(struct section *sec, unsigned long offset); | |||
| 83 | struct rela *find_rela_by_dest_range(struct section *sec, unsigned long offset, | 91 | struct rela *find_rela_by_dest_range(struct section *sec, unsigned long offset, |
| 84 | unsigned int len); | 92 | unsigned int len); |
| 85 | struct symbol *find_containing_func(struct section *sec, unsigned long offset); | 93 | struct symbol *find_containing_func(struct section *sec, unsigned long offset); |
| 94 | struct section *elf_create_section(struct elf *elf, const char *name, size_t | ||
| 95 | entsize, int nr); | ||
| 96 | struct section *elf_create_rela_section(struct elf *elf, struct section *base); | ||
| 97 | int elf_rebuild_rela_section(struct section *sec); | ||
| 98 | int elf_write(struct elf *elf); | ||
| 86 | void elf_close(struct elf *elf); | 99 | void elf_close(struct elf *elf); |
| 87 | 100 | ||
| 88 | #define for_each_sec(file, sec) \ | 101 | #define for_each_sec(file, sec) \ |
diff --git a/tools/objtool/objtool.c b/tools/objtool/objtool.c index ecc5b1b5d15d..31e0f9143840 100644 --- a/tools/objtool/objtool.c +++ b/tools/objtool/objtool.c | |||
| @@ -42,10 +42,11 @@ struct cmd_struct { | |||
| 42 | }; | 42 | }; |
| 43 | 43 | ||
| 44 | static const char objtool_usage_string[] = | 44 | static const char objtool_usage_string[] = |
| 45 | "objtool [OPTIONS] COMMAND [ARGS]"; | 45 | "objtool COMMAND [ARGS]"; |
| 46 | 46 | ||
| 47 | static struct cmd_struct objtool_cmds[] = { | 47 | static struct cmd_struct objtool_cmds[] = { |
| 48 | {"check", cmd_check, "Perform stack metadata validation on an object file" }, | 48 | {"check", cmd_check, "Perform stack metadata validation on an object file" }, |
| 49 | {"orc", cmd_orc, "Generate in-place ORC unwind tables for an object file" }, | ||
| 49 | }; | 50 | }; |
| 50 | 51 | ||
| 51 | bool help; | 52 | bool help; |
diff --git a/tools/objtool/orc.h b/tools/objtool/orc.h new file mode 100644 index 000000000000..a4139e386ef3 --- /dev/null +++ b/tools/objtool/orc.h | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com> | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU General Public License | ||
| 6 | * as published by the Free Software Foundation; either version 2 | ||
| 7 | * of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #ifndef _ORC_H | ||
| 19 | #define _ORC_H | ||
| 20 | |||
| 21 | #include "orc_types.h" | ||
| 22 | |||
| 23 | struct objtool_file; | ||
| 24 | |||
| 25 | int create_orc(struct objtool_file *file); | ||
| 26 | int create_orc_sections(struct objtool_file *file); | ||
| 27 | |||
| 28 | int orc_dump(const char *objname); | ||
| 29 | |||
| 30 | #endif /* _ORC_H */ | ||
diff --git a/tools/objtool/orc_dump.c b/tools/objtool/orc_dump.c new file mode 100644 index 000000000000..36c5bf6a2675 --- /dev/null +++ b/tools/objtool/orc_dump.c | |||
| @@ -0,0 +1,212 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com> | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU General Public License | ||
| 6 | * as published by the Free Software Foundation; either version 2 | ||
| 7 | * of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #include <unistd.h> | ||
| 19 | #include "orc.h" | ||
| 20 | #include "warn.h" | ||
| 21 | |||
| 22 | static const char *reg_name(unsigned int reg) | ||
| 23 | { | ||
| 24 | switch (reg) { | ||
| 25 | case ORC_REG_PREV_SP: | ||
| 26 | return "prevsp"; | ||
| 27 | case ORC_REG_DX: | ||
| 28 | return "dx"; | ||
| 29 | case ORC_REG_DI: | ||
| 30 | return "di"; | ||
| 31 | case ORC_REG_BP: | ||
| 32 | return "bp"; | ||
| 33 | case ORC_REG_SP: | ||
| 34 | return "sp"; | ||
| 35 | case ORC_REG_R10: | ||
| 36 | return "r10"; | ||
| 37 | case ORC_REG_R13: | ||
| 38 | return "r13"; | ||
| 39 | case ORC_REG_BP_INDIRECT: | ||
| 40 | return "bp(ind)"; | ||
| 41 | case ORC_REG_SP_INDIRECT: | ||
| 42 | return "sp(ind)"; | ||
| 43 | default: | ||
| 44 | return "?"; | ||
| 45 | } | ||
| 46 | } | ||
| 47 | |||
| 48 | static const char *orc_type_name(unsigned int type) | ||
| 49 | { | ||
| 50 | switch (type) { | ||
| 51 | case ORC_TYPE_CALL: | ||
| 52 | return "call"; | ||
| 53 | case ORC_TYPE_REGS: | ||
| 54 | return "regs"; | ||
| 55 | case ORC_TYPE_REGS_IRET: | ||
| 56 | return "iret"; | ||
| 57 | default: | ||
| 58 | return "?"; | ||
| 59 | } | ||
| 60 | } | ||
| 61 | |||
| 62 | static void print_reg(unsigned int reg, int offset) | ||
| 63 | { | ||
| 64 | if (reg == ORC_REG_BP_INDIRECT) | ||
| 65 | printf("(bp%+d)", offset); | ||
| 66 | else if (reg == ORC_REG_SP_INDIRECT) | ||
| 67 | printf("(sp%+d)", offset); | ||
| 68 | else if (reg == ORC_REG_UNDEFINED) | ||
| 69 | printf("(und)"); | ||
| 70 | else | ||
| 71 | printf("%s%+d", reg_name(reg), offset); | ||
| 72 | } | ||
| 73 | |||
| 74 | int orc_dump(const char *_objname) | ||
| 75 | { | ||
| 76 | int fd, nr_entries, i, *orc_ip = NULL, orc_size = 0; | ||
| 77 | struct orc_entry *orc = NULL; | ||
| 78 | char *name; | ||
| 79 | unsigned long nr_sections, orc_ip_addr = 0; | ||
| 80 | size_t shstrtab_idx; | ||
| 81 | Elf *elf; | ||
| 82 | Elf_Scn *scn; | ||
| 83 | GElf_Shdr sh; | ||
| 84 | GElf_Rela rela; | ||
| 85 | GElf_Sym sym; | ||
| 86 | Elf_Data *data, *symtab = NULL, *rela_orc_ip = NULL; | ||
| 87 | |||
| 88 | |||
| 89 | objname = _objname; | ||
| 90 | |||
| 91 | elf_version(EV_CURRENT); | ||
| 92 | |||
| 93 | fd = open(objname, O_RDONLY); | ||
| 94 | if (fd == -1) { | ||
| 95 | perror("open"); | ||
| 96 | return -1; | ||
| 97 | } | ||
| 98 | |||
| 99 | elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); | ||
| 100 | if (!elf) { | ||
| 101 | WARN_ELF("elf_begin"); | ||
| 102 | return -1; | ||
| 103 | } | ||
| 104 | |||
| 105 | if (elf_getshdrnum(elf, &nr_sections)) { | ||
| 106 | WARN_ELF("elf_getshdrnum"); | ||
| 107 | return -1; | ||
| 108 | } | ||
| 109 | |||
| 110 | if (elf_getshdrstrndx(elf, &shstrtab_idx)) { | ||
| 111 | WARN_ELF("elf_getshdrstrndx"); | ||
| 112 | return -1; | ||
| 113 | } | ||
| 114 | |||
| 115 | for (i = 0; i < nr_sections; i++) { | ||
| 116 | scn = elf_getscn(elf, i); | ||
| 117 | if (!scn) { | ||
| 118 | WARN_ELF("elf_getscn"); | ||
| 119 | return -1; | ||
| 120 | } | ||
| 121 | |||
| 122 | if (!gelf_getshdr(scn, &sh)) { | ||
| 123 | WARN_ELF("gelf_getshdr"); | ||
| 124 | return -1; | ||
| 125 | } | ||
| 126 | |||
| 127 | name = elf_strptr(elf, shstrtab_idx, sh.sh_name); | ||
| 128 | if (!name) { | ||
| 129 | WARN_ELF("elf_strptr"); | ||
| 130 | return -1; | ||
| 131 | } | ||
| 132 | |||
| 133 | data = elf_getdata(scn, NULL); | ||
| 134 | if (!data) { | ||
| 135 | WARN_ELF("elf_getdata"); | ||
| 136 | return -1; | ||
| 137 | } | ||
| 138 | |||
| 139 | if (!strcmp(name, ".symtab")) { | ||
| 140 | symtab = data; | ||
| 141 | } else if (!strcmp(name, ".orc_unwind")) { | ||
| 142 | orc = data->d_buf; | ||
| 143 | orc_size = sh.sh_size; | ||
| 144 | } else if (!strcmp(name, ".orc_unwind_ip")) { | ||
| 145 | orc_ip = data->d_buf; | ||
| 146 | orc_ip_addr = sh.sh_addr; | ||
| 147 | } else if (!strcmp(name, ".rela.orc_unwind_ip")) { | ||
| 148 | rela_orc_ip = data; | ||
| 149 | } | ||
| 150 | } | ||
| 151 | |||
| 152 | if (!symtab || !orc || !orc_ip) | ||
| 153 | return 0; | ||
| 154 | |||
| 155 | if (orc_size % sizeof(*orc) != 0) { | ||
| 156 | WARN("bad .orc_unwind section size"); | ||
| 157 | return -1; | ||
| 158 | } | ||
| 159 | |||
| 160 | nr_entries = orc_size / sizeof(*orc); | ||
| 161 | for (i = 0; i < nr_entries; i++) { | ||
| 162 | if (rela_orc_ip) { | ||
| 163 | if (!gelf_getrela(rela_orc_ip, i, &rela)) { | ||
| 164 | WARN_ELF("gelf_getrela"); | ||
| 165 | return -1; | ||
| 166 | } | ||
| 167 | |||
| 168 | if (!gelf_getsym(symtab, GELF_R_SYM(rela.r_info), &sym)) { | ||
| 169 | WARN_ELF("gelf_getsym"); | ||
| 170 | return -1; | ||
| 171 | } | ||
| 172 | |||
| 173 | scn = elf_getscn(elf, sym.st_shndx); | ||
| 174 | if (!scn) { | ||
| 175 | WARN_ELF("elf_getscn"); | ||
| 176 | return -1; | ||
| 177 | } | ||
| 178 | |||
| 179 | if (!gelf_getshdr(scn, &sh)) { | ||
| 180 | WARN_ELF("gelf_getshdr"); | ||
| 181 | return -1; | ||
| 182 | } | ||
| 183 | |||
| 184 | name = elf_strptr(elf, shstrtab_idx, sh.sh_name); | ||
| 185 | if (!name || !*name) { | ||
| 186 | WARN_ELF("elf_strptr"); | ||
| 187 | return -1; | ||
| 188 | } | ||
| 189 | |||
| 190 | printf("%s+%lx:", name, rela.r_addend); | ||
| 191 | |||
| 192 | } else { | ||
| 193 | printf("%lx:", orc_ip_addr + (i * sizeof(int)) + orc_ip[i]); | ||
| 194 | } | ||
| 195 | |||
| 196 | |||
| 197 | printf(" sp:"); | ||
| 198 | |||
| 199 | print_reg(orc[i].sp_reg, orc[i].sp_offset); | ||
| 200 | |||
| 201 | printf(" bp:"); | ||
| 202 | |||
| 203 | print_reg(orc[i].bp_reg, orc[i].bp_offset); | ||
| 204 | |||
| 205 | printf(" type:%s\n", orc_type_name(orc[i].type)); | ||
| 206 | } | ||
| 207 | |||
| 208 | elf_end(elf); | ||
| 209 | close(fd); | ||
| 210 | |||
| 211 | return 0; | ||
| 212 | } | ||
diff --git a/tools/objtool/orc_gen.c b/tools/objtool/orc_gen.c new file mode 100644 index 000000000000..e5ca31429c9b --- /dev/null +++ b/tools/objtool/orc_gen.c | |||
| @@ -0,0 +1,214 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com> | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU General Public License | ||
| 6 | * as published by the Free Software Foundation; either version 2 | ||
| 7 | * of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #include <stdlib.h> | ||
| 19 | #include <string.h> | ||
| 20 | |||
| 21 | #include "orc.h" | ||
| 22 | #include "check.h" | ||
| 23 | #include "warn.h" | ||
| 24 | |||
| 25 | int create_orc(struct objtool_file *file) | ||
| 26 | { | ||
| 27 | struct instruction *insn; | ||
| 28 | |||
| 29 | for_each_insn(file, insn) { | ||
| 30 | struct orc_entry *orc = &insn->orc; | ||
| 31 | struct cfi_reg *cfa = &insn->state.cfa; | ||
| 32 | struct cfi_reg *bp = &insn->state.regs[CFI_BP]; | ||
| 33 | |||
| 34 | if (cfa->base == CFI_UNDEFINED) { | ||
| 35 | orc->sp_reg = ORC_REG_UNDEFINED; | ||
| 36 | continue; | ||
| 37 | } | ||
| 38 | |||
| 39 | switch (cfa->base) { | ||
| 40 | case CFI_SP: | ||
| 41 | orc->sp_reg = ORC_REG_SP; | ||
| 42 | break; | ||
| 43 | case CFI_SP_INDIRECT: | ||
| 44 | orc->sp_reg = ORC_REG_SP_INDIRECT; | ||
| 45 | break; | ||
| 46 | case CFI_BP: | ||
| 47 | orc->sp_reg = ORC_REG_BP; | ||
| 48 | break; | ||
| 49 | case CFI_BP_INDIRECT: | ||
| 50 | orc->sp_reg = ORC_REG_BP_INDIRECT; | ||
| 51 | break; | ||
| 52 | case CFI_R10: | ||
| 53 | orc->sp_reg = ORC_REG_R10; | ||
| 54 | break; | ||
| 55 | case CFI_R13: | ||
| 56 | orc->sp_reg = ORC_REG_R13; | ||
| 57 | break; | ||
| 58 | case CFI_DI: | ||
| 59 | orc->sp_reg = ORC_REG_DI; | ||
| 60 | break; | ||
| 61 | case CFI_DX: | ||
| 62 | orc->sp_reg = ORC_REG_DX; | ||
| 63 | break; | ||
| 64 | default: | ||
| 65 | WARN_FUNC("unknown CFA base reg %d", | ||
| 66 | insn->sec, insn->offset, cfa->base); | ||
| 67 | return -1; | ||
| 68 | } | ||
| 69 | |||
| 70 | switch(bp->base) { | ||
| 71 | case CFI_UNDEFINED: | ||
| 72 | orc->bp_reg = ORC_REG_UNDEFINED; | ||
| 73 | break; | ||
| 74 | case CFI_CFA: | ||
| 75 | orc->bp_reg = ORC_REG_PREV_SP; | ||
| 76 | break; | ||
| 77 | case CFI_BP: | ||
| 78 | orc->bp_reg = ORC_REG_BP; | ||
| 79 | break; | ||
| 80 | default: | ||
| 81 | WARN_FUNC("unknown BP base reg %d", | ||
| 82 | insn->sec, insn->offset, bp->base); | ||
| 83 | return -1; | ||
| 84 | } | ||
| 85 | |||
| 86 | orc->sp_offset = cfa->offset; | ||
| 87 | orc->bp_offset = bp->offset; | ||
| 88 | orc->type = insn->state.type; | ||
| 89 | } | ||
| 90 | |||
| 91 | return 0; | ||
| 92 | } | ||
| 93 | |||
| 94 | static int create_orc_entry(struct section *u_sec, struct section *ip_relasec, | ||
| 95 | unsigned int idx, struct section *insn_sec, | ||
| 96 | unsigned long insn_off, struct orc_entry *o) | ||
| 97 | { | ||
| 98 | struct orc_entry *orc; | ||
| 99 | struct rela *rela; | ||
| 100 | |||
| 101 | /* populate ORC data */ | ||
| 102 | orc = (struct orc_entry *)u_sec->data->d_buf + idx; | ||
| 103 | memcpy(orc, o, sizeof(*orc)); | ||
| 104 | |||
| 105 | /* populate rela for ip */ | ||
| 106 | rela = malloc(sizeof(*rela)); | ||
| 107 | if (!rela) { | ||
| 108 | perror("malloc"); | ||
| 109 | return -1; | ||
| 110 | } | ||
| 111 | memset(rela, 0, sizeof(*rela)); | ||
| 112 | |||
| 113 | rela->sym = insn_sec->sym; | ||
| 114 | rela->addend = insn_off; | ||
| 115 | rela->type = R_X86_64_PC32; | ||
| 116 | rela->offset = idx * sizeof(int); | ||
| 117 | |||
| 118 | list_add_tail(&rela->list, &ip_relasec->rela_list); | ||
| 119 | hash_add(ip_relasec->rela_hash, &rela->hash, rela->offset); | ||
| 120 | |||
| 121 | return 0; | ||
| 122 | } | ||
| 123 | |||
| 124 | int create_orc_sections(struct objtool_file *file) | ||
| 125 | { | ||
| 126 | struct instruction *insn, *prev_insn; | ||
| 127 | struct section *sec, *u_sec, *ip_relasec; | ||
| 128 | unsigned int idx; | ||
| 129 | |||
| 130 | struct orc_entry empty = { | ||
| 131 | .sp_reg = ORC_REG_UNDEFINED, | ||
| 132 | .bp_reg = ORC_REG_UNDEFINED, | ||
| 133 | .type = ORC_TYPE_CALL, | ||
| 134 | }; | ||
| 135 | |||
| 136 | sec = find_section_by_name(file->elf, ".orc_unwind"); | ||
| 137 | if (sec) { | ||
| 138 | WARN("file already has .orc_unwind section, skipping"); | ||
| 139 | return -1; | ||
| 140 | } | ||
| 141 | |||
| 142 | /* count the number of needed orcs */ | ||
| 143 | idx = 0; | ||
| 144 | for_each_sec(file, sec) { | ||
| 145 | if (!sec->text) | ||
| 146 | continue; | ||
| 147 | |||
| 148 | prev_insn = NULL; | ||
| 149 | sec_for_each_insn(file, sec, insn) { | ||
| 150 | if (!prev_insn || | ||
| 151 | memcmp(&insn->orc, &prev_insn->orc, | ||
| 152 | sizeof(struct orc_entry))) { | ||
| 153 | idx++; | ||
| 154 | } | ||
| 155 | prev_insn = insn; | ||
| 156 | } | ||
| 157 | |||
| 158 | /* section terminator */ | ||
| 159 | if (prev_insn) | ||
| 160 | idx++; | ||
| 161 | } | ||
| 162 | if (!idx) | ||
| 163 | return -1; | ||
| 164 | |||
| 165 | |||
| 166 | /* create .orc_unwind_ip and .rela.orc_unwind_ip sections */ | ||
| 167 | sec = elf_create_section(file->elf, ".orc_unwind_ip", sizeof(int), idx); | ||
| 168 | |||
| 169 | ip_relasec = elf_create_rela_section(file->elf, sec); | ||
| 170 | if (!ip_relasec) | ||
| 171 | return -1; | ||
| 172 | |||
| 173 | /* create .orc_unwind section */ | ||
| 174 | u_sec = elf_create_section(file->elf, ".orc_unwind", | ||
| 175 | sizeof(struct orc_entry), idx); | ||
| 176 | |||
| 177 | /* populate sections */ | ||
| 178 | idx = 0; | ||
| 179 | for_each_sec(file, sec) { | ||
| 180 | if (!sec->text) | ||
| 181 | continue; | ||
| 182 | |||
| 183 | prev_insn = NULL; | ||
| 184 | sec_for_each_insn(file, sec, insn) { | ||
| 185 | if (!prev_insn || memcmp(&insn->orc, &prev_insn->orc, | ||
| 186 | sizeof(struct orc_entry))) { | ||
| 187 | |||
| 188 | if (create_orc_entry(u_sec, ip_relasec, idx, | ||
| 189 | insn->sec, insn->offset, | ||
| 190 | &insn->orc)) | ||
| 191 | return -1; | ||
| 192 | |||
| 193 | idx++; | ||
| 194 | } | ||
| 195 | prev_insn = insn; | ||
| 196 | } | ||
| 197 | |||
| 198 | /* section terminator */ | ||
| 199 | if (prev_insn) { | ||
| 200 | if (create_orc_entry(u_sec, ip_relasec, idx, | ||
| 201 | prev_insn->sec, | ||
| 202 | prev_insn->offset + prev_insn->len, | ||
| 203 | &empty)) | ||
| 204 | return -1; | ||
| 205 | |||
| 206 | idx++; | ||
| 207 | } | ||
| 208 | } | ||
| 209 | |||
| 210 | if (elf_rebuild_rela_section(ip_relasec)) | ||
| 211 | return -1; | ||
| 212 | |||
| 213 | return 0; | ||
| 214 | } | ||
diff --git a/tools/objtool/orc_types.h b/tools/objtool/orc_types.h new file mode 100644 index 000000000000..9c9dc579bd7d --- /dev/null +++ b/tools/objtool/orc_types.h | |||
| @@ -0,0 +1,107 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com> | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU General Public License | ||
| 6 | * as published by the Free Software Foundation; either version 2 | ||
| 7 | * of the License, or (at your option) any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program; if not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #ifndef _ORC_TYPES_H | ||
| 19 | #define _ORC_TYPES_H | ||
| 20 | |||
| 21 | #include <linux/types.h> | ||
| 22 | #include <linux/compiler.h> | ||
| 23 | |||
| 24 | /* | ||
| 25 | * The ORC_REG_* registers are base registers which are used to find other | ||
| 26 | * registers on the stack. | ||
| 27 | * | ||
| 28 | * ORC_REG_PREV_SP, also known as DWARF Call Frame Address (CFA), is the | ||
| 29 | * address of the previous frame: the caller's SP before it called the current | ||
| 30 | * function. | ||
| 31 | * | ||
| 32 | * ORC_REG_UNDEFINED means the corresponding register's value didn't change in | ||
| 33 | * the current frame. | ||
| 34 | * | ||
| 35 | * The most commonly used base registers are SP and BP -- which the previous SP | ||
| 36 | * is usually based on -- and PREV_SP and UNDEFINED -- which the previous BP is | ||
| 37 | * usually based on. | ||
| 38 | * | ||
| 39 | * The rest of the base registers are needed for special cases like entry code | ||
| 40 | * and GCC realigned stacks. | ||
| 41 | */ | ||
| 42 | #define ORC_REG_UNDEFINED 0 | ||
| 43 | #define ORC_REG_PREV_SP 1 | ||
| 44 | #define ORC_REG_DX 2 | ||
| 45 | #define ORC_REG_DI 3 | ||
| 46 | #define ORC_REG_BP 4 | ||
| 47 | #define ORC_REG_SP 5 | ||
| 48 | #define ORC_REG_R10 6 | ||
| 49 | #define ORC_REG_R13 7 | ||
| 50 | #define ORC_REG_BP_INDIRECT 8 | ||
| 51 | #define ORC_REG_SP_INDIRECT 9 | ||
| 52 | #define ORC_REG_MAX 15 | ||
| 53 | |||
| 54 | /* | ||
| 55 | * ORC_TYPE_CALL: Indicates that sp_reg+sp_offset resolves to PREV_SP (the | ||
| 56 | * caller's SP right before it made the call). Used for all callable | ||
| 57 | * functions, i.e. all C code and all callable asm functions. | ||
| 58 | * | ||
| 59 | * ORC_TYPE_REGS: Used in entry code to indicate that sp_reg+sp_offset points | ||
| 60 | * to a fully populated pt_regs from a syscall, interrupt, or exception. | ||
| 61 | * | ||
| 62 | * ORC_TYPE_REGS_IRET: Used in entry code to indicate that sp_reg+sp_offset | ||
| 63 | * points to the iret return frame. | ||
| 64 | * | ||
| 65 | * The UNWIND_HINT macros are used only for the unwind_hint struct. They | ||
| 66 | * aren't used in struct orc_entry due to size and complexity constraints. | ||
| 67 | * Objtool converts them to real types when it converts the hints to orc | ||
| 68 | * entries. | ||
| 69 | */ | ||
| 70 | #define ORC_TYPE_CALL 0 | ||
| 71 | #define ORC_TYPE_REGS 1 | ||
| 72 | #define ORC_TYPE_REGS_IRET 2 | ||
| 73 | #define UNWIND_HINT_TYPE_SAVE 3 | ||
| 74 | #define UNWIND_HINT_TYPE_RESTORE 4 | ||
| 75 | |||
| 76 | #ifndef __ASSEMBLY__ | ||
| 77 | /* | ||
| 78 | * This struct is more or less a vastly simplified version of the DWARF Call | ||
| 79 | * Frame Information standard. It contains only the necessary parts of DWARF | ||
| 80 | * CFI, simplified for ease of access by the in-kernel unwinder. It tells the | ||
| 81 | * unwinder how to find the previous SP and BP (and sometimes entry regs) on | ||
| 82 | * the stack for a given code address. Each instance of the struct corresponds | ||
| 83 | * to one or more code locations. | ||
| 84 | */ | ||
| 85 | struct orc_entry { | ||
| 86 | s16 sp_offset; | ||
| 87 | s16 bp_offset; | ||
| 88 | unsigned sp_reg:4; | ||
| 89 | unsigned bp_reg:4; | ||
| 90 | unsigned type:2; | ||
| 91 | } __packed; | ||
| 92 | |||
| 93 | /* | ||
| 94 | * This struct is used by asm and inline asm code to manually annotate the | ||
| 95 | * location of registers on the stack for the ORC unwinder. | ||
| 96 | * | ||
| 97 | * Type can be either ORC_TYPE_* or UNWIND_HINT_TYPE_*. | ||
| 98 | */ | ||
| 99 | struct unwind_hint { | ||
| 100 | u32 ip; | ||
| 101 | s16 sp_offset; | ||
| 102 | u8 sp_reg; | ||
| 103 | u8 type; | ||
| 104 | }; | ||
| 105 | #endif /* __ASSEMBLY__ */ | ||
| 106 | |||
| 107 | #endif /* _ORC_TYPES_H */ | ||
