--- /dev/null
+From 7dec80ccbe310fb7e225bf21c48c672bb780ce7b Mon Sep 17 00:00:00 2001
+From: Josh Poimboeuf <jpoimboe@redhat.com>
+Date: Fri, 18 May 2018 15:10:34 -0500
+Subject: objtool: Detect RIP-relative switch table references, part 2
+
+From: Josh Poimboeuf <jpoimboe@redhat.com>
+
+commit 7dec80ccbe310fb7e225bf21c48c672bb780ce7b upstream.
+
+With the following commit:
+
+ fd35c88b7417 ("objtool: Support GCC 8 switch tables")
+
+I added a "can't find switch jump table" warning, to stop covering up
+silent failures if add_switch_table() can't find anything.
+
+That warning found yet another bug in the objtool switch table detection
+logic. For cases 1 and 2 (as described in the comments of
+find_switch_table()), the find_symbol_containing() check doesn't adjust
+the offset for RIP-relative switch jumps.
+
+Incidentally, this bug was already fixed for case 3 with:
+
+ 6f5ec2993b1f ("objtool: Detect RIP-relative switch table references")
+
+However, that commit missed the fix for cases 1 and 2.
+
+The different cases are now starting to look more and more alike. So
+fix the bug by consolidating them into a single case, by checking the
+original dynamic jump instruction in the case 3 loop.
+
+This also simplifies the code and makes it more robust against future
+switch table detection issues -- of which I'm sure there will be many...
+
+Switch table detection has been the most fragile area of objtool, by
+far. I long for the day when we'll have a GCC plugin for annotating
+switch tables. Linus asked me to delay such a plugin due to the
+flakiness of the plugin infrastructure in older versions of GCC, so this
+rickety code is what we're stuck with for now. At least the code is now
+a little simpler than it was.
+
+Reported-by: kbuild test robot <lkp@intel.com>
+Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Link: http://lkml.kernel.org/r/f400541613d45689086329432f3095119ffbc328.1526674218.git.jpoimboe@redhat.com
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/objtool/check.c | 37 ++++++++++++-------------------------
+ 1 file changed, 12 insertions(+), 25 deletions(-)
+
+--- a/tools/objtool/check.c
++++ b/tools/objtool/check.c
+@@ -901,40 +901,19 @@ static struct rela *find_switch_table(st
+ struct instruction *orig_insn = insn;
+ unsigned long table_offset;
+
+- /* case 1 & 2 */
+- text_rela = find_rela_by_dest_range(insn->sec, insn->offset, insn->len);
+- if (text_rela && text_rela->sym == file->rodata->sym &&
+- !find_symbol_containing(file->rodata, text_rela->addend)) {
+-
+- table_offset = text_rela->addend;
+- if (text_rela->type == R_X86_64_PC32) {
+- /* case 2 */
+- table_offset += 4;
+- file->ignore_unreachables = true;
+- }
+-
+- rodata_rela = find_rela_by_dest(file->rodata, table_offset);
+- if (!rodata_rela)
+- return NULL;
+-
+- return rodata_rela;
+- }
+-
+- /* case 3 */
+ /*
+ * Backward search using the @first_jump_src links, these help avoid
+ * much of the 'in between' code. Which avoids us getting confused by
+ * it.
+ */
+- for (insn = list_prev_entry(insn, list);
+-
++ for (;
+ &insn->list != &file->insn_list &&
+ insn->sec == func->sec &&
+ insn->offset >= func->offset;
+
+ insn = insn->first_jump_src ?: list_prev_entry(insn, list)) {
+
+- if (insn->type == INSN_JUMP_DYNAMIC)
++ if (insn != orig_insn && insn->type == INSN_JUMP_DYNAMIC)
+ break;
+
+ /* allow small jumps within the range */
+@@ -961,10 +940,18 @@ static struct rela *find_switch_table(st
+ if (find_symbol_containing(file->rodata, table_offset))
+ continue;
+
+- /* mov [rodata addr], %reg */
+ rodata_rela = find_rela_by_dest(file->rodata, table_offset);
+- if (rodata_rela)
++ if (rodata_rela) {
++ /*
++ * Use of RIP-relative switch jumps is quite rare, and
++ * indicates a rare GCC quirk/bug which can leave dead
++ * code behind.
++ */
++ if (text_rela->type == R_X86_64_PC32)
++ file->ignore_unreachables = true;
++
+ return rodata_rela;
++ }
+ }
+
+ return NULL;
--- /dev/null
+From 6f5ec2993b1f39aed12fa6fd56e8dc2272ee8a33 Mon Sep 17 00:00:00 2001
+From: Josh Poimboeuf <jpoimboe@redhat.com>
+Date: Mon, 14 May 2018 08:53:24 -0500
+Subject: objtool: Detect RIP-relative switch table references
+
+From: Josh Poimboeuf <jpoimboe@redhat.com>
+
+commit 6f5ec2993b1f39aed12fa6fd56e8dc2272ee8a33 upstream.
+
+Typically a switch table can be found by detecting a .rodata access
+followed an indirect jump:
+
+ 1969: 4a 8b 0c e5 00 00 00 mov 0x0(,%r12,8),%rcx
+ 1970: 00
+ 196d: R_X86_64_32S .rodata+0x438
+ 1971: e9 00 00 00 00 jmpq 1976 <dispc_runtime_suspend+0xb6a>
+ 1972: R_X86_64_PC32 __x86_indirect_thunk_rcx-0x4
+
+Randy Dunlap reported a case (seen with GCC 4.8) where the .rodata
+access uses RIP-relative addressing:
+
+ 19bd: 48 8b 3d 00 00 00 00 mov 0x0(%rip),%rdi # 19c4 <dispc_runtime_suspend+0xbb8>
+ 19c0: R_X86_64_PC32 .rodata+0x45c
+ 19c4: e9 00 00 00 00 jmpq 19c9 <dispc_runtime_suspend+0xbbd>
+ 19c5: R_X86_64_PC32 __x86_indirect_thunk_rdi-0x4
+
+In this case the relocation addend needs to be adjusted accordingly in
+order to find the location of the switch table.
+
+The fix is for case 3 (as described in the comments), but also make the
+existing case 1 & 2 checks more precise by only adjusting the addend for
+R_X86_64_PC32 relocations.
+
+This fixes the following warnings:
+
+ drivers/video/fbdev/omap2/omapfb/dss/dispc.o: warning: objtool: dispc_runtime_suspend()+0xbb8: sibling call from callable instruction with modified stack frame
+ drivers/video/fbdev/omap2/omapfb/dss/dispc.o: warning: objtool: dispc_runtime_resume()+0xcc5: sibling call from callable instruction with modified stack frame
+
+Reported-by: Randy Dunlap <rdunlap@infradead.org>
+Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Link: http://lkml.kernel.org/r/b6098294fd67afb69af8c47c9883d7a68bf0f8ea.1526305958.git.jpoimboe@redhat.com
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/objtool/check.c | 33 ++++++++++++++++++---------------
+ 1 file changed, 18 insertions(+), 15 deletions(-)
+
+--- a/tools/objtool/check.c
++++ b/tools/objtool/check.c
+@@ -899,24 +899,24 @@ static struct rela *find_switch_table(st
+ {
+ struct rela *text_rela, *rodata_rela;
+ struct instruction *orig_insn = insn;
++ unsigned long table_offset;
+
++ /* case 1 & 2 */
+ text_rela = find_rela_by_dest_range(insn->sec, insn->offset, insn->len);
+ if (text_rela && text_rela->sym == file->rodata->sym &&
+ !find_symbol_containing(file->rodata, text_rela->addend)) {
+
+- /* case 1 */
+- rodata_rela = find_rela_by_dest(file->rodata,
+- text_rela->addend);
+- if (rodata_rela)
+- return rodata_rela;
++ table_offset = text_rela->addend;
++ if (text_rela->type == R_X86_64_PC32) {
++ /* case 2 */
++ table_offset += 4;
++ file->ignore_unreachables = true;
++ }
+
+- /* case 2 */
+- rodata_rela = find_rela_by_dest(file->rodata,
+- text_rela->addend + 4);
++ rodata_rela = find_rela_by_dest(file->rodata, table_offset);
+ if (!rodata_rela)
+ return NULL;
+
+- file->ignore_unreachables = true;
+ return rodata_rela;
+ }
+
+@@ -950,18 +950,21 @@ static struct rela *find_switch_table(st
+ if (!text_rela || text_rela->sym != file->rodata->sym)
+ continue;
+
++ table_offset = text_rela->addend;
++ if (text_rela->type == R_X86_64_PC32)
++ table_offset += 4;
++
+ /*
+ * Make sure the .rodata address isn't associated with a
+ * symbol. gcc jump tables are anonymous data.
+ */
+- if (find_symbol_containing(file->rodata, text_rela->addend))
++ if (find_symbol_containing(file->rodata, table_offset))
+ continue;
+
+- rodata_rela = find_rela_by_dest(file->rodata, text_rela->addend);
+- if (!rodata_rela)
+- continue;
+-
+- return rodata_rela;
++ /* mov [rodata addr], %reg */
++ rodata_rela = find_rela_by_dest(file->rodata, table_offset);
++ if (rodata_rela)
++ return rodata_rela;
+ }
+
+ return NULL;
--- /dev/null
+From 0afd0d9e0e7879d666c1df2fa1bea4d8716909fe Mon Sep 17 00:00:00 2001
+From: Josh Poimboeuf <jpoimboe@redhat.com>
+Date: Wed, 9 May 2018 22:39:14 -0500
+Subject: objtool: Fix "noreturn" detection for recursive sibling calls
+
+From: Josh Poimboeuf <jpoimboe@redhat.com>
+
+commit 0afd0d9e0e7879d666c1df2fa1bea4d8716909fe upstream.
+
+Objtool has some crude logic for detecting static "noreturn" functions
+(aka "dead ends"). This is necessary for being able to correctly follow
+GCC code flow when such functions are called.
+
+It's remotely possible for two functions to call each other via sibling
+calls. If they don't have RET instructions, objtool's noreturn
+detection logic goes into a recursive loop:
+
+ drivers/char/ipmi/ipmi_ssif.o: warning: objtool: return_hosed_msg()+0x0: infinite recursion (objtool bug!)
+ drivers/char/ipmi/ipmi_ssif.o: warning: objtool: deliver_recv_msg()+0x0: infinite recursion (objtool bug!)
+
+Instead of reporting an error in this case, consider the functions to be
+non-dead-ends.
+
+Reported-and-tested-by: Randy Dunlap <rdunlap@infradead.org>
+Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
+Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Cc: Arnd Bergmann <arnd@arndb.de>
+Cc: David Laight <David.Laight@ACULAB.COM>
+Cc: Greg KH <gregkh@linuxfoundation.org>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: damian <damian.tometzki@icloud.com>
+Link: http://lkml.kernel.org/r/7cc156408c5781a1f62085d352ced1fe39fe2f91.1525923412.git.jpoimboe@redhat.com
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/objtool/check.c | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+--- a/tools/objtool/check.c
++++ b/tools/objtool/check.c
+@@ -208,9 +208,13 @@ static int __dead_end_function(struct ob
+
+ /* local sibling call */
+ if (recursion == 5) {
+- WARN_FUNC("infinite recursion (objtool bug!)",
+- dest->sec, dest->offset);
+- return -1;
++ /*
++ * Infinite recursion: two functions
++ * have sibling calls to each other.
++ * This is a very rare case. It means
++ * they aren't dead ends.
++ */
++ return 0;
+ }
+
+ return __dead_end_function(file, dest->func,
--- /dev/null
+From 13810435b9a7014fb92eb715f77da488f3b65b99 Mon Sep 17 00:00:00 2001
+From: Josh Poimboeuf <jpoimboe@redhat.com>
+Date: Wed, 9 May 2018 22:39:15 -0500
+Subject: objtool: Support GCC 8's cold subfunctions
+
+From: Josh Poimboeuf <jpoimboe@redhat.com>
+
+commit 13810435b9a7014fb92eb715f77da488f3b65b99 upstream.
+
+GCC 8 moves a lot of unlikely code out of line to "cold" subfunctions in
+.text.unlikely. Properly detect the new subfunctions and treat them as
+extensions of the original functions.
+
+This fixes a bunch of warnings like:
+
+ kernel/cgroup/cgroup.o: warning: objtool: parse_cgroup_root_flags()+0x33: sibling call from callable instruction with modified stack frame
+ kernel/cgroup/cgroup.o: warning: objtool: cgroup_addrm_files()+0x290: sibling call from callable instruction with modified stack frame
+ kernel/cgroup/cgroup.o: warning: objtool: cgroup_apply_control_enable()+0x25b: sibling call from callable instruction with modified stack frame
+ kernel/cgroup/cgroup.o: warning: objtool: rebind_subsystems()+0x325: sibling call from callable instruction with modified stack frame
+
+Reported-and-tested-by: damian <damian.tometzki@icloud.com>
+Reported-by: Arnd Bergmann <arnd@arndb.de>
+Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
+Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Cc: David Laight <David.Laight@ACULAB.COM>
+Cc: Greg KH <gregkh@linuxfoundation.org>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Randy Dunlap <rdunlap@infradead.org>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Link: http://lkml.kernel.org/r/0965e7fcfc5f31a276f0c7f298ff770c19b68706.1525923412.git.jpoimboe@redhat.com
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/objtool/check.c | 93 +++++++++++++++++++++++++++-----------------------
+ tools/objtool/elf.c | 42 +++++++++++++++++++++-
+ tools/objtool/elf.h | 2 +
+ 3 files changed, 93 insertions(+), 44 deletions(-)
+
+--- a/tools/objtool/check.c
++++ b/tools/objtool/check.c
+@@ -59,6 +59,31 @@ static struct instruction *next_insn_sam
+ return next;
+ }
+
++static struct instruction *next_insn_same_func(struct objtool_file *file,
++ struct instruction *insn)
++{
++ struct instruction *next = list_next_entry(insn, list);
++ struct symbol *func = insn->func;
++
++ if (!func)
++ return NULL;
++
++ if (&next->list != &file->insn_list && next->func == func)
++ return next;
++
++ /* Check if we're already in the subfunction: */
++ if (func == func->cfunc)
++ return NULL;
++
++ /* Move to the subfunction: */
++ return find_insn(file, func->cfunc->sec, func->cfunc->offset);
++}
++
++#define func_for_each_insn_all(file, func, insn) \
++ for (insn = find_insn(file, func->sec, func->offset); \
++ insn; \
++ insn = next_insn_same_func(file, insn))
++
+ #define func_for_each_insn(file, func, insn) \
+ for (insn = find_insn(file, func->sec, func->offset); \
+ insn && &insn->list != &file->insn_list && \
+@@ -149,10 +174,14 @@ static int __dead_end_function(struct ob
+ if (!strcmp(func->name, global_noreturns[i]))
+ return 1;
+
+- if (!func->sec)
++ if (!func->len)
++ return 0;
++
++ insn = find_insn(file, func->sec, func->offset);
++ if (!insn->func)
+ return 0;
+
+- func_for_each_insn(file, func, insn) {
++ func_for_each_insn_all(file, func, insn) {
+ empty = false;
+
+ if (insn->type == INSN_RETURN)
+@@ -167,35 +196,24 @@ static int __dead_end_function(struct ob
+ * case, the function's dead-end status depends on whether the target
+ * of the sibling call returns.
+ */
+- func_for_each_insn(file, func, insn) {
+- if (insn->sec != func->sec ||
+- insn->offset >= func->offset + func->len)
+- break;
+-
++ func_for_each_insn_all(file, func, insn) {
+ if (insn->type == INSN_JUMP_UNCONDITIONAL) {
+ struct instruction *dest = insn->jump_dest;
+- struct symbol *dest_func;
+
+ if (!dest)
+ /* sibling call to another file */
+ return 0;
+
+- if (dest->sec != func->sec ||
+- dest->offset < func->offset ||
+- dest->offset >= func->offset + func->len) {
+- /* local sibling call */
+- dest_func = find_symbol_by_offset(dest->sec,
+- dest->offset);
+- if (!dest_func)
+- continue;
++ if (dest->func && dest->func->pfunc != insn->func->pfunc) {
+
++ /* local sibling call */
+ if (recursion == 5) {
+ WARN_FUNC("infinite recursion (objtool bug!)",
+ dest->sec, dest->offset);
+ return -1;
+ }
+
+- return __dead_end_function(file, dest_func,
++ return __dead_end_function(file, dest->func,
+ recursion + 1);
+ }
+ }
+@@ -422,7 +440,7 @@ static void add_ignores(struct objtool_f
+ if (!ignore_func(file, func))
+ continue;
+
+- func_for_each_insn(file, func, insn)
++ func_for_each_insn_all(file, func, insn)
+ insn->ignore = true;
+ }
+ }
+@@ -782,9 +800,8 @@ out:
+ return ret;
+ }
+
+-static int add_switch_table(struct objtool_file *file, struct symbol *func,
+- struct instruction *insn, struct rela *table,
+- struct rela *next_table)
++static int add_switch_table(struct objtool_file *file, struct instruction *insn,
++ struct rela *table, struct rela *next_table)
+ {
+ struct rela *rela = table;
+ struct instruction *alt_insn;
+@@ -794,18 +811,13 @@ static int add_switch_table(struct objto
+ if (rela == next_table)
+ break;
+
+- if (rela->sym->sec != insn->sec ||
+- rela->addend <= func->offset ||
+- rela->addend >= func->offset + func->len)
++ alt_insn = find_insn(file, rela->sym->sec, rela->addend);
++ if (!alt_insn)
+ break;
+
+- alt_insn = find_insn(file, insn->sec, rela->addend);
+- if (!alt_insn) {
+- WARN("%s: can't find instruction at %s+0x%x",
+- file->rodata->rela->name, insn->sec->name,
+- rela->addend);
+- return -1;
+- }
++ /* Make sure the jmp dest is in the function or subfunction: */
++ if (alt_insn->func->pfunc != insn->func->pfunc)
++ break;
+
+ alt = malloc(sizeof(*alt));
+ if (!alt) {
+@@ -943,7 +955,7 @@ static int add_func_switch_tables(struct
+ struct rela *rela, *prev_rela = NULL;
+ int ret;
+
+- func_for_each_insn(file, func, insn) {
++ func_for_each_insn_all(file, func, insn) {
+ if (!last)
+ last = insn;
+
+@@ -974,8 +986,7 @@ static int add_func_switch_tables(struct
+ * the beginning of another switch table in the same function.
+ */
+ if (prev_jump) {
+- ret = add_switch_table(file, func, prev_jump, prev_rela,
+- rela);
++ ret = add_switch_table(file, prev_jump, prev_rela, rela);
+ if (ret)
+ return ret;
+ }
+@@ -985,7 +996,7 @@ static int add_func_switch_tables(struct
+ }
+
+ if (prev_jump) {
+- ret = add_switch_table(file, func, prev_jump, prev_rela, NULL);
++ ret = add_switch_table(file, prev_jump, prev_rela, NULL);
+ if (ret)
+ return ret;
+ }
+@@ -1749,15 +1760,13 @@ static int validate_branch(struct objtoo
+ while (1) {
+ next_insn = next_insn_same_sec(file, insn);
+
+-
+- if (file->c_file && func && insn->func && func != insn->func) {
++ if (file->c_file && func && insn->func && func != insn->func->pfunc) {
+ WARN("%s() falls through to next function %s()",
+ func->name, insn->func->name);
+ return 1;
+ }
+
+- if (insn->func)
+- func = insn->func;
++ func = insn->func ? insn->func->pfunc : NULL;
+
+ if (func && insn->ignore) {
+ WARN_FUNC("BUG: why am I validating an ignored function?",
+@@ -1778,7 +1787,7 @@ static int validate_branch(struct objtoo
+
+ i = insn;
+ save_insn = NULL;
+- func_for_each_insn_continue_reverse(file, func, i) {
++ func_for_each_insn_continue_reverse(file, insn->func, i) {
+ if (i->save) {
+ save_insn = i;
+ break;
+@@ -1865,7 +1874,7 @@ static int validate_branch(struct objtoo
+ case INSN_JUMP_UNCONDITIONAL:
+ if (insn->jump_dest &&
+ (!func || !insn->jump_dest->func ||
+- func == insn->jump_dest->func)) {
++ insn->jump_dest->func->pfunc == func)) {
+ ret = validate_branch(file, insn->jump_dest,
+ state);
+ if (ret)
+@@ -2060,7 +2069,7 @@ static int validate_functions(struct obj
+
+ for_each_sec(file, sec) {
+ list_for_each_entry(func, &sec->symbol_list, list) {
+- if (func->type != STT_FUNC)
++ if (func->type != STT_FUNC || func->pfunc != func)
+ continue;
+
+ insn = find_insn(file, sec, func->offset);
+--- a/tools/objtool/elf.c
++++ b/tools/objtool/elf.c
+@@ -79,6 +79,19 @@ struct symbol *find_symbol_by_offset(str
+ return NULL;
+ }
+
++struct symbol *find_symbol_by_name(struct elf *elf, const char *name)
++{
++ struct section *sec;
++ struct symbol *sym;
++
++ list_for_each_entry(sec, &elf->sections, list)
++ list_for_each_entry(sym, &sec->symbol_list, list)
++ if (!strcmp(sym->name, name))
++ return sym;
++
++ return NULL;
++}
++
+ struct symbol *find_symbol_containing(struct section *sec, unsigned long offset)
+ {
+ struct symbol *sym;
+@@ -203,10 +216,11 @@ static int read_sections(struct elf *elf
+
+ static int read_symbols(struct elf *elf)
+ {
+- struct section *symtab;
+- struct symbol *sym;
++ struct section *symtab, *sec;
++ struct symbol *sym, *pfunc;
+ struct list_head *entry, *tmp;
+ int symbols_nr, i;
++ char *coldstr;
+
+ symtab = find_section_by_name(elf, ".symtab");
+ if (!symtab) {
+@@ -281,6 +295,30 @@ static int read_symbols(struct elf *elf)
+ hash_add(sym->sec->symbol_hash, &sym->hash, sym->idx);
+ }
+
++ /* Create parent/child links for any cold subfunctions */
++ list_for_each_entry(sec, &elf->sections, list) {
++ list_for_each_entry(sym, &sec->symbol_list, list) {
++ if (sym->type != STT_FUNC)
++ continue;
++ sym->pfunc = sym->cfunc = sym;
++ coldstr = strstr(sym->name, ".cold.");
++ if (coldstr) {
++ coldstr[0] = '\0';
++ pfunc = find_symbol_by_name(elf, sym->name);
++ coldstr[0] = '.';
++
++ if (!pfunc) {
++ WARN("%s(): can't find parent function",
++ sym->name);
++ goto err;
++ }
++
++ sym->pfunc = pfunc;
++ pfunc->cfunc = sym;
++ }
++ }
++ }
++
+ return 0;
+
+ err:
+--- a/tools/objtool/elf.h
++++ b/tools/objtool/elf.h
+@@ -61,6 +61,7 @@ struct symbol {
+ unsigned char bind, type;
+ unsigned long offset;
+ unsigned int len;
++ struct symbol *pfunc, *cfunc;
+ };
+
+ struct rela {
+@@ -86,6 +87,7 @@ struct elf {
+ struct elf *elf_open(const char *name, int flags);
+ struct section *find_section_by_name(struct elf *elf, const char *name);
+ struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset);
++struct symbol *find_symbol_by_name(struct elf *elf, const char *name);
+ struct symbol *find_symbol_containing(struct section *sec, unsigned long offset);
+ struct rela *find_rela_by_dest(struct section *sec, unsigned long offset);
+ struct rela *find_rela_by_dest_range(struct section *sec, unsigned long offset,
--- /dev/null
+From fd35c88b74170d9335530d9abf271d5d73eb5401 Mon Sep 17 00:00:00 2001
+From: Josh Poimboeuf <jpoimboe@redhat.com>
+Date: Thu, 10 May 2018 17:48:49 -0500
+Subject: objtool: Support GCC 8 switch tables
+
+From: Josh Poimboeuf <jpoimboe@redhat.com>
+
+commit fd35c88b74170d9335530d9abf271d5d73eb5401 upstream.
+
+With GCC 8, some issues were found with the objtool switch table
+detection.
+
+1) In the .rodata section, immediately after the switch table, there can
+ be another object which contains a pointer to the function which had
+ the switch statement. In this case objtool wrongly considers the
+ function pointer to be part of the switch table. Fix it by:
+
+ a) making sure there are no pointers to the beginning of the
+ function; and
+
+ b) making sure there are no gaps in the switch table.
+
+ Only the former was needed, the latter adds additional protection for
+ future optimizations.
+
+2) In find_switch_table(), case 1 and case 2 are missing the check to
+ ensure that the .rodata switch table data is anonymous, i.e. that it
+ isn't already associated with an ELF symbol. Fix it by adding the
+ same find_symbol_containing() check which is used for case 3.
+
+This fixes the following warnings with GCC 8:
+
+ drivers/block/virtio_blk.o: warning: objtool: virtio_queue_rq()+0x0: stack state mismatch: cfa1=7+8 cfa2=7+72
+ net/ipv6/icmp.o: warning: objtool: icmpv6_rcv()+0x0: stack state mismatch: cfa1=7+8 cfa2=7+64
+ drivers/usb/core/quirks.o: warning: objtool: quirks_param_set()+0x0: stack state mismatch: cfa1=7+8 cfa2=7+48
+ drivers/mtd/nand/raw/nand_hynix.o: warning: objtool: hynix_nand_decode_id()+0x0: stack state mismatch: cfa1=7+8 cfa2=7+24
+ drivers/mtd/nand/raw/nand_samsung.o: warning: objtool: samsung_nand_decode_id()+0x0: stack state mismatch: cfa1=7+8 cfa2=7+32
+ drivers/gpu/drm/nouveau/nvkm/subdev/top/gk104.o: warning: objtool: gk104_top_oneinit()+0x0: stack state mismatch: cfa1=7+8 cfa2=7+64
+
+Reported-by: Arnd Bergmann <arnd@arndb.de>
+Reported-by: kbuild test robot <lkp@intel.com>
+Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
+Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Cc: David Laight <David.Laight@ACULAB.COM>
+Cc: Greg KH <gregkh@linuxfoundation.org>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Randy Dunlap <rdunlap@infradead.org>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: damian <damian.tometzki@icloud.com>
+Link: http://lkml.kernel.org/r/20180510224849.xwi34d6tzheb5wgw@treble
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/objtool/check.c | 24 ++++++++++++++++++++++--
+ 1 file changed, 22 insertions(+), 2 deletions(-)
+
+--- a/tools/objtool/check.c
++++ b/tools/objtool/check.c
+@@ -806,17 +806,28 @@ static int add_switch_table(struct objto
+ struct rela *rela = table;
+ struct instruction *alt_insn;
+ struct alternative *alt;
++ struct symbol *pfunc = insn->func->pfunc;
++ unsigned int prev_offset = 0;
+
+ list_for_each_entry_from(rela, &file->rodata->rela->rela_list, list) {
+ if (rela == next_table)
+ break;
+
++ /* Make sure the switch table entries are consecutive: */
++ if (prev_offset && rela->offset != prev_offset + 8)
++ break;
++
++ /* Detect function pointers from contiguous objects: */
++ if (rela->sym->sec == pfunc->sec &&
++ rela->addend == pfunc->offset)
++ break;
++
+ alt_insn = find_insn(file, rela->sym->sec, rela->addend);
+ if (!alt_insn)
+ break;
+
+ /* Make sure the jmp dest is in the function or subfunction: */
+- if (alt_insn->func->pfunc != insn->func->pfunc)
++ if (alt_insn->func->pfunc != pfunc)
+ break;
+
+ alt = malloc(sizeof(*alt));
+@@ -827,6 +838,13 @@ static int add_switch_table(struct objto
+
+ alt->insn = alt_insn;
+ list_add_tail(&alt->list, &insn->alts);
++ prev_offset = rela->offset;
++ }
++
++ if (!prev_offset) {
++ WARN_FUNC("can't find switch jump table",
++ insn->sec, insn->offset);
++ return -1;
+ }
+
+ return 0;
+@@ -883,7 +901,9 @@ static struct rela *find_switch_table(st
+ struct instruction *orig_insn = insn;
+
+ text_rela = find_rela_by_dest_range(insn->sec, insn->offset, insn->len);
+- if (text_rela && text_rela->sym == file->rodata->sym) {
++ if (text_rela && text_rela->sym == file->rodata->sym &&
++ !find_symbol_containing(file->rodata, text_rela->addend)) {
++
+ /* case 1 */
+ rodata_rela = find_rela_by_dest(file->rodata,
+ text_rela->addend);
+objtool-support-gcc-8-s-cold-subfunctions.patch
+objtool-support-gcc-8-switch-tables.patch
+objtool-detect-rip-relative-switch-table-references.patch
+objtool-detect-rip-relative-switch-table-references-part-2.patch
+objtool-fix-noreturn-detection-for-recursive-sibling-calls.patch
+x86-mce-amd-carve-out-smca-get_block_address-code.patch
+x86-mce-amd-cache-smca-misc-block-addresses.patch
--- /dev/null
+From 78ce241099bb363b19dbd0245442e66c8de8f567 Mon Sep 17 00:00:00 2001
+From: Borislav Petkov <bp@suse.de>
+Date: Thu, 17 May 2018 10:46:26 +0200
+Subject: x86/MCE/AMD: Cache SMCA MISC block addresses
+
+From: Borislav Petkov <bp@suse.de>
+
+commit 78ce241099bb363b19dbd0245442e66c8de8f567 upstream.
+
+... into a global, two-dimensional array and service subsequent reads from
+that cache to avoid rdmsr_on_cpu() calls during CPU hotplug (IPIs with IRQs
+disabled).
+
+In addition, this fixes a KASAN slab-out-of-bounds read due to wrong usage
+of the bank->blocks pointer.
+
+Fixes: 27bd59502702 ("x86/mce/AMD: Get address from already initialized block")
+Reported-by: Johannes Hirte <johannes.hirte@datenkhaos.de>
+Tested-by: Johannes Hirte <johannes.hirte@datenkhaos.de>
+Signed-off-by: Borislav Petkov <bp@suse.de>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Cc: Yazen Ghannam <yazen.ghannam@amd.com>
+Link: http://lkml.kernel.org/r/20180414004230.GA2033@probook
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/kernel/cpu/mcheck/mce_amd.c | 29 ++++++++++++++---------------
+ 1 file changed, 14 insertions(+), 15 deletions(-)
+
+--- a/arch/x86/kernel/cpu/mcheck/mce_amd.c
++++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c
+@@ -94,6 +94,11 @@ static struct smca_bank_name smca_names[
+ [SMCA_SMU] = { "smu", "System Management Unit" },
+ };
+
++static u32 smca_bank_addrs[MAX_NR_BANKS][NR_BLOCKS] __ro_after_init =
++{
++ [0 ... MAX_NR_BANKS - 1] = { [0 ... NR_BLOCKS - 1] = -1 }
++};
++
+ const char *smca_get_name(enum smca_bank_types t)
+ {
+ if (t >= N_SMCA_BANK_TYPES)
+@@ -443,20 +448,26 @@ static u32 smca_get_block_address(unsign
+ if (!block)
+ return MSR_AMD64_SMCA_MCx_MISC(bank);
+
++ /* Check our cache first: */
++ if (smca_bank_addrs[bank][block] != -1)
++ return smca_bank_addrs[bank][block];
++
+ /*
+ * For SMCA enabled processors, BLKPTR field of the first MISC register
+ * (MCx_MISC0) indicates presence of additional MISC regs set (MISC1-4).
+ */
+ if (rdmsr_safe_on_cpu(cpu, MSR_AMD64_SMCA_MCx_CONFIG(bank), &low, &high))
+- return addr;
++ goto out;
+
+ if (!(low & MCI_CONFIG_MCAX))
+- return addr;
++ goto out;
+
+ if (!rdmsr_safe_on_cpu(cpu, MSR_AMD64_SMCA_MCx_MISC(bank), &low, &high) &&
+ (low & MASK_BLKPTR_LO))
+- return MSR_AMD64_SMCA_MCx_MISCy(bank, block - 1);
++ addr = MSR_AMD64_SMCA_MCx_MISCy(bank, block - 1);
+
++out:
++ smca_bank_addrs[bank][block] = addr;
+ return addr;
+ }
+
+@@ -468,18 +479,6 @@ static u32 get_block_address(unsigned in
+ if ((bank >= mca_cfg.banks) || (block >= NR_BLOCKS))
+ return addr;
+
+- /* Get address from already initialized block. */
+- if (per_cpu(threshold_banks, cpu)) {
+- struct threshold_bank *bankp = per_cpu(threshold_banks, cpu)[bank];
+-
+- if (bankp && bankp->blocks) {
+- struct threshold_block *blockp = &bankp->blocks[block];
+-
+- if (blockp)
+- return blockp->address;
+- }
+- }
+-
+ if (mce_flags.smca)
+ return smca_get_block_address(cpu, bank, block);
+
--- /dev/null
+From 8a331f4a0863bea758561c921b94b4d28f7c4029 Mon Sep 17 00:00:00 2001
+From: Yazen Ghannam <yazen.ghannam@amd.com>
+Date: Wed, 21 Feb 2018 11:19:00 +0100
+Subject: x86/mce/AMD: Carve out SMCA get_block_address() code
+
+From: Yazen Ghannam <yazen.ghannam@amd.com>
+
+commit 8a331f4a0863bea758561c921b94b4d28f7c4029 upstream.
+
+Carve out the SMCA code in get_block_address() into a separate helper
+function.
+
+No functional change.
+
+Signed-off-by: Yazen Ghannam <yazen.ghannam@amd.com>
+[ Save an indentation level. ]
+Signed-off-by: Borislav Petkov <bp@suse.de>
+Cc: Borislav Petkov <bp@alien8.de>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: Tony Luck <tony.luck@intel.com>
+Cc: linux-edac <linux-edac@vger.kernel.org>
+Link: http://lkml.kernel.org/r/20180215210943.11530-4-Yazen.Ghannam@amd.com
+Signed-off-by: Ingo Molnar <mingo@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/kernel/cpu/mcheck/mce_amd.c | 57 +++++++++++++++++++----------------
+ 1 file changed, 31 insertions(+), 26 deletions(-)
+
+--- a/arch/x86/kernel/cpu/mcheck/mce_amd.c
++++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c
+@@ -431,6 +431,35 @@ static void deferred_error_interrupt_ena
+ wrmsr(MSR_CU_DEF_ERR, low, high);
+ }
+
++static u32 smca_get_block_address(unsigned int cpu, unsigned int bank,
++ unsigned int block)
++{
++ u32 low, high;
++ u32 addr = 0;
++
++ if (smca_get_bank_type(bank) == SMCA_RESERVED)
++ return addr;
++
++ if (!block)
++ return MSR_AMD64_SMCA_MCx_MISC(bank);
++
++ /*
++ * For SMCA enabled processors, BLKPTR field of the first MISC register
++ * (MCx_MISC0) indicates presence of additional MISC regs set (MISC1-4).
++ */
++ if (rdmsr_safe_on_cpu(cpu, MSR_AMD64_SMCA_MCx_CONFIG(bank), &low, &high))
++ return addr;
++
++ if (!(low & MCI_CONFIG_MCAX))
++ return addr;
++
++ if (!rdmsr_safe_on_cpu(cpu, MSR_AMD64_SMCA_MCx_MISC(bank), &low, &high) &&
++ (low & MASK_BLKPTR_LO))
++ return MSR_AMD64_SMCA_MCx_MISCy(bank, block - 1);
++
++ return addr;
++}
++
+ static u32 get_block_address(unsigned int cpu, u32 current_addr, u32 low, u32 high,
+ unsigned int bank, unsigned int block)
+ {
+@@ -451,32 +480,8 @@ static u32 get_block_address(unsigned in
+ }
+ }
+
+- if (mce_flags.smca) {
+- if (smca_get_bank_type(bank) == SMCA_RESERVED)
+- return addr;
+-
+- if (!block) {
+- addr = MSR_AMD64_SMCA_MCx_MISC(bank);
+- } else {
+- /*
+- * For SMCA enabled processors, BLKPTR field of the
+- * first MISC register (MCx_MISC0) indicates presence of
+- * additional MISC register set (MISC1-4).
+- */
+- u32 low, high;
+-
+- if (rdmsr_safe_on_cpu(cpu, MSR_AMD64_SMCA_MCx_CONFIG(bank), &low, &high))
+- return addr;
+-
+- if (!(low & MCI_CONFIG_MCAX))
+- return addr;
+-
+- if (!rdmsr_safe_on_cpu(cpu, MSR_AMD64_SMCA_MCx_MISC(bank), &low, &high) &&
+- (low & MASK_BLKPTR_LO))
+- addr = MSR_AMD64_SMCA_MCx_MISCy(bank, block - 1);
+- }
+- return addr;
+- }
++ if (mce_flags.smca)
++ return smca_get_block_address(cpu, bank, block);
+
+ /* Fall back to method we used for older processors: */
+ switch (block) {