Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

objtool: Add ORC unwind table generation

Now that objtool knows the states of all registers on the stack for each
instruction, it's straightforward to generate debuginfo for an unwinder
to use.

Instead of generating DWARF, generate a new format called ORC, which is
more suitable for an in-kernel unwinder. See
Documentation/x86/orc-unwinder.txt for a more detailed description of
this new debuginfo format and why it's preferable to DWARF.

Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: live-patching@vger.kernel.org
Link: http://lkml.kernel.org/r/c9b9f01ba6c5ed2bdc9bb0957b78167fdbf9632e.1499786555.git.jpoimboe@redhat.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>

authored by

Josh Poimboeuf and committed by
Ingo Molnar
627fce14 5a3cf869

+916 -60
+3
tools/objtool/Build
··· 1 1 objtool-y += arch/$(SRCARCH)/ 2 2 objtool-y += builtin-check.o 3 + objtool-y += builtin-orc.o 3 4 objtool-y += check.o 5 + objtool-y += orc_gen.o 6 + objtool-y += orc_dump.o 4 7 objtool-y += elf.o 5 8 objtool-y += special.o 6 9 objtool-y += objtool.o
+17 -39
tools/objtool/Documentation/stack-validation.txt
··· 11 11 It enforces a set of rules on asm code and C inline assembly code so 12 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 14 For each function, it recursively follows all possible code paths and 18 15 validates the correct frame pointer state at each instruction. 19 16 ··· 19 22 alternative execution paths to a given instruction (or set of 20 23 instructions). Similarly, it knows how to follow switch statements, for 21 24 which gcc sometimes uses jump tables. 25 + 26 + (Objtool also has an 'orc generate' subcommand which generates debuginfo 27 + for the ORC unwinder. See Documentation/x86/orc-unwinder.txt in the 28 + kernel tree for more details.) 22 29 23 30 24 31 Why do we need stack metadata validation? ··· 94 93 or at the very end of the function after the stack frame has been 95 94 destroyed. This is an inherent limitation of frame pointers. 96 95 97 - b) 100% reliable stack traces for DWARF enabled kernels 96 + b) ORC (Oops Rewind Capability) unwind table generation 98 97 99 - (NOTE: This is not yet implemented) 98 + An alternative to frame pointers and DWARF, ORC unwind data can be 99 + used to walk the stack. Unlike frame pointers, ORC data is out of 100 + band. So it doesn't affect runtime performance and it can be 101 + reliable even when interrupts or exceptions are involved. 100 102 101 - As an alternative to frame pointers, DWARF Call Frame Information 102 - (CFI) metadata can be used to walk the stack. Unlike frame pointers, 103 - CFI metadata is out of band. So it doesn't affect runtime 104 - performance and it can be reliable even when interrupts or exceptions 105 - are involved. 106 - 107 - For C code, gcc automatically generates DWARF CFI metadata. But for 108 - asm code, generating CFI is a tedious manual approach which requires 109 - manually placed .cfi assembler macros to be scattered throughout the 110 - code. It's clumsy and very easy to get wrong, and it makes the real 111 - code harder to read. 112 - 113 - Stacktool will improve this situation in several ways. For code 114 - which already has CFI annotations, it will validate them. For code 115 - which doesn't have CFI annotations, it will generate them. So an 116 - architecture can opt to strip out all the manual .cfi annotations 117 - from their asm code and have objtool generate them instead. 118 - 119 - We might also add a runtime stack validation debug option where we 120 - periodically walk the stack from schedule() and/or an NMI to ensure 121 - that the stack metadata is sane and that we reach the bottom of the 122 - stack. 123 - 124 - So the benefit of objtool here will be that external tooling should 125 - always show perfect stack traces. And the same will be true for 126 - kernel warning/oops traces if the architecture has a runtime DWARF 127 - unwinder. 103 + For more details, see Documentation/x86/orc-unwinder.txt. 128 104 129 105 c) Higher live patching compatibility rate 130 106 ··· 189 211 function, add proper frame pointer logic using the FRAME_BEGIN and 190 212 FRAME_END macros. Otherwise, if it's not a callable function, remove 191 213 its ELF function annotation by changing ENDPROC to END, and instead 192 - use the manual CFI hint macros in asm/undwarf.h. 214 + use the manual unwind hint macros in asm/unwind_hints.h. 193 215 194 216 If it's a GCC-compiled .c file, the error may be because the function 195 217 uses an inline asm() statement which has a "call" instruction. An ··· 209 231 If the error is for an asm file, and the instruction is inside (or 210 232 reachable from) a callable function, the function should be annotated 211 233 with the ENTRY/ENDPROC macros (ENDPROC is the important one). 212 - Otherwise, the code should probably be annotated with the CFI hint 213 - macros in asm/undwarf.h so objtool and the unwinder can know the 234 + Otherwise, the code should probably be annotated with the unwind hint 235 + macros in asm/unwind_hints.h so objtool and the unwinder can know the 214 236 stack state associated with the code. 215 237 216 238 If you're 100% sure the code won't affect stack traces, or if you're ··· 236 258 instructions aren't allowed in a callable function, and are most 237 259 likely part of the kernel entry code. They should usually not have 238 260 the callable function annotation (ENDPROC) and should always be 239 - annotated with the CFI hint macros in asm/undwarf.h. 261 + annotated with the unwind hint macros in asm/unwind_hints.h. 240 262 241 263 242 264 6. file.o: warning: objtool: func()+0x26: sibling call from callable instruction with modified stack frame ··· 250 272 251 273 If the instruction is not actually in a callable function (e.g. 252 274 kernel entry code), change ENDPROC to END and annotate manually with 253 - the CFI hint macros in asm/undwarf.h. 275 + the unwind hint macros in asm/unwind_hints.h. 254 276 255 277 256 278 7. file: warning: objtool: func()+0x5c: stack state mismatch ··· 266 288 267 289 Another possibility is that the code has some asm or inline asm which 268 290 does some unusual things to the stack or the frame pointer. In such 269 - cases it's probably appropriate to use the CFI hint macros in 270 - asm/undwarf.h. 291 + cases it's probably appropriate to use the unwind hint macros in 292 + asm/unwind_hints.h. 271 293 272 294 273 295 8. file.o: warning: objtool: funcA() falls through to next function funcB()
+1 -1
tools/objtool/builtin-check.c
··· 52 52 53 53 objname = argv[0]; 54 54 55 - return check(objname, nofp); 55 + return check(objname, nofp, false); 56 56 }
+70
tools/objtool/builtin-orc.c
··· 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 nofp; 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, nofp, 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 + }
+1
tools/objtool/builtin.h
··· 18 18 #define _BUILTIN_H 19 19 20 20 extern int cmd_check(int argc, const char **argv); 21 + extern int cmd_orc(int argc, const char **argv); 21 22 22 23 #endif /* _BUILTIN_H */
+54 -4
tools/objtool/check.c
··· 36 36 static bool nofp; 37 37 struct cfi_state initial_func_cfi; 38 38 39 - static struct instruction *find_insn(struct objtool_file *file, 40 - struct section *sec, unsigned long offset) 39 + struct instruction *find_insn(struct objtool_file *file, 40 + struct section *sec, unsigned long offset) 41 41 { 42 42 struct instruction *insn; 43 43 ··· 258 258 259 259 if (!(sec->sh.sh_flags & SHF_EXECINSTR)) 260 260 continue; 261 + 262 + if (strcmp(sec->name, ".altinstr_replacement") && 263 + strcmp(sec->name, ".altinstr_aux") && 264 + strncmp(sec->name, ".discard.", 9)) 265 + sec->text = true; 261 266 262 267 for (offset = 0; offset < sec->len; offset += insn->len) { 263 268 insn = malloc(sizeof(*insn)); ··· 952 947 return false; 953 948 } 954 949 950 + static int update_insn_state_regs(struct instruction *insn, struct insn_state *state) 951 + { 952 + struct cfi_reg *cfa = &state->cfa; 953 + struct stack_op *op = &insn->stack_op; 954 + 955 + if (cfa->base != CFI_SP) 956 + return 0; 957 + 958 + /* push */ 959 + if (op->dest.type == OP_DEST_PUSH) 960 + cfa->offset += 8; 961 + 962 + /* pop */ 963 + if (op->src.type == OP_SRC_POP) 964 + cfa->offset -= 8; 965 + 966 + /* add immediate to sp */ 967 + if (op->dest.type == OP_DEST_REG && op->src.type == OP_SRC_ADD && 968 + op->dest.reg == CFI_SP && op->src.reg == CFI_SP) 969 + cfa->offset -= op->src.offset; 970 + 971 + return 0; 972 + } 973 + 955 974 static void save_reg(struct insn_state *state, unsigned char reg, int base, 956 975 int offset) 957 976 { ··· 1060 1031 } 1061 1032 return 0; 1062 1033 } 1034 + 1035 + if (state->type == ORC_TYPE_REGS || state->type == ORC_TYPE_REGS_IRET) 1036 + return update_insn_state_regs(insn, state); 1063 1037 1064 1038 switch (op->dest.type) { 1065 1039 ··· 1355 1323 break; 1356 1324 } 1357 1325 1326 + } else if (state1->type != state2->type) { 1327 + WARN_FUNC("stack state mismatch: type1=%d type2=%d", 1328 + insn->sec, insn->offset, state1->type, state2->type); 1329 + 1358 1330 } else if (state1->drap != state2->drap || 1359 1331 (state1->drap && state1->drap_reg != state2->drap_reg)) { 1360 1332 WARN_FUNC("stack state mismatch: drap1=%d(%d) drap2=%d(%d)", ··· 1649 1613 elf_close(file->elf); 1650 1614 } 1651 1615 1652 - int check(const char *_objname, bool _nofp) 1616 + int check(const char *_objname, bool _nofp, bool orc) 1653 1617 { 1654 1618 struct objtool_file file; 1655 1619 int ret, warnings = 0; ··· 1657 1621 objname = _objname; 1658 1622 nofp = _nofp; 1659 1623 1660 - file.elf = elf_open(objname); 1624 + file.elf = elf_open(objname, orc ? O_RDWR : O_RDONLY); 1661 1625 if (!file.elf) 1662 1626 return 1; 1663 1627 ··· 1688 1652 if (ret < 0) 1689 1653 goto out; 1690 1654 warnings += ret; 1655 + } 1656 + 1657 + if (orc) { 1658 + ret = create_orc(&file); 1659 + if (ret < 0) 1660 + goto out; 1661 + 1662 + ret = create_orc_sections(&file); 1663 + if (ret < 0) 1664 + goto out; 1665 + 1666 + ret = elf_write(file.elf); 1667 + if (ret < 0) 1668 + goto out; 1691 1669 } 1692 1670 1693 1671 out:
+14 -1
tools/objtool/check.h
··· 22 22 #include "elf.h" 23 23 #include "cfi.h" 24 24 #include "arch.h" 25 + #include "orc.h" 25 26 #include <linux/hashtable.h> 26 27 27 28 struct insn_state { 28 29 struct cfi_reg cfa; 29 30 struct cfi_reg regs[CFI_NUM_REGS]; 30 31 int stack_size; 32 + unsigned char type; 31 33 bool bp_scratch; 32 34 bool drap; 33 35 int drap_reg; ··· 50 48 struct symbol *func; 51 49 struct stack_op stack_op; 52 50 struct insn_state state; 51 + struct orc_entry orc; 53 52 }; 54 53 55 54 struct objtool_file { ··· 61 58 bool ignore_unreachables, c_file; 62 59 }; 63 60 64 - int check(const char *objname, bool nofp); 61 + int check(const char *objname, bool nofp, bool orc); 62 + 63 + struct instruction *find_insn(struct objtool_file *file, 64 + struct section *sec, unsigned long offset); 65 65 66 66 #define for_each_insn(file, insn) \ 67 67 list_for_each_entry(insn, &file->insn_list, list) 68 + 69 + #define sec_for_each_insn(file, sec, insn) \ 70 + for (insn = find_insn(file, sec, 0); \ 71 + insn && &insn->list != &file->insn_list && \ 72 + insn->sec == sec; \ 73 + insn = list_next_entry(insn, list)) 74 + 68 75 69 76 #endif /* _CHECK_H */
+199 -13
tools/objtool/elf.c
··· 30 30 #include "elf.h" 31 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 33 struct section *find_section_by_name(struct elf *elf, const char *name) 44 34 { 45 35 struct section *sec; ··· 339 349 return 0; 340 350 } 341 351 342 - struct elf *elf_open(const char *name) 352 + struct elf *elf_open(const char *name, int flags) 343 353 { 344 354 struct elf *elf; 355 + Elf_Cmd cmd; 345 356 346 357 elf_version(EV_CURRENT); 347 358 ··· 355 364 356 365 INIT_LIST_HEAD(&elf->sections); 357 366 358 - elf->fd = open(name, O_RDONLY); 367 + elf->fd = open(name, flags); 359 368 if (elf->fd == -1) { 360 369 perror("open"); 361 370 goto err; 362 371 } 363 372 364 - elf->elf = elf_begin(elf->fd, ELF_C_READ_MMAP, NULL); 373 + if ((flags & O_ACCMODE) == O_RDONLY) 374 + cmd = ELF_C_READ_MMAP; 375 + else if ((flags & O_ACCMODE) == O_RDWR) 376 + cmd = ELF_C_RDWR; 377 + else /* O_WRONLY */ 378 + cmd = ELF_C_WRITE; 379 + 380 + elf->elf = elf_begin(elf->fd, cmd, NULL); 365 381 if (!elf->elf) { 366 382 WARN_ELF("elf_begin"); 367 383 goto err; ··· 393 395 err: 394 396 elf_close(elf); 395 397 return NULL; 398 + } 399 + 400 + struct section *elf_create_section(struct elf *elf, const char *name, 401 + size_t entsize, int nr) 402 + { 403 + struct section *sec, *shstrtab; 404 + size_t size = entsize * nr; 405 + struct Elf_Scn *s; 406 + Elf_Data *data; 407 + 408 + sec = malloc(sizeof(*sec)); 409 + if (!sec) { 410 + perror("malloc"); 411 + return NULL; 412 + } 413 + memset(sec, 0, sizeof(*sec)); 414 + 415 + INIT_LIST_HEAD(&sec->symbol_list); 416 + INIT_LIST_HEAD(&sec->rela_list); 417 + hash_init(sec->rela_hash); 418 + hash_init(sec->symbol_hash); 419 + 420 + list_add_tail(&sec->list, &elf->sections); 421 + 422 + s = elf_newscn(elf->elf); 423 + if (!s) { 424 + WARN_ELF("elf_newscn"); 425 + return NULL; 426 + } 427 + 428 + sec->name = strdup(name); 429 + if (!sec->name) { 430 + perror("strdup"); 431 + return NULL; 432 + } 433 + 434 + sec->idx = elf_ndxscn(s); 435 + sec->len = size; 436 + sec->changed = true; 437 + 438 + sec->data = elf_newdata(s); 439 + if (!sec->data) { 440 + WARN_ELF("elf_newdata"); 441 + return NULL; 442 + } 443 + 444 + sec->data->d_size = size; 445 + sec->data->d_align = 1; 446 + 447 + if (size) { 448 + sec->data->d_buf = malloc(size); 449 + if (!sec->data->d_buf) { 450 + perror("malloc"); 451 + return NULL; 452 + } 453 + memset(sec->data->d_buf, 0, size); 454 + } 455 + 456 + if (!gelf_getshdr(s, &sec->sh)) { 457 + WARN_ELF("gelf_getshdr"); 458 + return NULL; 459 + } 460 + 461 + sec->sh.sh_size = size; 462 + sec->sh.sh_entsize = entsize; 463 + sec->sh.sh_type = SHT_PROGBITS; 464 + sec->sh.sh_addralign = 1; 465 + sec->sh.sh_flags = SHF_ALLOC; 466 + 467 + 468 + /* Add section name to .shstrtab */ 469 + shstrtab = find_section_by_name(elf, ".shstrtab"); 470 + if (!shstrtab) { 471 + WARN("can't find .shstrtab section"); 472 + return NULL; 473 + } 474 + 475 + s = elf_getscn(elf->elf, shstrtab->idx); 476 + if (!s) { 477 + WARN_ELF("elf_getscn"); 478 + return NULL; 479 + } 480 + 481 + data = elf_newdata(s); 482 + if (!data) { 483 + WARN_ELF("elf_newdata"); 484 + return NULL; 485 + } 486 + 487 + data->d_buf = sec->name; 488 + data->d_size = strlen(name) + 1; 489 + data->d_align = 1; 490 + 491 + sec->sh.sh_name = shstrtab->len; 492 + 493 + shstrtab->len += strlen(name) + 1; 494 + shstrtab->changed = true; 495 + 496 + return sec; 497 + } 498 + 499 + struct section *elf_create_rela_section(struct elf *elf, struct section *base) 500 + { 501 + char *relaname; 502 + struct section *sec; 503 + 504 + relaname = malloc(strlen(base->name) + strlen(".rela") + 1); 505 + if (!relaname) { 506 + perror("malloc"); 507 + return NULL; 508 + } 509 + strcpy(relaname, ".rela"); 510 + strcat(relaname, base->name); 511 + 512 + sec = elf_create_section(elf, relaname, sizeof(GElf_Rela), 0); 513 + if (!sec) 514 + return NULL; 515 + 516 + base->rela = sec; 517 + sec->base = base; 518 + 519 + sec->sh.sh_type = SHT_RELA; 520 + sec->sh.sh_addralign = 8; 521 + sec->sh.sh_link = find_section_by_name(elf, ".symtab")->idx; 522 + sec->sh.sh_info = base->idx; 523 + sec->sh.sh_flags = SHF_INFO_LINK; 524 + 525 + return sec; 526 + } 527 + 528 + int elf_rebuild_rela_section(struct section *sec) 529 + { 530 + struct rela *rela; 531 + int nr, idx = 0, size; 532 + GElf_Rela *relas; 533 + 534 + nr = 0; 535 + list_for_each_entry(rela, &sec->rela_list, list) 536 + nr++; 537 + 538 + size = nr * sizeof(*relas); 539 + relas = malloc(size); 540 + if (!relas) { 541 + perror("malloc"); 542 + return -1; 543 + } 544 + 545 + sec->data->d_buf = relas; 546 + sec->data->d_size = size; 547 + 548 + sec->sh.sh_size = size; 549 + 550 + idx = 0; 551 + list_for_each_entry(rela, &sec->rela_list, list) { 552 + relas[idx].r_offset = rela->offset; 553 + relas[idx].r_addend = rela->addend; 554 + relas[idx].r_info = GELF_R_INFO(rela->sym->idx, rela->type); 555 + idx++; 556 + } 557 + 558 + return 0; 559 + } 560 + 561 + int elf_write(struct elf *elf) 562 + { 563 + struct section *sec; 564 + Elf_Scn *s; 565 + 566 + list_for_each_entry(sec, &elf->sections, list) { 567 + if (sec->changed) { 568 + s = elf_getscn(elf->elf, sec->idx); 569 + if (!s) { 570 + WARN_ELF("elf_getscn"); 571 + return -1; 572 + } 573 + if (!gelf_update_shdr (s, &sec->sh)) { 574 + WARN_ELF("gelf_update_shdr"); 575 + return -1; 576 + } 577 + } 578 + } 579 + 580 + if (elf_update(elf->elf, ELF_C_WRITE) < 0) { 581 + WARN_ELF("elf_update"); 582 + return -1; 583 + } 584 + 585 + return 0; 396 586 } 397 587 398 588 void elf_close(struct elf *elf)
+14 -1
tools/objtool/elf.h
··· 28 28 # define elf_getshdrstrndx elf_getshstrndx 29 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 38 struct section { 32 39 struct list_head list; 33 40 GElf_Shdr sh; ··· 48 41 char *name; 49 42 int idx; 50 43 unsigned int len; 44 + bool changed, text; 51 45 }; 52 46 53 47 struct symbol { ··· 83 75 }; 84 76 85 77 86 - struct elf *elf_open(const char *name); 78 + struct elf *elf_open(const char *name, int flags); 87 79 struct section *find_section_by_name(struct elf *elf, const char *name); 88 80 struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset); 89 81 struct symbol *find_symbol_containing(struct section *sec, unsigned long offset); ··· 91 83 struct rela *find_rela_by_dest_range(struct section *sec, unsigned long offset, 92 84 unsigned int len); 93 85 struct symbol *find_containing_func(struct section *sec, unsigned long offset); 86 + struct section *elf_create_section(struct elf *elf, const char *name, size_t 87 + entsize, int nr); 88 + struct section *elf_create_rela_section(struct elf *elf, struct section *base); 89 + int elf_rebuild_rela_section(struct section *sec); 90 + int elf_write(struct elf *elf); 94 91 void elf_close(struct elf *elf); 95 92 96 93 #define for_each_sec(file, sec) \
+2 -1
tools/objtool/objtool.c
··· 42 42 }; 43 43 44 44 static const char objtool_usage_string[] = 45 - "objtool [OPTIONS] COMMAND [ARGS]"; 45 + "objtool COMMAND [ARGS]"; 46 46 47 47 static struct cmd_struct objtool_cmds[] = { 48 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 52 bool help;
+30
tools/objtool/orc.h
··· 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 */
+212
tools/objtool/orc_dump.c
··· 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 + }
+214
tools/objtool/orc_gen.c
··· 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 + }
+85
tools/objtool/orc_types.h
··· 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 + #define ORC_TYPE_CALL 0 66 + #define ORC_TYPE_REGS 1 67 + #define ORC_TYPE_REGS_IRET 2 68 + 69 + /* 70 + * This struct is more or less a vastly simplified version of the DWARF Call 71 + * Frame Information standard. It contains only the necessary parts of DWARF 72 + * CFI, simplified for ease of access by the in-kernel unwinder. It tells the 73 + * unwinder how to find the previous SP and BP (and sometimes entry regs) on 74 + * the stack for a given code address. Each instance of the struct corresponds 75 + * to one or more code locations. 76 + */ 77 + struct orc_entry { 78 + s16 sp_offset; 79 + s16 bp_offset; 80 + unsigned sp_reg:4; 81 + unsigned bp_reg:4; 82 + unsigned type:2; 83 + } __packed; 84 + 85 + #endif /* _ORC_TYPES_H */