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

Configure Feed

Select the types of activity you want to include in your feed.

objtool: Improve error handling

Fix some error handling issues, improve error messages, properly
distinguish betwee errors and warnings, and generally try to make all
the error handling more consistent.

Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Link: https://lore.kernel.org/r/3094bb4463dad29b6bd1bea03848d1571ace771c.1742852846.git.jpoimboe@kernel.org

authored by

Josh Poimboeuf and committed by
Ingo Molnar
c5995abe e1a9dda7

+232 -221
+17 -20
tools/objtool/builtin-check.c
··· 8 8 #include <stdlib.h> 9 9 #include <fcntl.h> 10 10 #include <unistd.h> 11 + #include <errno.h> 11 12 #include <sys/stat.h> 12 13 #include <sys/sendfile.h> 13 14 #include <objtool/builtin.h> 14 15 #include <objtool/objtool.h> 15 - 16 - #define ERROR(format, ...) \ 17 - fprintf(stderr, \ 18 - "error: objtool: " format "\n", \ 19 - ##__VA_ARGS__) 16 + #include <objtool/warn.h> 20 17 21 18 const char *objname; 22 19 ··· 136 139 static bool opts_valid(void) 137 140 { 138 141 if (opts.mnop && !opts.mcount) { 139 - ERROR("--mnop requires --mcount"); 142 + WARN("--mnop requires --mcount"); 140 143 return false; 141 144 } 142 145 143 146 if (opts.noinstr && !opts.link) { 144 - ERROR("--noinstr requires --link"); 147 + WARN("--noinstr requires --link"); 145 148 return false; 146 149 } 147 150 148 151 if (opts.ibt && !opts.link) { 149 - ERROR("--ibt requires --link"); 152 + WARN("--ibt requires --link"); 150 153 return false; 151 154 } 152 155 153 156 if (opts.unret && !opts.link) { 154 - ERROR("--unret requires --link"); 157 + WARN("--unret requires --link"); 155 158 return false; 156 159 } 157 160 ··· 168 171 opts.static_call || 169 172 opts.uaccess) { 170 173 if (opts.dump_orc) { 171 - ERROR("--dump can't be combined with other actions"); 174 + WARN("--dump can't be combined with other actions"); 172 175 return false; 173 176 } 174 177 ··· 178 181 if (opts.dump_orc) 179 182 return true; 180 183 181 - ERROR("At least one action required"); 184 + WARN("At least one action required"); 182 185 return false; 183 186 } 184 187 ··· 191 194 192 195 src_fd = open(src, O_RDONLY); 193 196 if (src_fd == -1) { 194 - ERROR("can't open '%s' for reading", src); 197 + WARN("can't open %s for reading: %s", src, strerror(errno)); 195 198 return 1; 196 199 } 197 200 198 201 dst_fd = open(dst, O_WRONLY | O_CREAT | O_TRUNC, 0400); 199 202 if (dst_fd == -1) { 200 - ERROR("can't open '%s' for writing", dst); 203 + WARN("can't open %s for writing: %s", dst, strerror(errno)); 201 204 return 1; 202 205 } 203 206 204 207 if (fstat(src_fd, &stat) == -1) { 205 - perror("fstat"); 208 + WARN_GLIBC("fstat"); 206 209 return 1; 207 210 } 208 211 209 212 if (fchmod(dst_fd, stat.st_mode) == -1) { 210 - perror("fchmod"); 213 + WARN_GLIBC("fchmod"); 211 214 return 1; 212 215 } 213 216 214 217 for (to_copy = stat.st_size; to_copy > 0; to_copy -= copied) { 215 218 copied = sendfile(dst_fd, src_fd, &offset, to_copy); 216 219 if (copied == -1) { 217 - perror("sendfile"); 220 + WARN_GLIBC("sendfile"); 218 221 return 1; 219 222 } 220 223 } ··· 230 233 231 234 orig_argv = calloc(argc, sizeof(char *)); 232 235 if (!orig_argv) { 233 - perror("calloc"); 236 + WARN_GLIBC("calloc"); 234 237 return NULL; 235 238 } 236 239 237 240 for (int i = 0; i < argc; i++) { 238 241 orig_argv[i] = strdup(argv[i]); 239 242 if (!orig_argv[i]) { 240 - perror("strdup"); 243 + WARN_GLIBC("strdup(%s)", orig_argv[i]); 241 244 return NULL; 242 245 } 243 246 }; ··· 282 285 goto err; 283 286 284 287 if (!opts.link && has_multiple_files(file->elf)) { 285 - ERROR("Linked object requires --link"); 288 + WARN("Linked object requires --link"); 286 289 goto err; 287 290 } 288 291 ··· 310 313 */ 311 314 backup = malloc(strlen(objname) + strlen(ORIG_SUFFIX) + 1); 312 315 if (!backup) { 313 - perror("malloc"); 316 + WARN_GLIBC("malloc"); 314 317 return 1; 315 318 } 316 319
+188 -180
tools/objtool/check.c
··· 353 353 { 354 354 struct cfi_state *cfi = calloc(1, sizeof(struct cfi_state)); 355 355 if (!cfi) { 356 - WARN("calloc failed"); 356 + WARN_GLIBC("calloc"); 357 357 exit(1); 358 358 } 359 359 nr_cfi++; ··· 409 409 PROT_READ|PROT_WRITE, 410 410 MAP_PRIVATE|MAP_ANON, -1, 0); 411 411 if (cfi_hash == (void *)-1L) { 412 - WARN("mmap fail cfi_hash"); 412 + WARN_GLIBC("mmap fail cfi_hash"); 413 413 cfi_hash = NULL; 414 414 } else if (opts.stats) { 415 415 printf("cfi_bits: %d\n", cfi_bits); ··· 465 465 if (!insns || idx == INSN_CHUNK_MAX) { 466 466 insns = calloc(sizeof(*insn), INSN_CHUNK_SIZE); 467 467 if (!insns) { 468 - WARN("malloc failed"); 468 + WARN_GLIBC("calloc"); 469 469 return -1; 470 470 } 471 471 idx = 0; ··· 567 567 if (!reloc) 568 568 break; 569 569 570 + idx = (reloc_offset(reloc) - sym->offset) / sizeof(unsigned long); 571 + 570 572 func = reloc->sym; 571 573 if (func->type == STT_SECTION) 572 574 func = find_symbol_by_offset(reloc->sym->sec, 573 575 reloc_addend(reloc)); 576 + if (!func) { 577 + WARN_FUNC("can't find func at %s[%d]", 578 + reloc->sym->sec, reloc_addend(reloc), 579 + symname, idx); 580 + return -1; 581 + } 574 582 575 - idx = (reloc_offset(reloc) - sym->offset) / sizeof(unsigned long); 576 - 577 - objtool_pv_add(file, idx, func); 583 + if (objtool_pv_add(file, idx, func)) 584 + return -1; 578 585 579 586 off = reloc_offset(reloc) + 1; 580 587 if (off > end) ··· 605 598 }; 606 599 const char *pv_ops; 607 600 struct symbol *sym; 608 - int idx, nr; 601 + int idx, nr, ret; 609 602 610 603 if (!opts.noinstr) 611 604 return 0; ··· 618 611 619 612 nr = sym->len / sizeof(unsigned long); 620 613 file->pv_ops = calloc(sizeof(struct pv_state), nr); 621 - if (!file->pv_ops) 614 + if (!file->pv_ops) { 615 + WARN_GLIBC("calloc"); 622 616 return -1; 617 + } 623 618 624 619 for (idx = 0; idx < nr; idx++) 625 620 INIT_LIST_HEAD(&file->pv_ops[idx].targets); 626 621 627 - for (idx = 0; (pv_ops = pv_ops_tables[idx]); idx++) 628 - add_pv_ops(file, pv_ops); 622 + for (idx = 0; (pv_ops = pv_ops_tables[idx]); idx++) { 623 + ret = add_pv_ops(file, pv_ops); 624 + if (ret) 625 + return ret; 626 + } 629 627 630 628 return 0; 631 629 } ··· 678 666 /* find key symbol */ 679 667 key_name = strdup(insn_call_dest(insn)->name); 680 668 if (!key_name) { 681 - perror("strdup"); 669 + WARN_GLIBC("strdup"); 682 670 return -1; 683 671 } 684 672 if (strncmp(key_name, STATIC_CALL_TRAMP_PREFIX_STR, 685 673 STATIC_CALL_TRAMP_PREFIX_LEN)) { 686 674 WARN("static_call: trampoline name malformed: %s", key_name); 687 - free(key_name); 688 675 return -1; 689 676 } 690 677 tmp = key_name + STATIC_CALL_TRAMP_PREFIX_LEN - STATIC_CALL_KEY_PREFIX_LEN; ··· 693 682 if (!key_sym) { 694 683 if (!opts.module) { 695 684 WARN("static_call: can't find static_call_key symbol: %s", tmp); 696 - free(key_name); 697 685 return -1; 698 686 } 699 687 ··· 707 697 */ 708 698 key_sym = insn_call_dest(insn); 709 699 } 710 - free(key_name); 711 700 712 701 /* populate reloc for 'key' */ 713 702 if (!elf_init_reloc_data_sym(file->elf, sec, ··· 990 981 /* 991 982 * Warnings shouldn't be reported for ignored functions. 992 983 */ 993 - static void add_ignores(struct objtool_file *file) 984 + static int add_ignores(struct objtool_file *file) 994 985 { 995 986 struct section *rsec; 996 987 struct symbol *func; ··· 998 989 999 990 rsec = find_section_by_name(file->elf, ".rela.discard.func_stack_frame_non_standard"); 1000 991 if (!rsec) 1001 - return; 992 + return 0; 1002 993 1003 994 for_each_reloc(rsec, reloc) { 1004 995 switch (reloc->sym->type) { ··· 1015 1006 default: 1016 1007 WARN("unexpected relocation symbol type in %s: %d", 1017 1008 rsec->name, reloc->sym->type); 1018 - continue; 1009 + return -1; 1019 1010 } 1020 1011 1021 1012 func->ignore = true; 1022 1013 } 1014 + 1015 + return 0; 1023 1016 } 1024 1017 1025 1018 /* ··· 1286 1275 insn->stack_ops = NULL; 1287 1276 } 1288 1277 1289 - static void annotate_call_site(struct objtool_file *file, 1278 + static int annotate_call_site(struct objtool_file *file, 1290 1279 struct instruction *insn, bool sibling) 1291 1280 { 1292 1281 struct reloc *reloc = insn_reloc(file, insn); ··· 1297 1286 1298 1287 if (sym->static_call_tramp) { 1299 1288 list_add_tail(&insn->call_node, &file->static_call_list); 1300 - return; 1289 + return 0; 1301 1290 } 1302 1291 1303 1292 if (sym->retpoline_thunk) { 1304 1293 list_add_tail(&insn->call_node, &file->retpoline_call_list); 1305 - return; 1294 + return 0; 1306 1295 } 1307 1296 1308 1297 /* ··· 1314 1303 if (reloc) 1315 1304 set_reloc_type(file->elf, reloc, R_NONE); 1316 1305 1317 - elf_write_insn(file->elf, insn->sec, 1318 - insn->offset, insn->len, 1319 - sibling ? arch_ret_insn(insn->len) 1320 - : arch_nop_insn(insn->len)); 1306 + if (elf_write_insn(file->elf, insn->sec, 1307 + insn->offset, insn->len, 1308 + sibling ? arch_ret_insn(insn->len) 1309 + : arch_nop_insn(insn->len))) { 1310 + return -1; 1311 + } 1321 1312 1322 1313 insn->type = sibling ? INSN_RETURN : INSN_NOP; 1323 1314 ··· 1333 1320 insn->retpoline_safe = true; 1334 1321 } 1335 1322 1336 - return; 1323 + return 0; 1337 1324 } 1338 1325 1339 1326 if (opts.mcount && sym->fentry) { ··· 1343 1330 if (reloc) 1344 1331 set_reloc_type(file->elf, reloc, R_NONE); 1345 1332 1346 - elf_write_insn(file->elf, insn->sec, 1347 - insn->offset, insn->len, 1348 - arch_nop_insn(insn->len)); 1333 + if (elf_write_insn(file->elf, insn->sec, 1334 + insn->offset, insn->len, 1335 + arch_nop_insn(insn->len))) { 1336 + return -1; 1337 + } 1349 1338 1350 1339 insn->type = INSN_NOP; 1351 1340 } 1352 1341 1353 1342 list_add_tail(&insn->call_node, &file->mcount_loc_list); 1354 - return; 1343 + return 0; 1355 1344 } 1356 1345 1357 1346 if (insn->type == INSN_CALL && !insn->sec->init && ··· 1362 1347 1363 1348 if (!sibling && dead_end_function(file, sym)) 1364 1349 insn->dead_end = true; 1350 + 1351 + return 0; 1365 1352 } 1366 1353 1367 - static void add_call_dest(struct objtool_file *file, struct instruction *insn, 1354 + static int add_call_dest(struct objtool_file *file, struct instruction *insn, 1368 1355 struct symbol *dest, bool sibling) 1369 1356 { 1370 1357 insn->_call_dest = dest; 1371 1358 if (!dest) 1372 - return; 1359 + return 0; 1373 1360 1374 1361 /* 1375 1362 * Whatever stack impact regular CALLs have, should be undone ··· 1382 1365 */ 1383 1366 remove_insn_ops(insn); 1384 1367 1385 - annotate_call_site(file, insn, sibling); 1368 + return annotate_call_site(file, insn, sibling); 1386 1369 } 1387 1370 1388 - static void add_retpoline_call(struct objtool_file *file, struct instruction *insn) 1371 + static int add_retpoline_call(struct objtool_file *file, struct instruction *insn) 1389 1372 { 1390 1373 /* 1391 1374 * Retpoline calls/jumps are really dynamic calls/jumps in disguise, ··· 1402 1385 insn->type = INSN_JUMP_DYNAMIC_CONDITIONAL; 1403 1386 break; 1404 1387 default: 1405 - return; 1388 + return 0; 1406 1389 } 1407 1390 1408 1391 insn->retpoline_safe = true; ··· 1416 1399 */ 1417 1400 remove_insn_ops(insn); 1418 1401 1419 - annotate_call_site(file, insn, false); 1402 + return annotate_call_site(file, insn, false); 1420 1403 } 1421 1404 1422 1405 static void add_return_call(struct objtool_file *file, struct instruction *insn, bool add) ··· 1485 1468 struct reloc *reloc; 1486 1469 struct section *dest_sec; 1487 1470 unsigned long dest_off; 1471 + int ret; 1488 1472 1489 1473 for_each_insn(file, insn) { 1490 1474 if (insn->jump_dest) { ··· 1506 1488 dest_sec = reloc->sym->sec; 1507 1489 dest_off = arch_dest_reloc_offset(reloc_addend(reloc)); 1508 1490 } else if (reloc->sym->retpoline_thunk) { 1509 - add_retpoline_call(file, insn); 1491 + ret = add_retpoline_call(file, insn); 1492 + if (ret) 1493 + return ret; 1510 1494 continue; 1511 1495 } else if (reloc->sym->return_thunk) { 1512 1496 add_return_call(file, insn, true); ··· 1518 1498 * External sibling call or internal sibling call with 1519 1499 * STT_FUNC reloc. 1520 1500 */ 1521 - add_call_dest(file, insn, reloc->sym, true); 1501 + ret = add_call_dest(file, insn, reloc->sym, true); 1502 + if (ret) 1503 + return ret; 1522 1504 continue; 1523 1505 } else if (reloc->sym->sec->idx) { 1524 1506 dest_sec = reloc->sym->sec; ··· 1560 1538 */ 1561 1539 if (jump_dest->sym && jump_dest->offset == jump_dest->sym->offset) { 1562 1540 if (jump_dest->sym->retpoline_thunk) { 1563 - add_retpoline_call(file, insn); 1541 + ret = add_retpoline_call(file, insn); 1542 + if (ret) 1543 + return ret; 1564 1544 continue; 1565 1545 } 1566 1546 if (jump_dest->sym->return_thunk) { ··· 1604 1580 * Internal sibling call without reloc or with 1605 1581 * STT_SECTION reloc. 1606 1582 */ 1607 - add_call_dest(file, insn, insn_func(jump_dest), true); 1583 + ret = add_call_dest(file, insn, insn_func(jump_dest), true); 1584 + if (ret) 1585 + return ret; 1608 1586 continue; 1609 1587 } 1610 1588 ··· 1636 1610 unsigned long dest_off; 1637 1611 struct symbol *dest; 1638 1612 struct reloc *reloc; 1613 + int ret; 1639 1614 1640 1615 for_each_insn(file, insn) { 1641 1616 struct symbol *func = insn_func(insn); ··· 1648 1621 dest_off = arch_jump_destination(insn); 1649 1622 dest = find_call_destination(insn->sec, dest_off); 1650 1623 1651 - add_call_dest(file, insn, dest, false); 1624 + ret = add_call_dest(file, insn, dest, false); 1625 + if (ret) 1626 + return ret; 1652 1627 1653 1628 if (func && func->ignore) 1654 1629 continue; ··· 1674 1645 return -1; 1675 1646 } 1676 1647 1677 - add_call_dest(file, insn, dest, false); 1648 + ret = add_call_dest(file, insn, dest, false); 1649 + if (ret) 1650 + return ret; 1678 1651 1679 1652 } else if (reloc->sym->retpoline_thunk) { 1680 - add_retpoline_call(file, insn); 1653 + ret = add_retpoline_call(file, insn); 1654 + if (ret) 1655 + return ret; 1681 1656 1682 - } else 1683 - add_call_dest(file, insn, reloc->sym, false); 1657 + } else { 1658 + ret = add_call_dest(file, insn, reloc->sym, false); 1659 + if (ret) 1660 + return ret; 1661 + } 1684 1662 } 1685 1663 1686 1664 return 0; ··· 1710 1674 if (!orig_alt_group) { 1711 1675 struct instruction *last_orig_insn = NULL; 1712 1676 1713 - orig_alt_group = malloc(sizeof(*orig_alt_group)); 1677 + orig_alt_group = calloc(1, sizeof(*orig_alt_group)); 1714 1678 if (!orig_alt_group) { 1715 - WARN("malloc failed"); 1679 + WARN_GLIBC("calloc"); 1716 1680 return -1; 1717 1681 } 1718 1682 orig_alt_group->cfi = calloc(special_alt->orig_len, 1719 1683 sizeof(struct cfi_state *)); 1720 1684 if (!orig_alt_group->cfi) { 1721 - WARN("calloc failed"); 1685 + WARN_GLIBC("calloc"); 1722 1686 return -1; 1723 1687 } 1724 1688 ··· 1747 1711 } 1748 1712 } 1749 1713 1750 - new_alt_group = malloc(sizeof(*new_alt_group)); 1714 + new_alt_group = calloc(1, sizeof(*new_alt_group)); 1751 1715 if (!new_alt_group) { 1752 - WARN("malloc failed"); 1716 + WARN_GLIBC("calloc"); 1753 1717 return -1; 1754 1718 } 1755 1719 ··· 1761 1725 * instruction affects the stack, the instruction after it (the 1762 1726 * nop) will propagate the new state to the shared CFI array. 1763 1727 */ 1764 - nop = malloc(sizeof(*nop)); 1728 + nop = calloc(1, sizeof(*nop)); 1765 1729 if (!nop) { 1766 - WARN("malloc failed"); 1730 + WARN_GLIBC("calloc"); 1767 1731 return -1; 1768 1732 } 1769 1733 memset(nop, 0, sizeof(*nop)); ··· 1863 1827 1864 1828 if (reloc) 1865 1829 set_reloc_type(file->elf, reloc, R_NONE); 1866 - elf_write_insn(file->elf, orig_insn->sec, 1867 - orig_insn->offset, orig_insn->len, 1868 - arch_nop_insn(orig_insn->len)); 1830 + 1831 + if (elf_write_insn(file->elf, orig_insn->sec, 1832 + orig_insn->offset, orig_insn->len, 1833 + arch_nop_insn(orig_insn->len))) { 1834 + return -1; 1835 + } 1836 + 1869 1837 orig_insn->type = INSN_NOP; 1870 1838 } 1871 1839 ··· 1905 1865 struct alternative *alt; 1906 1866 int ret; 1907 1867 1908 - ret = special_get_alts(file->elf, &special_alts); 1909 - if (ret) 1910 - return ret; 1868 + if (special_get_alts(file->elf, &special_alts)) 1869 + return -1; 1911 1870 1912 1871 list_for_each_entry_safe(special_alt, tmp, &special_alts, list) { 1913 1872 ··· 1915 1876 if (!orig_insn) { 1916 1877 WARN_FUNC("special: can't find orig instruction", 1917 1878 special_alt->orig_sec, special_alt->orig_off); 1918 - ret = -1; 1919 - goto out; 1879 + return -1; 1920 1880 } 1921 1881 1922 1882 new_insn = NULL; ··· 1926 1888 WARN_FUNC("special: can't find new instruction", 1927 1889 special_alt->new_sec, 1928 1890 special_alt->new_off); 1929 - ret = -1; 1930 - goto out; 1891 + return -1; 1931 1892 } 1932 1893 } 1933 1894 ··· 1939 1902 ret = handle_group_alt(file, special_alt, orig_insn, 1940 1903 &new_insn); 1941 1904 if (ret) 1942 - goto out; 1905 + return ret; 1906 + 1943 1907 } else if (special_alt->jump_or_nop) { 1944 1908 ret = handle_jump_alt(file, special_alt, orig_insn, 1945 1909 &new_insn); 1946 1910 if (ret) 1947 - goto out; 1911 + return ret; 1948 1912 } 1949 1913 1950 - alt = malloc(sizeof(*alt)); 1914 + alt = calloc(1, sizeof(*alt)); 1951 1915 if (!alt) { 1952 - WARN("malloc failed"); 1953 - ret = -1; 1954 - goto out; 1916 + WARN_GLIBC("calloc"); 1917 + return -1; 1955 1918 } 1956 1919 1957 1920 alt->insn = new_insn; ··· 1968 1931 printf("long:\t%ld\t%ld\n", file->jl_nop_long, file->jl_long); 1969 1932 } 1970 1933 1971 - out: 1972 - return ret; 1934 + return 0; 1973 1935 } 1974 1936 1975 1937 __weak unsigned long arch_jump_table_sym_offset(struct reloc *reloc, struct reloc *table) ··· 2025 1989 if (!insn_func(dest_insn) || insn_func(dest_insn)->pfunc != pfunc) 2026 1990 break; 2027 1991 2028 - alt = malloc(sizeof(*alt)); 1992 + alt = calloc(1, sizeof(*alt)); 2029 1993 if (!alt) { 2030 - WARN("malloc failed"); 1994 + WARN_GLIBC("calloc"); 2031 1995 return -1; 2032 1996 } 2033 1997 ··· 2075 2039 insn->jump_dest && 2076 2040 (insn->jump_dest->offset <= insn->offset || 2077 2041 insn->jump_dest->offset > orig_insn->offset)) 2078 - break; 2042 + break; 2079 2043 2080 2044 table_reloc = arch_find_switch_table(file, insn, &table_size); 2081 2045 if (!table_reloc) ··· 2138 2102 func_for_each_insn(file, func, insn) { 2139 2103 if (!insn_jump_table(insn)) 2140 2104 continue; 2141 - 2142 2105 2143 2106 ret = add_jump_table(file, insn); 2144 2107 if (ret) ··· 2256 2221 if (sym && sym->bind == STB_GLOBAL) { 2257 2222 if (opts.ibt && insn->type != INSN_ENDBR && !insn->noendbr) { 2258 2223 WARN_INSN(insn, "UNWIND_HINT_IRET_REGS without ENDBR"); 2224 + return -1; 2259 2225 } 2260 2226 } 2261 2227 } ··· 2426 2390 2427 2391 default: 2428 2392 WARN_INSN(insn, "Unknown annotation type: %d", type); 2429 - break; 2393 + return -1; 2430 2394 } 2431 2395 2432 2396 return 0; ··· 2539 2503 if (ret) 2540 2504 return ret; 2541 2505 2542 - add_ignores(file); 2506 + ret = add_ignores(file); 2507 + if (ret) 2508 + return ret; 2509 + 2543 2510 add_uaccess_safe(file); 2544 2511 2545 2512 ret = read_annotate(file, __annotate_early); ··· 2762 2723 if (cfa->base == CFI_UNDEFINED) { 2763 2724 if (insn_func(insn)) { 2764 2725 WARN_INSN(insn, "undefined stack state"); 2765 - return -1; 2726 + return 1; 2766 2727 } 2767 2728 return 0; 2768 2729 } ··· 3205 3166 if (cficmp(alt_cfi[group_off], insn->cfi)) { 3206 3167 struct alt_group *orig_group = insn->alt_group->orig_group ?: insn->alt_group; 3207 3168 struct instruction *orig = orig_group->first_insn; 3208 - char *where = offstr(insn->sec, insn->offset); 3209 - WARN_INSN(orig, "stack layout conflict in alternatives: %s", where); 3210 - free(where); 3169 + WARN_INSN(orig, "stack layout conflict in alternatives: %s", 3170 + offstr(insn->sec, insn->offset)); 3211 3171 return -1; 3212 3172 } 3213 3173 } ··· 3219 3181 struct insn_state *state) 3220 3182 { 3221 3183 struct stack_op *op; 3184 + int ret; 3222 3185 3223 3186 for (op = insn->stack_ops; op; op = op->next) { 3224 3187 3225 - if (update_cfi_state(insn, next_insn, &state->cfi, op)) 3226 - return 1; 3188 + ret = update_cfi_state(insn, next_insn, &state->cfi, op); 3189 + if (ret) 3190 + return ret; 3227 3191 3228 3192 if (!opts.uaccess || !insn->alt_group) 3229 3193 continue; ··· 3269 3229 WARN_INSN(insn, "stack state mismatch: cfa1=%d%+d cfa2=%d%+d", 3270 3230 cfi1->cfa.base, cfi1->cfa.offset, 3271 3231 cfi2->cfa.base, cfi2->cfa.offset); 3232 + return false; 3272 3233 3273 - } else if (memcmp(&cfi1->regs, &cfi2->regs, sizeof(cfi1->regs))) { 3234 + } 3235 + 3236 + if (memcmp(&cfi1->regs, &cfi2->regs, sizeof(cfi1->regs))) { 3274 3237 for (i = 0; i < CFI_NUM_REGS; i++) { 3275 - if (!memcmp(&cfi1->regs[i], &cfi2->regs[i], 3276 - sizeof(struct cfi_reg))) 3238 + 3239 + if (!memcmp(&cfi1->regs[i], &cfi2->regs[i], sizeof(struct cfi_reg))) 3277 3240 continue; 3278 3241 3279 3242 WARN_INSN(insn, "stack state mismatch: reg1[%d]=%d%+d reg2[%d]=%d%+d", 3280 3243 i, cfi1->regs[i].base, cfi1->regs[i].offset, 3281 3244 i, cfi2->regs[i].base, cfi2->regs[i].offset); 3282 - break; 3283 3245 } 3246 + return false; 3247 + } 3284 3248 3285 - } else if (cfi1->type != cfi2->type) { 3249 + if (cfi1->type != cfi2->type) { 3286 3250 3287 3251 WARN_INSN(insn, "stack state mismatch: type1=%d type2=%d", 3288 3252 cfi1->type, cfi2->type); 3253 + return false; 3254 + } 3289 3255 3290 - } else if (cfi1->drap != cfi2->drap || 3256 + if (cfi1->drap != cfi2->drap || 3291 3257 (cfi1->drap && cfi1->drap_reg != cfi2->drap_reg) || 3292 3258 (cfi1->drap && cfi1->drap_offset != cfi2->drap_offset)) { 3293 3259 3294 3260 WARN_INSN(insn, "stack state mismatch: drap1=%d(%d,%d) drap2=%d(%d,%d)", 3295 3261 cfi1->drap, cfi1->drap_reg, cfi1->drap_offset, 3296 3262 cfi2->drap, cfi2->drap_reg, cfi2->drap_offset); 3263 + return false; 3264 + } 3297 3265 3298 - } else 3299 - return true; 3300 - 3301 - return false; 3266 + return true; 3302 3267 } 3303 3268 3304 3269 static inline bool func_uaccess_safe(struct symbol *func) ··· 3535 3490 3536 3491 WARN("%s() falls through to next function %s()", 3537 3492 func->name, insn_func(insn)->name); 3493 + func->warnings++; 3494 + 3538 3495 return 1; 3539 3496 } 3540 3497 ··· 3644 3597 return 1; 3645 3598 } 3646 3599 3647 - if (insn->dead_end) 3648 - return 0; 3649 - 3650 3600 break; 3651 3601 3652 3602 case INSN_JUMP_CONDITIONAL: ··· 3750 3706 if (file->ignore_unreachables) 3751 3707 return 0; 3752 3708 3753 - WARN("%s: unexpected end of section", sec->name); 3709 + WARN("%s%sunexpected end of section %s", 3710 + func ? func->name : "", func ? ": " : "", 3711 + sec->name); 3754 3712 return 1; 3755 3713 } 3756 3714 ··· 3842 3796 if (!is_sibling_call(insn)) { 3843 3797 if (!insn->jump_dest) { 3844 3798 WARN_INSN(insn, "unresolved jump target after linking?!?"); 3845 - return -1; 3799 + return 1; 3846 3800 } 3847 3801 ret = validate_unret(file, insn->jump_dest); 3848 3802 if (ret) { ··· 3864 3818 if (!dest) { 3865 3819 WARN("Unresolved function after linking!?: %s", 3866 3820 insn_call_dest(insn)->name); 3867 - return -1; 3821 + return 1; 3868 3822 } 3869 3823 3870 3824 ret = validate_unret(file, dest); ··· 3893 3847 3894 3848 if (!next) { 3895 3849 WARN_INSN(insn, "teh end!"); 3896 - return -1; 3850 + return 1; 3897 3851 } 3898 3852 insn = next; 3899 3853 } ··· 3908 3862 static int validate_unrets(struct objtool_file *file) 3909 3863 { 3910 3864 struct instruction *insn; 3911 - int ret, warnings = 0; 3865 + int warnings = 0; 3912 3866 3913 3867 for_each_insn(file, insn) { 3914 3868 if (!insn->unret) 3915 3869 continue; 3916 3870 3917 - ret = validate_unret(file, insn); 3918 - if (ret < 0) { 3919 - WARN_INSN(insn, "Failed UNRET validation"); 3920 - return ret; 3921 - } 3922 - warnings += ret; 3871 + warnings += validate_unret(file, insn); 3923 3872 } 3924 3873 3925 3874 return warnings; ··· 3940 3899 if (insn->type == INSN_RETURN) { 3941 3900 if (opts.rethunk) { 3942 3901 WARN_INSN(insn, "'naked' return found in MITIGATION_RETHUNK build"); 3943 - } else 3944 - continue; 3945 - } else { 3946 - WARN_INSN(insn, "indirect %s found in MITIGATION_RETPOLINE build", 3947 - insn->type == INSN_JUMP_DYNAMIC ? "jump" : "call"); 3902 + warnings++; 3903 + } 3904 + continue; 3948 3905 } 3949 3906 3907 + WARN_INSN(insn, "indirect %s found in MITIGATION_RETPOLINE build", 3908 + insn->type == INSN_JUMP_DYNAMIC ? "jump" : "call"); 3950 3909 warnings++; 3951 3910 } 3952 3911 ··· 4513 4472 } 4514 4473 4515 4474 /* 'funcs' is a space-separated list of function names */ 4516 - static int disas_funcs(const char *funcs) 4475 + static void disas_funcs(const char *funcs) 4517 4476 { 4518 4477 const char *objdump_str, *cross_compile; 4519 4478 int size, ret; ··· 4546 4505 size = snprintf(NULL, 0, objdump_str, cross_compile, objname, funcs) + 1; 4547 4506 if (size <= 0) { 4548 4507 WARN("objdump string size calculation failed"); 4549 - return -1; 4508 + return; 4550 4509 } 4551 4510 4552 4511 cmd = malloc(size); ··· 4556 4515 ret = system(cmd); 4557 4516 if (ret) { 4558 4517 WARN("disassembly failed: %d", ret); 4559 - return -1; 4518 + return; 4560 4519 } 4561 - 4562 - return 0; 4563 4520 } 4564 4521 4565 - static int disas_warned_funcs(struct objtool_file *file) 4522 + static void disas_warned_funcs(struct objtool_file *file) 4566 4523 { 4567 4524 struct symbol *sym; 4568 4525 char *funcs = NULL, *tmp; ··· 4569 4530 if (sym->warnings) { 4570 4531 if (!funcs) { 4571 4532 funcs = malloc(strlen(sym->name) + 1); 4533 + if (!funcs) { 4534 + WARN_GLIBC("malloc"); 4535 + return; 4536 + } 4572 4537 strcpy(funcs, sym->name); 4573 4538 } else { 4574 4539 tmp = malloc(strlen(funcs) + strlen(sym->name) + 2); 4540 + if (!tmp) { 4541 + WARN_GLIBC("malloc"); 4542 + return; 4543 + } 4575 4544 sprintf(tmp, "%s %s", funcs, sym->name); 4576 4545 free(funcs); 4577 4546 funcs = tmp; ··· 4589 4542 4590 4543 if (funcs) 4591 4544 disas_funcs(funcs); 4592 - 4593 - return 0; 4594 4545 } 4595 4546 4596 4547 struct insn_chunk { ··· 4621 4576 4622 4577 int check(struct objtool_file *file) 4623 4578 { 4624 - int ret, warnings = 0; 4579 + int ret = 0, warnings = 0; 4625 4580 4626 4581 arch_initial_func_cfi_state(&initial_func_cfi); 4627 4582 init_cfi_state(&init_cfi); ··· 4639 4594 cfi_hash_add(&func_cfi); 4640 4595 4641 4596 ret = decode_sections(file); 4642 - if (ret < 0) 4597 + if (ret) 4643 4598 goto out; 4644 - 4645 - warnings += ret; 4646 4599 4647 4600 if (!nr_insns) 4648 4601 goto out; 4649 4602 4650 - if (opts.retpoline) { 4651 - ret = validate_retpoline(file); 4652 - if (ret < 0) 4653 - goto out; 4654 - warnings += ret; 4655 - } 4603 + if (opts.retpoline) 4604 + warnings += validate_retpoline(file); 4656 4605 4657 4606 if (opts.stackval || opts.orc || opts.uaccess) { 4658 - ret = validate_functions(file); 4659 - if (ret < 0) 4660 - goto out; 4661 - warnings += ret; 4607 + int w = 0; 4662 4608 4663 - ret = validate_unwind_hints(file, NULL); 4664 - if (ret < 0) 4665 - goto out; 4666 - warnings += ret; 4609 + w += validate_functions(file); 4610 + w += validate_unwind_hints(file, NULL); 4611 + if (!w) 4612 + w += validate_reachable_instructions(file); 4667 4613 4668 - if (!warnings) { 4669 - ret = validate_reachable_instructions(file); 4670 - if (ret < 0) 4671 - goto out; 4672 - warnings += ret; 4673 - } 4614 + warnings += w; 4674 4615 4675 4616 } else if (opts.noinstr) { 4676 - ret = validate_noinstr_sections(file); 4677 - if (ret < 0) 4678 - goto out; 4679 - warnings += ret; 4617 + warnings += validate_noinstr_sections(file); 4680 4618 } 4681 4619 4682 4620 if (opts.unret) { ··· 4667 4639 * Must be after validate_branch() and friends, it plays 4668 4640 * further games with insn->visited. 4669 4641 */ 4670 - ret = validate_unrets(file); 4671 - if (ret < 0) 4672 - goto out; 4673 - warnings += ret; 4642 + warnings += validate_unrets(file); 4674 4643 } 4675 4644 4676 - if (opts.ibt) { 4677 - ret = validate_ibt(file); 4678 - if (ret < 0) 4679 - goto out; 4680 - warnings += ret; 4681 - } 4645 + if (opts.ibt) 4646 + warnings += validate_ibt(file); 4682 4647 4683 - if (opts.sls) { 4684 - ret = validate_sls(file); 4685 - if (ret < 0) 4686 - goto out; 4687 - warnings += ret; 4688 - } 4648 + if (opts.sls) 4649 + warnings += validate_sls(file); 4689 4650 4690 4651 if (opts.static_call) { 4691 4652 ret = create_static_call_sections(file); 4692 - if (ret < 0) 4653 + if (ret) 4693 4654 goto out; 4694 - warnings += ret; 4695 4655 } 4696 4656 4697 4657 if (opts.retpoline) { 4698 4658 ret = create_retpoline_sites_sections(file); 4699 - if (ret < 0) 4659 + if (ret) 4700 4660 goto out; 4701 - warnings += ret; 4702 4661 } 4703 4662 4704 4663 if (opts.cfi) { 4705 4664 ret = create_cfi_sections(file); 4706 - if (ret < 0) 4665 + if (ret) 4707 4666 goto out; 4708 - warnings += ret; 4709 4667 } 4710 4668 4711 4669 if (opts.rethunk) { 4712 4670 ret = create_return_sites_sections(file); 4713 - if (ret < 0) 4671 + if (ret) 4714 4672 goto out; 4715 - warnings += ret; 4716 4673 4717 4674 if (opts.hack_skylake) { 4718 4675 ret = create_direct_call_sections(file); 4719 - if (ret < 0) 4676 + if (ret) 4720 4677 goto out; 4721 - warnings += ret; 4722 4678 } 4723 4679 } 4724 4680 4725 4681 if (opts.mcount) { 4726 4682 ret = create_mcount_loc_sections(file); 4727 - if (ret < 0) 4683 + if (ret) 4728 4684 goto out; 4729 - warnings += ret; 4730 4685 } 4731 4686 4732 4687 if (opts.prefix) { 4733 4688 ret = add_prefix_symbols(file); 4734 - if (ret < 0) 4689 + if (ret) 4735 4690 goto out; 4736 - warnings += ret; 4737 4691 } 4738 4692 4739 4693 if (opts.ibt) { 4740 4694 ret = create_ibt_endbr_seal_sections(file); 4741 - if (ret < 0) 4695 + if (ret) 4742 4696 goto out; 4743 - warnings += ret; 4744 4697 } 4745 4698 4746 4699 if (opts.orc && nr_insns) { 4747 4700 ret = orc_create(file); 4748 - if (ret < 0) 4701 + if (ret) 4749 4702 goto out; 4750 - warnings += ret; 4751 4703 } 4752 4704 4753 4705 free_insns(file);
+11 -11
tools/objtool/elf.c
··· 331 331 332 332 elf->section_data = calloc(sections_nr, sizeof(*sec)); 333 333 if (!elf->section_data) { 334 - perror("calloc"); 334 + WARN_GLIBC("calloc"); 335 335 return -1; 336 336 } 337 337 for (i = 0; i < sections_nr; i++) { ··· 467 467 468 468 elf->symbol_data = calloc(symbols_nr, sizeof(*sym)); 469 469 if (!elf->symbol_data) { 470 - perror("calloc"); 470 + WARN_GLIBC("calloc"); 471 471 return -1; 472 472 } 473 473 for (i = 0; i < symbols_nr; i++) { ··· 799 799 struct symbol *sym = calloc(1, sizeof(*sym)); 800 800 801 801 if (!sym) { 802 - perror("malloc"); 802 + WARN_GLIBC("malloc"); 803 803 return NULL; 804 804 } 805 805 ··· 829 829 char *name = malloc(namelen); 830 830 831 831 if (!sym || !name) { 832 - perror("malloc"); 832 + WARN_GLIBC("malloc"); 833 833 return NULL; 834 834 } 835 835 ··· 963 963 nr_reloc = 0; 964 964 rsec->relocs = calloc(sec_num_entries(rsec), sizeof(*reloc)); 965 965 if (!rsec->relocs) { 966 - perror("calloc"); 966 + WARN_GLIBC("calloc"); 967 967 return -1; 968 968 } 969 969 for (i = 0; i < sec_num_entries(rsec); i++) { ··· 1005 1005 1006 1006 elf = malloc(sizeof(*elf)); 1007 1007 if (!elf) { 1008 - perror("malloc"); 1008 + WARN_GLIBC("malloc"); 1009 1009 return NULL; 1010 1010 } 1011 1011 memset(elf, 0, sizeof(*elf)); ··· 1099 1099 1100 1100 sec = malloc(sizeof(*sec)); 1101 1101 if (!sec) { 1102 - perror("malloc"); 1102 + WARN_GLIBC("malloc"); 1103 1103 return NULL; 1104 1104 } 1105 1105 memset(sec, 0, sizeof(*sec)); ··· 1114 1114 1115 1115 sec->name = strdup(name); 1116 1116 if (!sec->name) { 1117 - perror("strdup"); 1117 + WARN_GLIBC("strdup"); 1118 1118 return NULL; 1119 1119 } 1120 1120 ··· 1132 1132 if (size) { 1133 1133 sec->data->d_buf = malloc(size); 1134 1134 if (!sec->data->d_buf) { 1135 - perror("malloc"); 1135 + WARN_GLIBC("malloc"); 1136 1136 return NULL; 1137 1137 } 1138 1138 memset(sec->data->d_buf, 0, size); ··· 1179 1179 1180 1180 rsec_name = malloc(strlen(sec->name) + strlen(".rela") + 1); 1181 1181 if (!rsec_name) { 1182 - perror("malloc"); 1182 + WARN_GLIBC("malloc"); 1183 1183 return NULL; 1184 1184 } 1185 1185 strcpy(rsec_name, ".rela"); ··· 1199 1199 1200 1200 rsec->relocs = calloc(sec_num_entries(rsec), sizeof(struct reloc)); 1201 1201 if (!rsec->relocs) { 1202 - perror("calloc"); 1202 + WARN_GLIBC("calloc"); 1203 1203 return NULL; 1204 1204 } 1205 1205
+1 -1
tools/objtool/include/objtool/objtool.h
··· 41 41 42 42 struct objtool_file *objtool_open_read(const char *_objname); 43 43 44 - void objtool_pv_add(struct objtool_file *file, int idx, struct symbol *func); 44 + int objtool_pv_add(struct objtool_file *file, int idx, struct symbol *func); 45 45 46 46 int check(struct objtool_file *file); 47 47 int orc_dump(const char *objname);
+9 -4
tools/objtool/include/objtool/warn.h
··· 11 11 #include <sys/types.h> 12 12 #include <sys/stat.h> 13 13 #include <fcntl.h> 14 + #include <errno.h> 14 15 #include <objtool/builtin.h> 15 16 #include <objtool/elf.h> 16 17 ··· 44 43 45 44 #define WARN(format, ...) \ 46 45 fprintf(stderr, \ 47 - "%s: %s: objtool: " format "\n", \ 48 - objname, \ 46 + "%s%s%s: objtool: " format "\n", \ 47 + objname ?: "", \ 48 + objname ? ": " : "", \ 49 49 opts.werror ? "error" : "warning", \ 50 50 ##__VA_ARGS__) 51 51 ··· 85 83 } \ 86 84 }) 87 85 88 - #define WARN_ELF(format, ...) \ 89 - WARN(format ": %s", ##__VA_ARGS__, elf_errmsg(-1)) 86 + #define WARN_ELF(format, ...) \ 87 + WARN("%s: " format " failed: %s", __func__, ##__VA_ARGS__, elf_errmsg(-1)) 88 + 89 + #define WARN_GLIBC(format, ...) \ 90 + WARN("%s: " format " failed: %s", __func__, ##__VA_ARGS__, strerror(errno)) 90 91 91 92 #endif /* _WARN_H */
+6 -5
tools/objtool/objtool.c
··· 44 44 return &file; 45 45 } 46 46 47 - void objtool_pv_add(struct objtool_file *f, int idx, struct symbol *func) 47 + int objtool_pv_add(struct objtool_file *f, int idx, struct symbol *func) 48 48 { 49 49 if (!opts.noinstr) 50 - return; 50 + return 0; 51 51 52 52 if (!f->pv_ops) { 53 53 WARN("paravirt confusion"); 54 - return; 54 + return -1; 55 55 } 56 56 57 57 /* ··· 60 60 */ 61 61 if (!strcmp(func->name, "_paravirt_nop") || 62 62 !strcmp(func->name, "_paravirt_ident_64")) 63 - return; 63 + return 0; 64 64 65 65 /* already added this function */ 66 66 if (!list_empty(&func->pv_target)) 67 - return; 67 + return 0; 68 68 69 69 list_add(&func->pv_target, &f->pv_ops[idx].targets); 70 70 f->pv_ops[idx].clean = false; 71 + return 0; 71 72 } 72 73 73 74 int main(int argc, const char **argv)