[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20241125130613.GO38972@noisy.programming.kicks-ass.net>
Date: Mon, 25 Nov 2024 14:06:13 +0100
From: Peter Zijlstra <peterz@...radead.org>
To: Josh Poimboeuf <jpoimboe@...hat.com>
Cc: linux-kernel@...r.kernel.org
Subject: Re: [PATCH 9/9] objtool: Collect all annotations in objtool.h
On Sat, Nov 23, 2024 at 02:19:43PM +0100, Peter Zijlstra wrote:
> > BTW, is there a reason .discard.[un]reachable weren't converted over?
>
> Completely forgot/missed them. Let me add a patch.
So this is turning into a bit of a trainwreck :/
That is, the below works, but I ended up having to include objtool.h
from compiler.h, which is really unfortunate.
--- a/arch/loongarch/include/asm/bug.h
+++ b/arch/loongarch/include/asm/bug.h
@@ -4,6 +4,7 @@
#include <asm/break.h>
#include <linux/stringify.h>
+#include <linux/objtool.h>
#ifndef CONFIG_DEBUG_BUGVERBOSE
#define _BUGVERBOSE_LOCATION(file, line)
--- a/arch/x86/entry/entry_64.S
+++ b/arch/x86/entry/entry_64.S
@@ -311,7 +311,7 @@ SYM_CODE_END(xen_error_entry)
call \cfunc
/* For some configurations \cfunc ends up being a noreturn. */
- REACHABLE
+ ANNOTATE_REACHABLE
jmp error_return
.endm
@@ -532,7 +532,7 @@ SYM_CODE_START(\asmsym)
call \cfunc
/* For some configurations \cfunc ends up being a noreturn. */
- REACHABLE
+ ANNOTATE_REACHABLE
jmp paranoid_exit
--- a/arch/x86/include/asm/bug.h
+++ b/arch/x86/include/asm/bug.h
@@ -92,7 +92,7 @@ do { \
do { \
__auto_type __flags = BUGFLAG_WARNING|(flags); \
instrumentation_begin(); \
- _BUG_FLAGS(ASM_UD2, __flags, ASM_REACHABLE); \
+ _BUG_FLAGS(ASM_UD2, __flags, ANNOTATE_REACHABLE); \
instrumentation_end(); \
} while (0)
--- a/arch/x86/include/asm/irq_stack.h
+++ b/arch/x86/include/asm/irq_stack.h
@@ -101,7 +101,7 @@
#define ASM_CALL_ARG0 \
"call %c[__func] \n" \
- ASM_REACHABLE
+ ANNOTATE_REACHABLE
#define ASM_CALL_ARG1 \
"movq %[arg1], %%rdi \n" \
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -3,6 +3,7 @@
#define __LINUX_COMPILER_H
#include <linux/compiler_types.h>
+#include <linux/objtool.h>
#ifndef __ASSEMBLY__
@@ -107,37 +108,10 @@ void ftrace_likely_update(struct ftrace_
# define barrier_before_unreachable() do { } while (0)
#endif
-/* Unreachable code */
#ifdef CONFIG_OBJTOOL
-/*
- * These macros help objtool understand GCC code flow for unreachable code.
- * The __COUNTER__ based labels are a hack to make each instance of the macros
- * unique, to convince GCC not to merge duplicate inline asm statements.
- */
-#define __stringify_label(n) #n
-
-#define __annotate_reachable(c) ({ \
- asm volatile(__stringify_label(c) ":\n\t" \
- ".pushsection .discard.reachable\n\t" \
- ".long " __stringify_label(c) "b - .\n\t" \
- ".popsection\n\t"); \
-})
-#define annotate_reachable() __annotate_reachable(__COUNTER__)
-
-#define __annotate_unreachable(c) ({ \
- asm volatile(__stringify_label(c) ":\n\t" \
- ".pushsection .discard.unreachable\n\t" \
- ".long " __stringify_label(c) "b - .\n\t" \
- ".popsection\n\t" : : "i" (c)); \
-})
-#define annotate_unreachable() __annotate_unreachable(__COUNTER__)
-
/* Annotate a C jump table to allow objtool to follow the code flow */
#define __annotate_jump_table __section(".rodata..c_jump_table,\"a\",@progbits #")
-
#else /* !CONFIG_OBJTOOL */
-#define annotate_reachable()
-#define annotate_unreachable()
#define __annotate_jump_table
#endif /* CONFIG_OBJTOOL */
--- a/include/linux/instrumentation.h
+++ b/include/linux/instrumentation.h
@@ -6,12 +6,11 @@
#include <linux/objtool.h>
#include <linux/stringify.h>
-#include <linux/args.h>
/* Begin/end of an instrumentation safe region */
#define __instrumentation_begin(c) ({ \
asm volatile(__stringify(c) ": nop\n\t" \
- __ASM_ANNOTATE(CONCATENATE(c, b), ANNOTYPE_INSTR_BEGIN) \
+ __ASM_ANNOTATE(__ASM_BREF(c), ANNOTYPE_INSTR_BEGIN)\
: : "i" (c)); \
})
#define instrumentation_begin() __instrumentation_begin(__COUNTER__)
@@ -49,7 +48,7 @@
*/
#define __instrumentation_end(c) ({ \
asm volatile(__stringify(c) ": nop\n\t" \
- __ASM_ANNOTATE(CONCATENATE(c, b), ANNOTYPE_INSTR_END) \
+ __ASM_ANNOTATE(__ASM_BREF(c), ANNOTYPE_INSTR_END) \
: : "i" (c)); \
})
#define instrumentation_end() __instrumentation_end(__COUNTER__)
--- a/include/linux/objtool.h
+++ b/include/linux/objtool.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _LINUX_OBJTOOL_H
#define _LINUX_OBJTOOL_H
+#ifndef LINKER_SCRIPT
#include <linux/objtool_types.h>
@@ -45,21 +46,19 @@
#define STACK_FRAME_NON_STANDARD_FP(func)
#endif
-#define ASM_REACHABLE \
- "998:\n\t" \
- ".pushsection .discard.reachable\n\t" \
- ".long 998b\n\t" \
- ".popsection\n\t"
-
#define __ASM_ANNOTATE(s, x) \
".pushsection .discard.annotate_insn,\"M\",@progbits,8\n\t" \
".long " __stringify(s) " - .\n\t" \
".long " __stringify(x) "\n\t" \
".popsection\n\t"
-#define ASM_ANNOTATE(x) \
- "911:\n\t" \
- __ASM_ANNOTATE(911b, x)
+#define __ASM_BREF(s) s ## b
+
+#define _ASM_ANNOTATE(s, x) \
+ __stringify(s) ":\n\t" \
+ __ASM_ANNOTATE(__ASM_BREF(s), x)
+
+#define ASM_ANNOTATE(x) _ASM_ANNOTATE(__COUNTER__, x)
#else /* __ASSEMBLY__ */
@@ -109,14 +108,6 @@
#endif
.endm
-
-.macro REACHABLE
-.Lhere_\@:
- .pushsection .discard.reachable
- .long .Lhere_\@
- .popsection
-.endm
-
.macro ANNOTATE type:req
.Lhere_\@:
.pushsection .discard.annotate_insn,"M",@progbits,8
@@ -135,14 +126,11 @@
#define STACK_FRAME_NON_STANDARD(func)
#define STACK_FRAME_NON_STANDARD_FP(func)
#define ASM_ANNOTATE(x)
-#define ASM_REACHABLE
#else
.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 signal=0
.endm
.macro STACK_FRAME_NON_STANDARD func:req
.endm
-.macro REACHABLE
-.endm
.macro ANNOTATE type:req
.endm
#endif
@@ -180,12 +168,17 @@
*/
#define ANNOTATE_UNRET_BEGIN ASM_ANNOTATE(ANNOTYPE_UNRET_BEGIN)
+#define ANNOTATE_REACHABLE ASM_ANNOTATE(ANNOTYPE_REACHABLE)
+#define ANNOTATE_UNREACHABLE ASM_ANNOTATE(ANNOTYPE_UNREACHABLE)
+
#else
#define ANNOTATE_NOENDBR ANNOTATE type=ANNOTYPE_NOENDBR
#define ANNOTATE_RETPOLINE_SAFE ANNOTATE type=ANNOTYPE_RETPOLINE_SAFE
#define ANNOTATE_IGNORE_ALTERNATIVE ANNOTATE type=ANNOTYPE_IGNORE_ALTS
#define ANNOTATE_INTRA_FUNCTION_CALL ANNOTATE type=ANNOTYPE_INTRA_FUNCTION_CALL
#define ANNOTATE_UNRET_BEGIN ANNOTATE type=ANNOTYPE_UNRET_BEGIN
+#define ANNOTATE_REACHABLE ANNOTATE type=ANNOTYPE_REACHABLE
+#define ANNOTATE_UNREACHABLE ANNOTATE type=ANNOTYPE_UNREACHABLE
#endif
#if defined(CONFIG_NOINSTR_VALIDATION) && \
@@ -195,4 +188,13 @@
#define VALIDATE_UNRET_BEGIN
#endif
+#define annotate_reachable() ({ \
+ asm volatile (ANNOTATE_REACHABLE); \
+})
+
+#define annotate_unreachable() ({ \
+ asm volatile (ANNOTATE_UNREACHABLE); \
+})
+
+#endif /* LINKER_SCRIPT */
#endif /* _LINUX_OBJTOOL_H */
--- a/include/linux/objtool_types.h
+++ b/include/linux/objtool_types.h
@@ -64,5 +64,7 @@ struct unwind_hint {
#define ANNOTYPE_UNRET_BEGIN 5
#define ANNOTYPE_IGNORE_ALTS 6
#define ANNOTYPE_INTRA_FUNCTION_CALL 7
+#define ANNOTYPE_REACHABLE 8
+#define ANNOTYPE_UNREACHABLE 9
#endif /* _LINUX_OBJTOOL_TYPES_H */
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -627,95 +627,6 @@ static struct instruction *find_last_ins
return insn;
}
-/*
- * Mark "ud2" instructions and manually annotated dead ends.
- */
-static int add_dead_ends(struct objtool_file *file)
-{
- struct section *rsec;
- struct reloc *reloc;
- struct instruction *insn;
- uint64_t offset;
-
- /*
- * Check for manually annotated dead ends.
- */
- rsec = find_section_by_name(file->elf, ".rela.discard.unreachable");
- if (!rsec)
- goto reachable;
-
- for_each_reloc(rsec, reloc) {
- if (reloc->sym->type == STT_SECTION) {
- offset = reloc_addend(reloc);
- } else if (reloc->sym->local_label) {
- offset = reloc->sym->offset;
- } else {
- WARN("unexpected relocation symbol type in %s", rsec->name);
- return -1;
- }
-
- insn = find_insn(file, reloc->sym->sec, offset);
- if (insn)
- insn = prev_insn_same_sec(file, insn);
- else if (offset == reloc->sym->sec->sh.sh_size) {
- insn = find_last_insn(file, reloc->sym->sec);
- if (!insn) {
- WARN("can't find unreachable insn at %s+0x%" PRIx64,
- reloc->sym->sec->name, offset);
- return -1;
- }
- } else {
- WARN("can't find unreachable insn at %s+0x%" PRIx64,
- reloc->sym->sec->name, offset);
- return -1;
- }
-
- insn->dead_end = true;
- }
-
-reachable:
- /*
- * These manually annotated reachable checks are needed for GCC 4.4,
- * where the Linux unreachable() macro isn't supported. In that case
- * GCC doesn't know the "ud2" is fatal, so it generates code as if it's
- * not a dead end.
- */
- rsec = find_section_by_name(file->elf, ".rela.discard.reachable");
- if (!rsec)
- return 0;
-
- for_each_reloc(rsec, reloc) {
- if (reloc->sym->type == STT_SECTION) {
- offset = reloc_addend(reloc);
- } else if (reloc->sym->local_label) {
- offset = reloc->sym->offset;
- } else {
- WARN("unexpected relocation symbol type in %s", rsec->name);
- return -1;
- }
-
- insn = find_insn(file, reloc->sym->sec, offset);
- if (insn)
- insn = prev_insn_same_sec(file, insn);
- else if (offset == reloc->sym->sec->sh.sh_size) {
- insn = find_last_insn(file, reloc->sym->sec);
- if (!insn) {
- WARN("can't find reachable insn at %s+0x%" PRIx64,
- reloc->sym->sec->name, offset);
- return -1;
- }
- } else {
- WARN("can't find reachable insn at %s+0x%" PRIx64,
- reloc->sym->sec->name, offset);
- return -1;
- }
-
- insn->dead_end = false;
- }
-
- return 0;
-}
-
static int create_static_call_sections(struct objtool_file *file)
{
struct static_call_site *site;
@@ -2345,6 +2256,7 @@ static int read_annotate(struct objtool_
struct section *sec;
struct instruction *insn;
struct reloc *reloc;
+ uint64_t offset;
int type, ret;
sec = find_section_by_name(file->elf, ".discard.annotate_insn");
@@ -2366,8 +2278,19 @@ static int read_annotate(struct objtool_
for_each_reloc(sec->rsec, reloc) {
type = *(u32 *)(sec->data->d_buf + (reloc_idx(reloc) * sec->sh.sh_entsize) + 4);
- insn = find_insn(file, reloc->sym->sec,
- reloc->sym->offset + reloc_addend(reloc));
+ offset = reloc->sym->offset + reloc_addend(reloc);
+ insn = find_insn(file, reloc->sym->sec, offset);
+
+ /*
+ * Reachable annotations are 'funneh' and act on the previous instruction :/
+ */
+ if (type == ANNOTYPE_REACHABLE || type == ANNOTYPE_UNREACHABLE) {
+ if (insn)
+ insn = prev_insn_same_sec(file, insn);
+ else if (offset == reloc->sym->sec->sh.sh_size)
+ insn = find_last_insn(file, reloc->sym->sec);
+ }
+
if (!insn) {
WARN("bad .discard.annotate_insn entry: %d of type %d", reloc_idx(reloc), type);
return -1;
@@ -2459,6 +2382,14 @@ static int __annotate_late(struct objtoo
insn->unret = 1;
break;
+ case ANNOTYPE_REACHABLE:
+ insn->dead_end = false;
+ break;
+
+ case ANNOTYPE_UNREACHABLE:
+ insn->dead_end = true;
+ break;
+
default:
break;
}
@@ -2605,14 +2536,6 @@ static int decode_sections(struct objtoo
if (ret)
return ret;
- /*
- * Must be after add_call_destinations() such that it can override
- * dead_end_function() marks.
- */
- ret = add_dead_ends(file);
- if (ret)
- return ret;
-
ret = add_jump_table_alts(file);
if (ret)
return ret;
@@ -2621,6 +2544,10 @@ static int decode_sections(struct objtoo
if (ret)
return ret;
+ /*
+ * Must be after add_call_destinations() such that it can override
+ * dead_end_function() marks.
+ */
ret = read_annotate(file, __annotate_late);
if (ret)
return ret;
Powered by blists - more mailing lists