0034-objtool-x86-Add-facility-for-asm-code-to-provide-unw.patch 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641
  1. From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
  2. From: Josh Poimboeuf <[email protected]>
  3. Date: Tue, 11 Jul 2017 10:33:43 -0500
  4. Subject: [PATCH] objtool, x86: Add facility for asm code to provide unwind
  5. hints
  6. MIME-Version: 1.0
  7. Content-Type: text/plain; charset=UTF-8
  8. Content-Transfer-Encoding: 8bit
  9. CVE-2017-5754
  10. Some asm (and inline asm) code does special things to the stack which
  11. objtool can't understand. (Nor can GCC or GNU assembler, for that
  12. matter.) In such cases we need a facility for the code to provide
  13. annotations, so the unwinder can unwind through it.
  14. This provides such a facility, in the form of unwind hints. They're
  15. similar to the GNU assembler .cfi* directives, but they give more
  16. information, and are needed in far fewer places, because objtool can
  17. fill in the blanks by following branches and adjusting the stack pointer
  18. for pushes and pops.
  19. Signed-off-by: Josh Poimboeuf <[email protected]>
  20. Cc: Andy Lutomirski <[email protected]>
  21. Cc: Borislav Petkov <[email protected]>
  22. Cc: Brian Gerst <[email protected]>
  23. Cc: Denys Vlasenko <[email protected]>
  24. Cc: H. Peter Anvin <[email protected]>
  25. Cc: Jiri Slaby <[email protected]>
  26. Cc: Linus Torvalds <[email protected]>
  27. Cc: Mike Galbraith <[email protected]>
  28. Cc: Peter Zijlstra <[email protected]>
  29. Cc: Thomas Gleixner <[email protected]>
  30. Cc: [email protected]
  31. Link: http://lkml.kernel.org/r/0f5f3c9104fca559ff4088bece1d14ae3bca52d5.1499786555.git.jpoimboe@redhat.com
  32. Signed-off-by: Ingo Molnar <[email protected]>
  33. (cherry picked from commit 39358a033b2e4432052265c1fa0f36f572d8cfb5)
  34. Signed-off-by: Andy Whitcroft <[email protected]>
  35. Signed-off-by: Kleber Sacilotto de Souza <[email protected]>
  36. (cherry picked from commit a1fed2e10e84d48643a09861c2d127968621813e)
  37. Signed-off-by: Fabian Grünbichler <[email protected]>
  38. ---
  39. tools/objtool/Makefile | 3 +
  40. arch/x86/include/asm/orc_types.h | 107 ++++++++++++++++++++
  41. arch/x86/include/asm/unwind_hints.h | 103 +++++++++++++++++++
  42. tools/objtool/check.h | 4 +-
  43. tools/objtool/orc_types.h | 22 +++++
  44. tools/objtool/check.c | 191 +++++++++++++++++++++++++++++++++---
  45. 6 files changed, 417 insertions(+), 13 deletions(-)
  46. create mode 100644 arch/x86/include/asm/orc_types.h
  47. create mode 100644 arch/x86/include/asm/unwind_hints.h
  48. diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile
  49. index 0e2765e243c0..3a6425fefc43 100644
  50. --- a/tools/objtool/Makefile
  51. +++ b/tools/objtool/Makefile
  52. @@ -52,6 +52,9 @@ $(OBJTOOL): $(LIBSUBCMD) $(OBJTOOL_IN)
  53. diff -I'^#include' arch/x86/insn/inat.h ../../arch/x86/include/asm/inat.h >/dev/null && \
  54. diff -I'^#include' arch/x86/insn/inat_types.h ../../arch/x86/include/asm/inat_types.h >/dev/null) \
  55. || echo "warning: objtool: x86 instruction decoder differs from kernel" >&2 )) || true
  56. + @(test -d ../../kernel -a -d ../../tools -a -d ../objtool && (( \
  57. + diff ../../arch/x86/include/asm/orc_types.h orc_types.h >/dev/null) \
  58. + || echo "warning: objtool: orc_types.h differs from kernel" >&2 )) || true
  59. $(QUIET_LINK)$(CC) $(OBJTOOL_IN) $(LDFLAGS) -o $@
  60. diff --git a/arch/x86/include/asm/orc_types.h b/arch/x86/include/asm/orc_types.h
  61. new file mode 100644
  62. index 000000000000..7dc777a6cb40
  63. --- /dev/null
  64. +++ b/arch/x86/include/asm/orc_types.h
  65. @@ -0,0 +1,107 @@
  66. +/*
  67. + * Copyright (C) 2017 Josh Poimboeuf <[email protected]>
  68. + *
  69. + * This program is free software; you can redistribute it and/or
  70. + * modify it under the terms of the GNU General Public License
  71. + * as published by the Free Software Foundation; either version 2
  72. + * of the License, or (at your option) any later version.
  73. + *
  74. + * This program is distributed in the hope that it will be useful,
  75. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  76. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  77. + * GNU General Public License for more details.
  78. + *
  79. + * You should have received a copy of the GNU General Public License
  80. + * along with this program; if not, see <http://www.gnu.org/licenses/>.
  81. + */
  82. +
  83. +#ifndef _ORC_TYPES_H
  84. +#define _ORC_TYPES_H
  85. +
  86. +#include <linux/types.h>
  87. +#include <linux/compiler.h>
  88. +
  89. +/*
  90. + * The ORC_REG_* registers are base registers which are used to find other
  91. + * registers on the stack.
  92. + *
  93. + * ORC_REG_PREV_SP, also known as DWARF Call Frame Address (CFA), is the
  94. + * address of the previous frame: the caller's SP before it called the current
  95. + * function.
  96. + *
  97. + * ORC_REG_UNDEFINED means the corresponding register's value didn't change in
  98. + * the current frame.
  99. + *
  100. + * The most commonly used base registers are SP and BP -- which the previous SP
  101. + * is usually based on -- and PREV_SP and UNDEFINED -- which the previous BP is
  102. + * usually based on.
  103. + *
  104. + * The rest of the base registers are needed for special cases like entry code
  105. + * and GCC realigned stacks.
  106. + */
  107. +#define ORC_REG_UNDEFINED 0
  108. +#define ORC_REG_PREV_SP 1
  109. +#define ORC_REG_DX 2
  110. +#define ORC_REG_DI 3
  111. +#define ORC_REG_BP 4
  112. +#define ORC_REG_SP 5
  113. +#define ORC_REG_R10 6
  114. +#define ORC_REG_R13 7
  115. +#define ORC_REG_BP_INDIRECT 8
  116. +#define ORC_REG_SP_INDIRECT 9
  117. +#define ORC_REG_MAX 15
  118. +
  119. +/*
  120. + * ORC_TYPE_CALL: Indicates that sp_reg+sp_offset resolves to PREV_SP (the
  121. + * caller's SP right before it made the call). Used for all callable
  122. + * functions, i.e. all C code and all callable asm functions.
  123. + *
  124. + * ORC_TYPE_REGS: Used in entry code to indicate that sp_reg+sp_offset points
  125. + * to a fully populated pt_regs from a syscall, interrupt, or exception.
  126. + *
  127. + * ORC_TYPE_REGS_IRET: Used in entry code to indicate that sp_reg+sp_offset
  128. + * points to the iret return frame.
  129. + *
  130. + * The UNWIND_HINT macros are used only for the unwind_hint struct. They
  131. + * aren't used in struct orc_entry due to size and complexity constraints.
  132. + * Objtool converts them to real types when it converts the hints to orc
  133. + * entries.
  134. + */
  135. +#define ORC_TYPE_CALL 0
  136. +#define ORC_TYPE_REGS 1
  137. +#define ORC_TYPE_REGS_IRET 2
  138. +#define UNWIND_HINT_TYPE_SAVE 3
  139. +#define UNWIND_HINT_TYPE_RESTORE 4
  140. +
  141. +#ifndef __ASSEMBLY__
  142. +/*
  143. + * This struct is more or less a vastly simplified version of the DWARF Call
  144. + * Frame Information standard. It contains only the necessary parts of DWARF
  145. + * CFI, simplified for ease of access by the in-kernel unwinder. It tells the
  146. + * unwinder how to find the previous SP and BP (and sometimes entry regs) on
  147. + * the stack for a given code address. Each instance of the struct corresponds
  148. + * to one or more code locations.
  149. + */
  150. +struct orc_entry {
  151. + s16 sp_offset;
  152. + s16 bp_offset;
  153. + unsigned sp_reg:4;
  154. + unsigned bp_reg:4;
  155. + unsigned type:2;
  156. +};
  157. +
  158. +/*
  159. + * This struct is used by asm and inline asm code to manually annotate the
  160. + * location of registers on the stack for the ORC unwinder.
  161. + *
  162. + * Type can be either ORC_TYPE_* or UNWIND_HINT_TYPE_*.
  163. + */
  164. +struct unwind_hint {
  165. + u32 ip;
  166. + s16 sp_offset;
  167. + u8 sp_reg;
  168. + u8 type;
  169. +};
  170. +#endif /* __ASSEMBLY__ */
  171. +
  172. +#endif /* _ORC_TYPES_H */
  173. diff --git a/arch/x86/include/asm/unwind_hints.h b/arch/x86/include/asm/unwind_hints.h
  174. new file mode 100644
  175. index 000000000000..5e02b11c9b86
  176. --- /dev/null
  177. +++ b/arch/x86/include/asm/unwind_hints.h
  178. @@ -0,0 +1,103 @@
  179. +#ifndef _ASM_X86_UNWIND_HINTS_H
  180. +#define _ASM_X86_UNWIND_HINTS_H
  181. +
  182. +#include "orc_types.h"
  183. +
  184. +#ifdef __ASSEMBLY__
  185. +
  186. +/*
  187. + * In asm, there are two kinds of code: normal C-type callable functions and
  188. + * the rest. The normal callable functions can be called by other code, and
  189. + * don't do anything unusual with the stack. Such normal callable functions
  190. + * are annotated with the ENTRY/ENDPROC macros. Most asm code falls in this
  191. + * category. In this case, no special debugging annotations are needed because
  192. + * objtool can automatically generate the ORC data for the ORC unwinder to read
  193. + * at runtime.
  194. + *
  195. + * Anything which doesn't fall into the above category, such as syscall and
  196. + * interrupt handlers, tends to not be called directly by other functions, and
  197. + * often does unusual non-C-function-type things with the stack pointer. Such
  198. + * code needs to be annotated such that objtool can understand it. The
  199. + * following CFI hint macros are for this type of code.
  200. + *
  201. + * These macros provide hints to objtool about the state of the stack at each
  202. + * instruction. Objtool starts from the hints and follows the code flow,
  203. + * making automatic CFI adjustments when it sees pushes and pops, filling out
  204. + * the debuginfo as necessary. It will also warn if it sees any
  205. + * inconsistencies.
  206. + */
  207. +.macro UNWIND_HINT sp_reg=ORC_REG_SP sp_offset=0 type=ORC_TYPE_CALL
  208. +#ifdef CONFIG_STACK_VALIDATION
  209. +.Lunwind_hint_ip_\@:
  210. + .pushsection .discard.unwind_hints
  211. + /* struct unwind_hint */
  212. + .long .Lunwind_hint_ip_\@ - .
  213. + .short \sp_offset
  214. + .byte \sp_reg
  215. + .byte \type
  216. + .popsection
  217. +#endif
  218. +.endm
  219. +
  220. +.macro UNWIND_HINT_EMPTY
  221. + UNWIND_HINT sp_reg=ORC_REG_UNDEFINED
  222. +.endm
  223. +
  224. +.macro UNWIND_HINT_REGS base=%rsp offset=0 indirect=0 extra=1 iret=0
  225. + .if \base == %rsp && \indirect
  226. + .set sp_reg, ORC_REG_SP_INDIRECT
  227. + .elseif \base == %rsp
  228. + .set sp_reg, ORC_REG_SP
  229. + .elseif \base == %rbp
  230. + .set sp_reg, ORC_REG_BP
  231. + .elseif \base == %rdi
  232. + .set sp_reg, ORC_REG_DI
  233. + .elseif \base == %rdx
  234. + .set sp_reg, ORC_REG_DX
  235. + .elseif \base == %r10
  236. + .set sp_reg, ORC_REG_R10
  237. + .else
  238. + .error "UNWIND_HINT_REGS: bad base register"
  239. + .endif
  240. +
  241. + .set sp_offset, \offset
  242. +
  243. + .if \iret
  244. + .set type, ORC_TYPE_REGS_IRET
  245. + .elseif \extra == 0
  246. + .set type, ORC_TYPE_REGS_IRET
  247. + .set sp_offset, \offset + (16*8)
  248. + .else
  249. + .set type, ORC_TYPE_REGS
  250. + .endif
  251. +
  252. + UNWIND_HINT sp_reg=sp_reg sp_offset=sp_offset type=type
  253. +.endm
  254. +
  255. +.macro UNWIND_HINT_IRET_REGS base=%rsp offset=0
  256. + UNWIND_HINT_REGS base=\base offset=\offset iret=1
  257. +.endm
  258. +
  259. +.macro UNWIND_HINT_FUNC sp_offset=8
  260. + UNWIND_HINT sp_offset=\sp_offset
  261. +.endm
  262. +
  263. +#else /* !__ASSEMBLY__ */
  264. +
  265. +#define UNWIND_HINT(sp_reg, sp_offset, type) \
  266. + "987: \n\t" \
  267. + ".pushsection .discard.unwind_hints\n\t" \
  268. + /* struct unwind_hint */ \
  269. + ".long 987b - .\n\t" \
  270. + ".short " __stringify(sp_offset) "\n\t" \
  271. + ".byte " __stringify(sp_reg) "\n\t" \
  272. + ".byte " __stringify(type) "\n\t" \
  273. + ".popsection\n\t"
  274. +
  275. +#define UNWIND_HINT_SAVE UNWIND_HINT(0, 0, UNWIND_HINT_TYPE_SAVE)
  276. +
  277. +#define UNWIND_HINT_RESTORE UNWIND_HINT(0, 0, UNWIND_HINT_TYPE_RESTORE)
  278. +
  279. +#endif /* __ASSEMBLY__ */
  280. +
  281. +#endif /* _ASM_X86_UNWIND_HINTS_H */
  282. diff --git a/tools/objtool/check.h b/tools/objtool/check.h
  283. index 046874bbe226..ac3d4b13f17b 100644
  284. --- a/tools/objtool/check.h
  285. +++ b/tools/objtool/check.h
  286. @@ -43,7 +43,7 @@ struct instruction {
  287. unsigned int len;
  288. unsigned char type;
  289. unsigned long immediate;
  290. - bool alt_group, visited, dead_end, ignore;
  291. + bool alt_group, visited, dead_end, ignore, hint, save, restore;
  292. struct symbol *call_dest;
  293. struct instruction *jump_dest;
  294. struct list_head alts;
  295. @@ -58,7 +58,7 @@ struct objtool_file {
  296. struct list_head insn_list;
  297. DECLARE_HASHTABLE(insn_hash, 16);
  298. struct section *rodata, *whitelist;
  299. - bool ignore_unreachables, c_file;
  300. + bool ignore_unreachables, c_file, hints;
  301. };
  302. int check(const char *objname, bool nofp, bool orc);
  303. diff --git a/tools/objtool/orc_types.h b/tools/objtool/orc_types.h
  304. index fc5cf6cffd9a..9c9dc579bd7d 100644
  305. --- a/tools/objtool/orc_types.h
  306. +++ b/tools/objtool/orc_types.h
  307. @@ -61,11 +61,19 @@
  308. *
  309. * ORC_TYPE_REGS_IRET: Used in entry code to indicate that sp_reg+sp_offset
  310. * points to the iret return frame.
  311. + *
  312. + * The UNWIND_HINT macros are used only for the unwind_hint struct. They
  313. + * aren't used in struct orc_entry due to size and complexity constraints.
  314. + * Objtool converts them to real types when it converts the hints to orc
  315. + * entries.
  316. */
  317. #define ORC_TYPE_CALL 0
  318. #define ORC_TYPE_REGS 1
  319. #define ORC_TYPE_REGS_IRET 2
  320. +#define UNWIND_HINT_TYPE_SAVE 3
  321. +#define UNWIND_HINT_TYPE_RESTORE 4
  322. +#ifndef __ASSEMBLY__
  323. /*
  324. * This struct is more or less a vastly simplified version of the DWARF Call
  325. * Frame Information standard. It contains only the necessary parts of DWARF
  326. @@ -82,4 +90,18 @@ struct orc_entry {
  327. unsigned type:2;
  328. } __packed;
  329. +/*
  330. + * This struct is used by asm and inline asm code to manually annotate the
  331. + * location of registers on the stack for the ORC unwinder.
  332. + *
  333. + * Type can be either ORC_TYPE_* or UNWIND_HINT_TYPE_*.
  334. + */
  335. +struct unwind_hint {
  336. + u32 ip;
  337. + s16 sp_offset;
  338. + u8 sp_reg;
  339. + u8 type;
  340. +};
  341. +#endif /* __ASSEMBLY__ */
  342. +
  343. #endif /* _ORC_TYPES_H */
  344. diff --git a/tools/objtool/check.c b/tools/objtool/check.c
  345. index cb57c526ba17..368275de5f23 100644
  346. --- a/tools/objtool/check.c
  347. +++ b/tools/objtool/check.c
  348. @@ -100,7 +100,6 @@ static bool gcov_enabled(struct objtool_file *file)
  349. static bool ignore_func(struct objtool_file *file, struct symbol *func)
  350. {
  351. struct rela *rela;
  352. - struct instruction *insn;
  353. /* check for STACK_FRAME_NON_STANDARD */
  354. if (file->whitelist && file->whitelist->rela)
  355. @@ -113,11 +112,6 @@ static bool ignore_func(struct objtool_file *file, struct symbol *func)
  356. return true;
  357. }
  358. - /* check if it has a context switching instruction */
  359. - func_for_each_insn(file, func, insn)
  360. - if (insn->type == INSN_CONTEXT_SWITCH)
  361. - return true;
  362. -
  363. return false;
  364. }
  365. @@ -879,6 +873,99 @@ static int add_switch_table_alts(struct objtool_file *file)
  366. return 0;
  367. }
  368. +static int read_unwind_hints(struct objtool_file *file)
  369. +{
  370. + struct section *sec, *relasec;
  371. + struct rela *rela;
  372. + struct unwind_hint *hint;
  373. + struct instruction *insn;
  374. + struct cfi_reg *cfa;
  375. + int i;
  376. +
  377. + sec = find_section_by_name(file->elf, ".discard.unwind_hints");
  378. + if (!sec)
  379. + return 0;
  380. +
  381. + relasec = sec->rela;
  382. + if (!relasec) {
  383. + WARN("missing .rela.discard.unwind_hints section");
  384. + return -1;
  385. + }
  386. +
  387. + if (sec->len % sizeof(struct unwind_hint)) {
  388. + WARN("struct unwind_hint size mismatch");
  389. + return -1;
  390. + }
  391. +
  392. + file->hints = true;
  393. +
  394. + for (i = 0; i < sec->len / sizeof(struct unwind_hint); i++) {
  395. + hint = (struct unwind_hint *)sec->data->d_buf + i;
  396. +
  397. + rela = find_rela_by_dest(sec, i * sizeof(*hint));
  398. + if (!rela) {
  399. + WARN("can't find rela for unwind_hints[%d]", i);
  400. + return -1;
  401. + }
  402. +
  403. + insn = find_insn(file, rela->sym->sec, rela->addend);
  404. + if (!insn) {
  405. + WARN("can't find insn for unwind_hints[%d]", i);
  406. + return -1;
  407. + }
  408. +
  409. + cfa = &insn->state.cfa;
  410. +
  411. + if (hint->type == UNWIND_HINT_TYPE_SAVE) {
  412. + insn->save = true;
  413. + continue;
  414. +
  415. + } else if (hint->type == UNWIND_HINT_TYPE_RESTORE) {
  416. + insn->restore = true;
  417. + insn->hint = true;
  418. + continue;
  419. + }
  420. +
  421. + insn->hint = true;
  422. +
  423. + switch (hint->sp_reg) {
  424. + case ORC_REG_UNDEFINED:
  425. + cfa->base = CFI_UNDEFINED;
  426. + break;
  427. + case ORC_REG_SP:
  428. + cfa->base = CFI_SP;
  429. + break;
  430. + case ORC_REG_BP:
  431. + cfa->base = CFI_BP;
  432. + break;
  433. + case ORC_REG_SP_INDIRECT:
  434. + cfa->base = CFI_SP_INDIRECT;
  435. + break;
  436. + case ORC_REG_R10:
  437. + cfa->base = CFI_R10;
  438. + break;
  439. + case ORC_REG_R13:
  440. + cfa->base = CFI_R13;
  441. + break;
  442. + case ORC_REG_DI:
  443. + cfa->base = CFI_DI;
  444. + break;
  445. + case ORC_REG_DX:
  446. + cfa->base = CFI_DX;
  447. + break;
  448. + default:
  449. + WARN_FUNC("unsupported unwind_hint sp base reg %d",
  450. + insn->sec, insn->offset, hint->sp_reg);
  451. + return -1;
  452. + }
  453. +
  454. + cfa->offset = hint->sp_offset;
  455. + insn->state.type = hint->type;
  456. + }
  457. +
  458. + return 0;
  459. +}
  460. +
  461. static int decode_sections(struct objtool_file *file)
  462. {
  463. int ret;
  464. @@ -909,6 +996,10 @@ static int decode_sections(struct objtool_file *file)
  465. if (ret)
  466. return ret;
  467. + ret = read_unwind_hints(file);
  468. + if (ret)
  469. + return ret;
  470. +
  471. return 0;
  472. }
  473. @@ -1382,7 +1473,7 @@ static int validate_branch(struct objtool_file *file, struct instruction *first,
  474. struct insn_state state)
  475. {
  476. struct alternative *alt;
  477. - struct instruction *insn;
  478. + struct instruction *insn, *next_insn;
  479. struct section *sec;
  480. struct symbol *func = NULL;
  481. int ret;
  482. @@ -1397,6 +1488,8 @@ static int validate_branch(struct objtool_file *file, struct instruction *first,
  483. }
  484. while (1) {
  485. + next_insn = next_insn_same_sec(file, insn);
  486. +
  487. if (file->c_file && insn->func) {
  488. if (func && func != insn->func) {
  489. WARN("%s() falls through to next function %s()",
  490. @@ -1414,13 +1507,54 @@ static int validate_branch(struct objtool_file *file, struct instruction *first,
  491. }
  492. if (insn->visited) {
  493. - if (!!insn_state_match(insn, &state))
  494. + if (!insn->hint && !insn_state_match(insn, &state))
  495. return 1;
  496. return 0;
  497. }
  498. - insn->state = state;
  499. + if (insn->hint) {
  500. + if (insn->restore) {
  501. + struct instruction *save_insn, *i;
  502. +
  503. + i = insn;
  504. + save_insn = NULL;
  505. + func_for_each_insn_continue_reverse(file, func, i) {
  506. + if (i->save) {
  507. + save_insn = i;
  508. + break;
  509. + }
  510. + }
  511. +
  512. + if (!save_insn) {
  513. + WARN_FUNC("no corresponding CFI save for CFI restore",
  514. + sec, insn->offset);
  515. + return 1;
  516. + }
  517. +
  518. + if (!save_insn->visited) {
  519. + /*
  520. + * Oops, no state to copy yet.
  521. + * Hopefully we can reach this
  522. + * instruction from another branch
  523. + * after the save insn has been
  524. + * visited.
  525. + */
  526. + if (insn == first)
  527. + return 0;
  528. +
  529. + WARN_FUNC("objtool isn't smart enough to handle this CFI save/restore combo",
  530. + sec, insn->offset);
  531. + return 1;
  532. + }
  533. +
  534. + insn->state = save_insn->state;
  535. + }
  536. +
  537. + state = insn->state;
  538. +
  539. + } else
  540. + insn->state = state;
  541. insn->visited = true;
  542. @@ -1497,6 +1631,14 @@ static int validate_branch(struct objtool_file *file, struct instruction *first,
  543. return 0;
  544. + case INSN_CONTEXT_SWITCH:
  545. + if (func && (!next_insn || !next_insn->hint)) {
  546. + WARN_FUNC("unsupported instruction in callable function",
  547. + sec, insn->offset);
  548. + return 1;
  549. + }
  550. + return 0;
  551. +
  552. case INSN_STACK:
  553. if (update_insn_state(insn, &state))
  554. return -1;
  555. @@ -1510,7 +1652,7 @@ static int validate_branch(struct objtool_file *file, struct instruction *first,
  556. if (insn->dead_end)
  557. return 0;
  558. - insn = next_insn_same_sec(file, insn);
  559. + insn = next_insn;
  560. if (!insn) {
  561. WARN("%s: unexpected end of section", sec->name);
  562. return 1;
  563. @@ -1520,6 +1662,27 @@ static int validate_branch(struct objtool_file *file, struct instruction *first,
  564. return 0;
  565. }
  566. +static int validate_unwind_hints(struct objtool_file *file)
  567. +{
  568. + struct instruction *insn;
  569. + int ret, warnings = 0;
  570. + struct insn_state state;
  571. +
  572. + if (!file->hints)
  573. + return 0;
  574. +
  575. + clear_insn_state(&state);
  576. +
  577. + for_each_insn(file, insn) {
  578. + if (insn->hint && !insn->visited) {
  579. + ret = validate_branch(file, insn, state);
  580. + warnings += ret;
  581. + }
  582. + }
  583. +
  584. + return warnings;
  585. +}
  586. +
  587. static bool is_kasan_insn(struct instruction *insn)
  588. {
  589. return (insn->type == INSN_CALL &&
  590. @@ -1665,8 +1828,9 @@ int check(const char *_objname, bool _nofp, bool orc)
  591. hash_init(file.insn_hash);
  592. file.whitelist = find_section_by_name(file.elf, ".discard.func_stack_frame_non_standard");
  593. file.rodata = find_section_by_name(file.elf, ".rodata");
  594. - file.ignore_unreachables = false;
  595. file.c_file = find_section_by_name(file.elf, ".comment");
  596. + file.ignore_unreachables = false;
  597. + file.hints = false;
  598. arch_initial_func_cfi_state(&initial_func_cfi);
  599. @@ -1683,6 +1847,11 @@ int check(const char *_objname, bool _nofp, bool orc)
  600. goto out;
  601. warnings += ret;
  602. + ret = validate_unwind_hints(&file);
  603. + if (ret < 0)
  604. + goto out;
  605. + warnings += ret;
  606. +
  607. if (!warnings) {
  608. ret = validate_reachable_instructions(&file);
  609. if (ret < 0)
  610. --
  611. 2.14.2