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