From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
To: linux-kernel@vger.kernel.org
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
stable@vger.kernel.org, Arnd Bergmann <arnd@arndb.de>,
Josh Poimboeuf <jpoimboe@redhat.com>,
"Peter Zijlstra (Intel)" <peterz@infradead.org>,
David Laight <David.Laight@ACULAB.COM>,
Linus Torvalds <torvalds@linux-foundation.org>,
Randy Dunlap <rdunlap@infradead.org>,
Thomas Gleixner <tglx@linutronix.de>,
Ingo Molnar <mingo@kernel.org>
Subject: [PATCH 4.9 21/29] objtool: Support GCC 8s cold subfunctions
Date: Mon, 4 Jun 2018 08:58:17 +0200 [thread overview]
Message-ID: <20180604065803.009101609@linuxfoundation.org> (raw)
In-Reply-To: <20180604065802.157744637@linuxfoundation.org>
4.9-stable review patch. If anyone has any objections, please let me know.
------------------
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 && \
@@ -148,10 +173,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)
@@ -166,35 +195,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);
}
}
@@ -421,7 +439,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;
}
}
@@ -781,9 +799,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;
@@ -793,18 +810,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) {
@@ -942,7 +954,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;
@@ -973,8 +985,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;
}
@@ -984,7 +995,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;
}
@@ -1748,15 +1759,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?",
@@ -1777,7 +1786,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;
@@ -1864,7 +1873,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)
@@ -2059,7 +2068,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,
next prev parent reply other threads:[~2018-06-04 7:00 UTC|newest]
Thread overview: 42+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-06-04 6:57 [PATCH 4.9 00/29] 4.9.106-stable review Greg Kroah-Hartman
2018-06-04 6:57 ` [PATCH 4.9 01/29] objtool: Improve detection of BUG() and other dead ends Greg Kroah-Hartman
2018-06-04 6:57 ` [PATCH 4.9 02/29] objtool: Move checking code to check.c Greg Kroah-Hartman
2018-06-04 6:57 ` [PATCH 4.9 03/29] tools lib: Add for_each_clear_bit macro Greg Kroah-Hartman
2018-06-04 6:58 ` [PATCH 4.9 04/29] tools: add more bitmap functions Greg Kroah-Hartman
2018-06-04 6:58 ` [PATCH 4.9 05/29] tools: enable endian checks for all sparse builds Greg Kroah-Hartman
2018-06-04 6:58 ` [PATCH 4.9 06/29] tools include: Introduce linux/compiler-gcc.h Greg Kroah-Hartman
2018-06-04 6:58 ` [PATCH 4.9 07/29] radix tree test suite: Remove types.h Greg Kroah-Hartman
2018-06-04 6:58 ` [PATCH 4.9 08/29] tools include: Adopt __compiletime_error Greg Kroah-Hartman
2018-06-04 6:58 ` Greg Kroah-Hartman
2018-06-04 6:58 ` [PATCH 4.9 09/29] tools include: Introduce atomic_cmpxchg_{relaxed,release}() Greg Kroah-Hartman
2018-06-04 6:58 ` [PATCH 4.9 10/29] tools include: Add UINT_MAX def to kernel.h Greg Kroah-Hartman
2018-06-04 6:58 ` [PATCH 4.9 11/29] tools include: Adopt kernels refcount.h Greg Kroah-Hartman
2018-06-04 6:58 ` [PATCH 4.9 12/29] perf tools: Force fixdep compilation at the start of the build Greg Kroah-Hartman
2018-06-04 6:58 ` [PATCH 4.9 13/29] perf tools: Move headers check into bash script Greg Kroah-Hartman
2018-06-04 6:58 ` [PATCH 4.9 14/29] tools include uapi: Grab copies of stat.h and fcntl.h Greg Kroah-Hartman
2018-06-04 6:58 ` [PATCH 4.9 15/29] tools include: Introduce linux/bug.h, from the kernel sources Greg Kroah-Hartman
2018-06-04 6:58 ` [PATCH 4.9 16/29] tools include: Adopt __same_type() and __must_be_array() from the kernel Greg Kroah-Hartman
2018-06-04 6:58 ` [PATCH 4.9 17/29] tools include: Move ARRAY_SIZE() to linux/kernel.h Greg Kroah-Hartman
2018-06-04 6:58 ` [PATCH 4.9 18/29] tools include: Drop ARRAY_SIZE() definition from linux/hashtable.h Greg Kroah-Hartman
2018-06-04 6:58 ` [PATCH 4.9 19/29] tools include: Include missing headers for fls() and types in linux/log2.h Greg Kroah-Hartman
2018-06-04 6:58 ` [PATCH 4.9 20/29] objtool: sync up with the 4.14.47 version of objtool Greg Kroah-Hartman
2018-06-04 6:58 ` Greg Kroah-Hartman [this message]
2018-06-04 6:58 ` [PATCH 4.9 22/29] objtool: Support GCC 8 switch tables Greg Kroah-Hartman
2018-06-04 6:58 ` [PATCH 4.9 23/29] objtool: Detect RIP-relative switch table references Greg Kroah-Hartman
2018-06-04 6:58 ` [PATCH 4.9 24/29] objtool: Detect RIP-relative switch table references, part 2 Greg Kroah-Hartman
2018-06-04 6:58 ` [PATCH 4.9 25/29] objtool: Fix "noreturn" detection for recursive sibling calls Greg Kroah-Hartman
2018-06-04 6:58 ` [PATCH 4.9 26/29] objtool, x86: Add several functions and files to the objtool whitelist Greg Kroah-Hartman
2018-06-04 6:58 ` [PATCH 4.9 27/29] perf/tools: header file sync up Greg Kroah-Hartman
2018-06-04 6:58 ` [PATCH 4.9 28/29] objtool: header file sync-up Greg Kroah-Hartman
2018-06-04 6:58 ` [PATCH 4.9 29/29] x86/xen: Add unwind hint annotations to xen_setup_gdt Greg Kroah-Hartman
2018-06-04 10:15 ` [PATCH 4.9 00/29] 4.9.106-stable review Guenter Roeck
2018-06-04 11:27 ` Greg Kroah-Hartman
2018-06-04 12:21 ` Greg Kroah-Hartman
2018-06-04 16:16 ` Guenter Roeck
2018-06-04 16:54 ` Guenter Roeck
2018-06-04 16:57 ` Greg Kroah-Hartman
2018-06-04 17:04 ` Guenter Roeck
2018-06-04 16:58 ` Greg Kroah-Hartman
2018-06-04 19:46 ` Shuah Khan
2018-06-05 6:14 ` Naresh Kamboju
[not found] ` <5b152b7c.1c69fb81.3f04a.096f@mx.google.com>
[not found] ` <7hr2lmjgcd.fsf@baylibre.com>
2018-06-05 10:51 ` Mark Brown
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180604065803.009101609@linuxfoundation.org \
--to=gregkh@linuxfoundation.org \
--cc=David.Laight@ACULAB.COM \
--cc=arnd@arndb.de \
--cc=jpoimboe@redhat.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@kernel.org \
--cc=peterz@infradead.org \
--cc=rdunlap@infradead.org \
--cc=stable@vger.kernel.org \
--cc=tglx@linutronix.de \
--cc=torvalds@linux-foundation.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.