Live Patching
 help / color / mirror / Atom feed
* [RFC PATCH v1 00/23] LoongArch: Add objtool and ORC unwinder support
@ 2023-06-20  7:46 Youling Tang
  2023-06-20  7:46 ` [RFC PATCH v1 01/23] objtool: Reorganize CFI code Youling Tang
                   ` (5 more replies)
  0 siblings, 6 replies; 12+ messages in thread
From: Youling Tang @ 2023-06-20  7:46 UTC (permalink / raw)
  To: Josh Poimboeuf, Peter Zijlstra, Huacai Chen, madvenka
  Cc: chenzhongjin, WANG Xuerui, Xi Ruoyao, live-patching, linux-kernel,
	loongarch, tangyouling00, youling.tang

This series of patches adds objtool and ORC unwinder support for
LoongArch.

Patch 01 - 07 are from "Madhavan T. Venkataraman" [1] with minor
code tweaks. The "objtool: Reorganize ORC types" patch was not
added, because LoongArch cannot share `strcut orc_entry`, it also
needs to include ra_offset and ra_reg.

Since the changes in Patch 01 - 08 in [1] are architecture-independent,
it might be better if they could be separated separately from the series
of patches.

ORC unwinder can get a reliable stack trace, which provides a prerequisite
for the subsequent addition of livepatch support.


Instruction decoder
===================

To do this, an instruction decoder needs to be implemented. I have implemented
a simple, table-driven decoder for LoongArch. Only a subset of the instructions
needs to be fully decoded for this purpose:

	- Load-Store instructions
	- Add instructions
	- Branch instructions
	- Call instructions
	- Return instructions
	- Stack pointer authentication instruction


Unwind hints
============

Unwind hints are collected in a special section. Objtool converts unwind hints
to ORC data. The unwinder processes unwind hints to handle special cases
mentioned above.


ORC unwinder
============

Before vmlinux created, we check all metadata, find the stack operation,
note stack state and create orc data. Objtool insert two sections into
vmlinux. '.orc_unwind_ip' and '.orc_unwind'. (For modules, insert
'.rela.orc_unwind_ip' to relocate '.orc_unwind_ip'.) Each insn has only
one stack state in .orc_unwind and orc_unwind_ip hint its pc address.
Through unwinding orc data, we can get stack info both kernel and module.


This is a series of RFC patches, which may require long-term discussions
and revisions. It is not based on the latest code but based on 6.3-rc3.
Any ideas or suggestions are welcome.

base-commit: e8d018dd0257f744ca50a729e3d042cf2ec9da65 (Linux 6.3-rc3)

Link:
[1]: https://lore.kernel.org/lkml/20230202074036.507249-1-madvenka@linux.microsoft.com/#r

Madhavan T. Venkataraman (7):
  objtool: Reorganize CFI code
  objtool: Reorganize instruction-related code
  objtool: Move decode_instructions() to a separate file
  objtool: Reorganize Unwind hint code
  objtool: Reorganize ORC code
  objtool: Reorganize ORC kernel code
  objtool: Introduce STATIC_CHECK

Youling Tang (16):
  tools: LoongArch: Copy inst.h and asm.h to tools
  objtool: LoongArch: Add base definition for LoongArch
  objtool: LoongArch: Implement decoder
  objtool: Add annotate_reachable() for objtools
  LoongArch: bug: Add reachable annotation to warning macros
  objtool: Add next member in struct reloc
  objtool: Add orc_print_dump() package
  objtool: Add ORC support for LoongArch
  LoongArch: Add ORC unwinder support
  LoongArch: Support R_LARCH_32_PCREL relocation type in kernel module
  LoongArch: Fix fpu.S objtool warning
  LoongArch: Annotate unwind_hint
  LoongArch: Move some data definitions into the .data section
  objtool: Add arch-specific "noreturn" function handling
  objtool: Make update_cfi_state() arch-specific function
  LoongArch: objtool: Mark non-standard object files and directories

 arch/loongarch/Kconfig                        |   2 +
 arch/loongarch/Kconfig.debug                  |  11 +
 arch/loongarch/Makefile                       |   4 +
 arch/loongarch/include/asm/bug.h              |   1 +
 arch/loongarch/include/asm/module.h           |   7 +
 arch/loongarch/include/asm/orc_types.h        |  58 ++
 arch/loongarch/include/asm/stackframe.h       |   3 +
 arch/loongarch/include/asm/unwind.h           |  17 +-
 arch/loongarch/include/asm/unwind_hints.h     | 110 +++
 arch/loongarch/kernel/Makefile                |   3 +
 arch/loongarch/kernel/entry.S                 |   2 +
 arch/loongarch/kernel/fpu.S                   |  11 +-
 arch/loongarch/kernel/genex.S                 |   2 +
 arch/loongarch/kernel/head.S                  |   1 +
 arch/loongarch/kernel/module.c                |  21 +-
 arch/loongarch/kernel/relocate_kernel.S       |  12 +-
 arch/loongarch/kernel/setup.c                 |   2 +
 arch/loongarch/kernel/stacktrace.c            |   1 +
 arch/loongarch/kernel/unwind_orc.c            | 301 +++++++++
 arch/loongarch/kernel/vmlinux.lds.S           |   3 +
 arch/loongarch/power/Makefile                 |   2 +
 arch/loongarch/vdso/Makefile                  |   2 +
 arch/x86/include/asm/unwind.h                 |   5 -
 arch/x86/include/asm/unwind_hints.h           |  86 +++
 arch/x86/kernel/module.c                      |   7 +-
 arch/x86/kernel/unwind_orc.c                  | 268 +-------
 arch/x86/kernel/vmlinux.lds.S                 |   2 +-
 .../asm => include/asm-generic}/orc_lookup.h  |  43 ++
 include/linux/compiler.h                      |   9 +
 include/linux/objtool.h                       |  70 --
 kernel/Makefile                               |   2 +
 kernel/orc_lookup.c                           | 261 ++++++++
 scripts/Makefile                              |   5 +-
 tools/arch/loongarch/include/asm/asm.h        | 201 ++++++
 tools/arch/loongarch/include/asm/inst.h       | 629 ++++++++++++++++++
 tools/arch/loongarch/include/asm/orc_types.h  |  58 ++
 .../arch/loongarch/include/asm/unwind_hints.h | 110 +++
 tools/arch/x86/include/asm/unwind_hints.h     | 160 +++++
 tools/include/linux/bitops.h                  |  10 +
 tools/include/linux/objtool.h                 |  70 --
 tools/objtool/Build                           |   8 +-
 tools/objtool/Makefile                        |   9 +-
 tools/objtool/arch/loongarch/Build            |   3 +
 tools/objtool/arch/loongarch/decode.c         | 352 ++++++++++
 .../arch/loongarch/include/arch/cfi_regs.h    |  14 +
 .../objtool/arch/loongarch/include/arch/elf.h |  15 +
 .../arch/loongarch/include/arch/special.h     |  21 +
 tools/objtool/arch/loongarch/orc.c            | 155 +++++
 tools/objtool/arch/loongarch/special.c        |  25 +
 tools/objtool/arch/powerpc/special.c          |   3 +
 tools/objtool/arch/x86/Build                  |   1 +
 tools/objtool/arch/x86/include/arch/elf.h     |   1 +
 tools/objtool/arch/x86/orc.c                  | 164 +++++
 tools/objtool/arch/x86/special.c              |   4 +
 tools/objtool/cfi.c                           | 108 +++
 tools/objtool/check.c                         | 568 +---------------
 tools/objtool/decode.c                        | 136 ++++
 tools/objtool/elf.c                           |  11 +-
 tools/objtool/include/objtool/arch.h          |   3 +
 tools/objtool/include/objtool/cfi.h           |  12 +
 tools/objtool/include/objtool/check.h         |  97 +--
 tools/objtool/include/objtool/elf.h           |   1 +
 tools/objtool/include/objtool/insn.h          | 166 +++++
 tools/objtool/include/objtool/objtool.h       |   3 +
 tools/objtool/include/objtool/orc.h           |  15 +
 tools/objtool/include/objtool/special.h       |   3 +
 tools/objtool/insn.c                          | 195 ++++++
 tools/objtool/orc_dump.c                      |  67 +-
 tools/objtool/orc_gen.c                       |  79 +--
 tools/objtool/sync-check.sh                   |   9 +
 tools/objtool/unwind_hints.c                  | 107 +++
 71 files changed, 3721 insertions(+), 1206 deletions(-)
 create mode 100644 arch/loongarch/include/asm/orc_types.h
 create mode 100644 arch/loongarch/include/asm/unwind_hints.h
 create mode 100644 arch/loongarch/kernel/unwind_orc.c
 rename {arch/x86/include/asm => include/asm-generic}/orc_lookup.h (50%)
 create mode 100644 kernel/orc_lookup.c
 create mode 100644 tools/arch/loongarch/include/asm/asm.h
 create mode 100644 tools/arch/loongarch/include/asm/inst.h
 create mode 100644 tools/arch/loongarch/include/asm/orc_types.h
 create mode 100644 tools/arch/loongarch/include/asm/unwind_hints.h
 create mode 100644 tools/arch/x86/include/asm/unwind_hints.h
 create mode 100644 tools/objtool/arch/loongarch/Build
 create mode 100644 tools/objtool/arch/loongarch/decode.c
 create mode 100644 tools/objtool/arch/loongarch/include/arch/cfi_regs.h
 create mode 100644 tools/objtool/arch/loongarch/include/arch/elf.h
 create mode 100644 tools/objtool/arch/loongarch/include/arch/special.h
 create mode 100644 tools/objtool/arch/loongarch/orc.c
 create mode 100644 tools/objtool/arch/loongarch/special.c
 create mode 100644 tools/objtool/arch/x86/orc.c
 create mode 100644 tools/objtool/cfi.c
 create mode 100644 tools/objtool/decode.c
 create mode 100644 tools/objtool/include/objtool/insn.h
 create mode 100644 tools/objtool/include/objtool/orc.h
 create mode 100644 tools/objtool/insn.c
 create mode 100644 tools/objtool/unwind_hints.c

-- 
2.39.2


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [RFC PATCH v1 01/23] objtool: Reorganize CFI code
  2023-06-20  7:46 [RFC PATCH v1 00/23] LoongArch: Add objtool and ORC unwinder support Youling Tang
@ 2023-06-20  7:46 ` Youling Tang
  2023-06-20  7:46 ` [RFC PATCH v1 02/23] objtool: Reorganize instruction-related code Youling Tang
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 12+ messages in thread
From: Youling Tang @ 2023-06-20  7:46 UTC (permalink / raw)
  To: Josh Poimboeuf, Peter Zijlstra, Huacai Chen, madvenka
  Cc: chenzhongjin, WANG Xuerui, Xi Ruoyao, live-patching, linux-kernel,
	loongarch, tangyouling00, youling.tang

From: "Madhavan T. Venkataraman" <madvenka@linux.microsoft.com>

check.c implements static stack validation. But the CFI code that it
contains can be shared with other types of validation. E.g., dynamic FP
validation. Move the CFI code to its own files - cfi.h and cfi.c.

Signed-off-by: Madhavan T. Venkataraman <madvenka@linux.microsoft.com>
---
 tools/objtool/Build                 |   1 +
 tools/objtool/cfi.c                 | 108 ++++++++++++++++++++++++++++
 tools/objtool/check.c               |  96 -------------------------
 tools/objtool/include/objtool/cfi.h |  12 ++++
 4 files changed, 121 insertions(+), 96 deletions(-)
 create mode 100644 tools/objtool/cfi.c

diff --git a/tools/objtool/Build b/tools/objtool/Build
index a3cdf8af6635..9f23d1f4c716 100644
--- a/tools/objtool/Build
+++ b/tools/objtool/Build
@@ -5,6 +5,7 @@ objtool-y += weak.o
 objtool-y += check.o
 objtool-y += special.o
 objtool-y += builtin-check.o
+objtool-y += cfi.o
 objtool-y += elf.o
 objtool-y += objtool.o
 
diff --git a/tools/objtool/cfi.c b/tools/objtool/cfi.c
new file mode 100644
index 000000000000..18b460e066c8
--- /dev/null
+++ b/tools/objtool/cfi.c
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2015-2017 Josh Poimboeuf <jpoimboe@redhat.com>
+ */
+
+#include <stdlib.h>
+#include <sys/mman.h>
+
+#include <objtool/cfi.h>
+#include <objtool/builtin.h>
+#include <objtool/warn.h>
+
+unsigned long nr_cfi, nr_cfi_reused, nr_cfi_cache;
+
+struct cfi_init_state initial_func_cfi;
+struct cfi_state init_cfi;
+struct cfi_state func_cfi;
+
+void init_cfi_state(struct cfi_state *cfi)
+{
+	int i;
+
+	for (i = 0; i < CFI_NUM_REGS; i++) {
+		cfi->regs[i].base = CFI_UNDEFINED;
+		cfi->vals[i].base = CFI_UNDEFINED;
+	}
+	cfi->cfa.base = CFI_UNDEFINED;
+	cfi->drap_reg = CFI_UNDEFINED;
+	cfi->drap_offset = -1;
+}
+
+static struct cfi_state *cfi_alloc(void)
+{
+	struct cfi_state *cfi = calloc(sizeof(struct cfi_state), 1);
+
+	if (!cfi) {
+		WARN("calloc failed");
+		exit(1);
+	}
+	nr_cfi++;
+	return cfi;
+}
+
+static int cfi_bits;
+static struct hlist_head *cfi_hash;
+
+inline bool cficmp(struct cfi_state *cfi1, struct cfi_state *cfi2)
+{
+	return memcmp((void *)cfi1 + sizeof(cfi1->hash),
+		      (void *)cfi2 + sizeof(cfi2->hash),
+		      sizeof(struct cfi_state) - sizeof(struct hlist_node));
+}
+
+static inline u32 cfi_key(struct cfi_state *cfi)
+{
+	return jhash((void *)cfi + sizeof(cfi->hash),
+		     sizeof(*cfi) - sizeof(cfi->hash), 0);
+}
+
+struct cfi_state *cfi_hash_find_or_add(struct cfi_state *cfi)
+{
+	struct hlist_head *head = &cfi_hash[hash_min(cfi_key(cfi), cfi_bits)];
+	struct cfi_state *obj;
+
+	hlist_for_each_entry(obj, head, hash) {
+		if (!cficmp(cfi, obj)) {
+			nr_cfi_cache++;
+			return obj;
+		}
+	}
+
+	obj = cfi_alloc();
+	*obj = *cfi;
+	hlist_add_head(&obj->hash, head);
+
+	return obj;
+}
+
+void cfi_hash_add(struct cfi_state *cfi)
+{
+	struct hlist_head *head = &cfi_hash[hash_min(cfi_key(cfi), cfi_bits)];
+
+	hlist_add_head(&cfi->hash, head);
+}
+
+void *cfi_hash_alloc(unsigned long size)
+{
+	cfi_bits = max(10, ilog2(size));
+	cfi_hash = mmap(NULL, sizeof(struct hlist_head) << cfi_bits,
+			PROT_READ|PROT_WRITE,
+			MAP_PRIVATE|MAP_ANON, -1, 0);
+	if (cfi_hash == (void *)-1L) {
+		WARN("mmap fail cfi_hash");
+		cfi_hash = NULL;
+	}  else if (opts.stats) {
+		printf("cfi_bits: %d\n", cfi_bits);
+	}
+
+	return cfi_hash;
+}
+
+void set_func_state(struct cfi_state *state)
+{
+	state->cfa = initial_func_cfi.cfa;
+	memcpy(&state->regs, &initial_func_cfi.regs,
+	       CFI_NUM_REGS * sizeof(struct cfi_reg));
+	state->stack_size = initial_func_cfi.cfa.offset;
+}
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index f937be1afe65..803764f4d4d8 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -28,12 +28,6 @@ struct alternative {
 	bool skip_orig;
 };
 
-static unsigned long nr_cfi, nr_cfi_reused, nr_cfi_cache;
-
-static struct cfi_init_state initial_func_cfi;
-static struct cfi_state init_cfi;
-static struct cfi_state func_cfi;
-
 struct instruction *find_insn(struct objtool_file *file,
 			      struct section *sec, unsigned long offset)
 {
@@ -288,19 +282,6 @@ static bool dead_end_function(struct objtool_file *file, struct symbol *func)
 	return __dead_end_function(file, func, 0);
 }
 
-static void init_cfi_state(struct cfi_state *cfi)
-{
-	int i;
-
-	for (i = 0; i < CFI_NUM_REGS; i++) {
-		cfi->regs[i].base = CFI_UNDEFINED;
-		cfi->vals[i].base = CFI_UNDEFINED;
-	}
-	cfi->cfa.base = CFI_UNDEFINED;
-	cfi->drap_reg = CFI_UNDEFINED;
-	cfi->drap_offset = -1;
-}
-
 static void init_insn_state(struct objtool_file *file, struct insn_state *state,
 			    struct section *sec)
 {
@@ -316,75 +297,6 @@ static void init_insn_state(struct objtool_file *file, struct insn_state *state,
 		state->noinstr = sec->noinstr;
 }
 
-static struct cfi_state *cfi_alloc(void)
-{
-	struct cfi_state *cfi = calloc(sizeof(struct cfi_state), 1);
-	if (!cfi) {
-		WARN("calloc failed");
-		exit(1);
-	}
-	nr_cfi++;
-	return cfi;
-}
-
-static int cfi_bits;
-static struct hlist_head *cfi_hash;
-
-static inline bool cficmp(struct cfi_state *cfi1, struct cfi_state *cfi2)
-{
-	return memcmp((void *)cfi1 + sizeof(cfi1->hash),
-		      (void *)cfi2 + sizeof(cfi2->hash),
-		      sizeof(struct cfi_state) - sizeof(struct hlist_node));
-}
-
-static inline u32 cfi_key(struct cfi_state *cfi)
-{
-	return jhash((void *)cfi + sizeof(cfi->hash),
-		     sizeof(*cfi) - sizeof(cfi->hash), 0);
-}
-
-static struct cfi_state *cfi_hash_find_or_add(struct cfi_state *cfi)
-{
-	struct hlist_head *head = &cfi_hash[hash_min(cfi_key(cfi), cfi_bits)];
-	struct cfi_state *obj;
-
-	hlist_for_each_entry(obj, head, hash) {
-		if (!cficmp(cfi, obj)) {
-			nr_cfi_cache++;
-			return obj;
-		}
-	}
-
-	obj = cfi_alloc();
-	*obj = *cfi;
-	hlist_add_head(&obj->hash, head);
-
-	return obj;
-}
-
-static void cfi_hash_add(struct cfi_state *cfi)
-{
-	struct hlist_head *head = &cfi_hash[hash_min(cfi_key(cfi), cfi_bits)];
-
-	hlist_add_head(&cfi->hash, head);
-}
-
-static void *cfi_hash_alloc(unsigned long size)
-{
-	cfi_bits = max(10, ilog2(size));
-	cfi_hash = mmap(NULL, sizeof(struct hlist_head) << cfi_bits,
-			PROT_READ|PROT_WRITE,
-			MAP_PRIVATE|MAP_ANON, -1, 0);
-	if (cfi_hash == (void *)-1L) {
-		WARN("mmap fail cfi_hash");
-		cfi_hash = NULL;
-	}  else if (opts.stats) {
-		printf("cfi_bits: %d\n", cfi_bits);
-	}
-
-	return cfi_hash;
-}
-
 static unsigned long nr_insns;
 static unsigned long nr_insns_visited;
 
@@ -2236,14 +2148,6 @@ static int add_jump_table_alts(struct objtool_file *file)
 	return 0;
 }
 
-static void set_func_state(struct cfi_state *state)
-{
-	state->cfa = initial_func_cfi.cfa;
-	memcpy(&state->regs, &initial_func_cfi.regs,
-	       CFI_NUM_REGS * sizeof(struct cfi_reg));
-	state->stack_size = initial_func_cfi.cfa.offset;
-}
-
 static int read_unwind_hints(struct objtool_file *file)
 {
 	struct cfi_state cfi = init_cfi;
diff --git a/tools/objtool/include/objtool/cfi.h b/tools/objtool/include/objtool/cfi.h
index b1258e79a1b7..28c70daa3965 100644
--- a/tools/objtool/include/objtool/cfi.h
+++ b/tools/objtool/include/objtool/cfi.h
@@ -38,4 +38,16 @@ struct cfi_state {
 	bool end;
 };
 
+void init_cfi_state(struct cfi_state *cfi);
+bool cficmp(struct cfi_state *cfi1, struct cfi_state *cfi2);
+struct cfi_state *cfi_hash_find_or_add(struct cfi_state *cfi);
+void cfi_hash_add(struct cfi_state *cfi);
+void *cfi_hash_alloc(unsigned long size);
+void set_func_state(struct cfi_state *state);
+
+extern unsigned long nr_cfi, nr_cfi_reused, nr_cfi_cache;
+extern struct cfi_init_state initial_func_cfi;
+extern struct cfi_state init_cfi;
+extern struct cfi_state func_cfi;
+
 #endif /* _OBJTOOL_CFI_H */
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [RFC PATCH v1 02/23] objtool: Reorganize instruction-related code
  2023-06-20  7:46 [RFC PATCH v1 00/23] LoongArch: Add objtool and ORC unwinder support Youling Tang
  2023-06-20  7:46 ` [RFC PATCH v1 01/23] objtool: Reorganize CFI code Youling Tang
@ 2023-06-20  7:46 ` Youling Tang
  2023-06-20  7:46 ` [RFC PATCH v1 03/23] objtool: Move decode_instructions() to a separate file Youling Tang
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 12+ messages in thread
From: Youling Tang @ 2023-06-20  7:46 UTC (permalink / raw)
  To: Josh Poimboeuf, Peter Zijlstra, Huacai Chen, madvenka
  Cc: chenzhongjin, WANG Xuerui, Xi Ruoyao, live-patching, linux-kernel,
	loongarch, tangyouling00, youling.tang

From: "Madhavan T. Venkataraman" <madvenka@linux.microsoft.com>

check.c implements static stack validation. But the instruction-related
code that it contains can be shared with other types of validation. E.g.,
dynamic FP validation. Move the instruction-related code to its own files
- insn.h and insn.c.

Signed-off-by: Madhavan T. Venkataraman <madvenka@linux.microsoft.com>
---
 tools/objtool/Build                   |   1 +
 tools/objtool/check.c                 | 231 --------------------------
 tools/objtool/include/objtool/check.h |  92 +---------
 tools/objtool/include/objtool/insn.h  | 163 ++++++++++++++++++
 tools/objtool/insn.c                  | 195 ++++++++++++++++++++++
 5 files changed, 360 insertions(+), 322 deletions(-)
 create mode 100644 tools/objtool/include/objtool/insn.h
 create mode 100644 tools/objtool/insn.c

diff --git a/tools/objtool/Build b/tools/objtool/Build
index 9f23d1f4c716..c04e36267379 100644
--- a/tools/objtool/Build
+++ b/tools/objtool/Build
@@ -6,6 +6,7 @@ objtool-y += check.o
 objtool-y += special.o
 objtool-y += builtin-check.o
 objtool-y += cfi.o
+objtool-y += insn.o
 objtool-y += elf.o
 objtool-y += objtool.o
 
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 803764f4d4d8..619f7467e39c 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -28,121 +28,6 @@ struct alternative {
 	bool skip_orig;
 };
 
-struct instruction *find_insn(struct objtool_file *file,
-			      struct section *sec, unsigned long offset)
-{
-	struct instruction *insn;
-
-	hash_for_each_possible(file->insn_hash, insn, hash, sec_offset_hash(sec, offset)) {
-		if (insn->sec == sec && insn->offset == offset)
-			return insn;
-	}
-
-	return NULL;
-}
-
-struct instruction *next_insn_same_sec(struct objtool_file *file,
-				       struct instruction *insn)
-{
-	if (insn->idx == INSN_CHUNK_MAX)
-		return find_insn(file, insn->sec, insn->offset + insn->len);
-
-	insn++;
-	if (!insn->len)
-		return NULL;
-
-	return insn;
-}
-
-static struct instruction *next_insn_same_func(struct objtool_file *file,
-					       struct instruction *insn)
-{
-	struct instruction *next = next_insn_same_sec(file, insn);
-	struct symbol *func = insn_func(insn);
-
-	if (!func)
-		return NULL;
-
-	if (next && insn_func(next) == 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);
-}
-
-static struct instruction *prev_insn_same_sec(struct objtool_file *file,
-					      struct instruction *insn)
-{
-	if (insn->idx == 0) {
-		if (insn->prev_len)
-			return find_insn(file, insn->sec, insn->offset - insn->prev_len);
-		return NULL;
-	}
-
-	return insn - 1;
-}
-
-static struct instruction *prev_insn_same_sym(struct objtool_file *file,
-					      struct instruction *insn)
-{
-	struct instruction *prev = prev_insn_same_sec(file, insn);
-
-	if (prev && insn_func(prev) == insn_func(insn))
-		return prev;
-
-	return NULL;
-}
-
-#define for_each_insn(file, insn)					\
-	for (struct section *__sec, *__fake = (struct section *)1;	\
-	     __fake; __fake = NULL)					\
-		for_each_sec(file, __sec)				\
-			sec_for_each_insn(file, __sec, insn)
-
-#define func_for_each_insn(file, func, insn)				\
-	for (insn = find_insn(file, func->sec, func->offset);		\
-	     insn;							\
-	     insn = next_insn_same_func(file, insn))
-
-#define sym_for_each_insn(file, sym, insn)				\
-	for (insn = find_insn(file, sym->sec, sym->offset);		\
-	     insn && insn->offset < sym->offset + sym->len;		\
-	     insn = next_insn_same_sec(file, insn))
-
-#define sym_for_each_insn_continue_reverse(file, sym, insn)		\
-	for (insn = prev_insn_same_sec(file, insn);			\
-	     insn && insn->offset >= sym->offset;			\
-	     insn = prev_insn_same_sec(file, insn))
-
-#define sec_for_each_insn_from(file, insn)				\
-	for (; insn; insn = next_insn_same_sec(file, insn))
-
-#define sec_for_each_insn_continue(file, insn)				\
-	for (insn = next_insn_same_sec(file, insn); insn;		\
-	     insn = next_insn_same_sec(file, insn))
-
-static inline struct symbol *insn_call_dest(struct instruction *insn)
-{
-	if (insn->type == INSN_JUMP_DYNAMIC ||
-	    insn->type == INSN_CALL_DYNAMIC)
-		return NULL;
-
-	return insn->_call_dest;
-}
-
-static inline struct reloc *insn_jump_table(struct instruction *insn)
-{
-	if (insn->type == INSN_JUMP_DYNAMIC ||
-	    insn->type == INSN_CALL_DYNAMIC)
-		return insn->_jump_table;
-
-	return NULL;
-}
-
 static bool is_jump_table_jump(struct instruction *insn)
 {
 	struct alt_group *alt_group = insn->alt_group;
@@ -282,21 +167,6 @@ static bool dead_end_function(struct objtool_file *file, struct symbol *func)
 	return __dead_end_function(file, func, 0);
 }
 
-static void init_insn_state(struct objtool_file *file, struct insn_state *state,
-			    struct section *sec)
-{
-	memset(state, 0, sizeof(*state));
-	init_cfi_state(&state->cfi);
-
-	/*
-	 * We need the full vmlinux for noinstr validation, otherwise we can
-	 * not correctly determine insn_call_dest(insn)->sec (external symbols
-	 * do not have a section).
-	 */
-	if (opts.link && opts.noinstr && sec)
-		state->noinstr = sec->noinstr;
-}
-
 static unsigned long nr_insns;
 static unsigned long nr_insns_visited;
 
@@ -501,19 +371,6 @@ static int init_pv_ops(struct objtool_file *file)
 	return 0;
 }
 
-static struct instruction *find_last_insn(struct objtool_file *file,
-					  struct section *sec)
-{
-	struct instruction *insn = NULL;
-	unsigned int offset;
-	unsigned int end = (sec->sh.sh_size > 10) ? sec->sh.sh_size - 10 : 0;
-
-	for (offset = sec->sh.sh_size - 1; offset >= end && !insn; offset--)
-		insn = find_insn(file, sec, offset);
-
-	return insn;
-}
-
 /*
  * Mark "ud2" instructions and manually annotated dead ends.
  */
@@ -1263,26 +1120,6 @@ __weak bool arch_is_rethunk(struct symbol *sym)
 	return false;
 }
 
-static struct reloc *insn_reloc(struct objtool_file *file, struct instruction *insn)
-{
-	struct reloc *reloc;
-
-	if (insn->no_reloc)
-		return NULL;
-
-	if (!file)
-		return NULL;
-
-	reloc = find_reloc_by_dest_range(file->elf, insn->sec,
-					 insn->offset, insn->len);
-	if (!reloc) {
-		insn->no_reloc = 1;
-		return NULL;
-	}
-
-	return reloc;
-}
-
 static void remove_insn_ops(struct instruction *insn)
 {
 	struct stack_op *op, *next;
@@ -1446,24 +1283,6 @@ static void add_return_call(struct objtool_file *file, struct instruction *insn,
 		list_add_tail(&insn->call_node, &file->return_thunk_list);
 }
 
-static bool is_first_func_insn(struct objtool_file *file,
-			       struct instruction *insn, struct symbol *sym)
-{
-	if (insn->offset == sym->offset)
-		return true;
-
-	/* Allow direct CALL/JMP past ENDBR */
-	if (opts.ibt) {
-		struct instruction *prev = prev_insn_same_sym(file, insn);
-
-		if (prev && prev->type == INSN_ENDBR &&
-		    insn->offset == sym->offset + prev->len)
-			return true;
-	}
-
-	return false;
-}
-
 /*
  * A sibling call is a tail-call to another symbol -- to differentiate from a
  * recursive tail-call which is to the same symbol.
@@ -3224,56 +3043,6 @@ static int handle_insn_ops(struct instruction *insn,
 	return 0;
 }
 
-static bool insn_cfi_match(struct instruction *insn, struct cfi_state *cfi2)
-{
-	struct cfi_state *cfi1 = insn->cfi;
-	int i;
-
-	if (!cfi1) {
-		WARN("CFI missing");
-		return false;
-	}
-
-	if (memcmp(&cfi1->cfa, &cfi2->cfa, sizeof(cfi1->cfa))) {
-
-		WARN_FUNC("stack state mismatch: cfa1=%d%+d cfa2=%d%+d",
-			  insn->sec, insn->offset,
-			  cfi1->cfa.base, cfi1->cfa.offset,
-			  cfi2->cfa.base, cfi2->cfa.offset);
-
-	} else if (memcmp(&cfi1->regs, &cfi2->regs, sizeof(cfi1->regs))) {
-		for (i = 0; i < CFI_NUM_REGS; i++) {
-			if (!memcmp(&cfi1->regs[i], &cfi2->regs[i],
-				    sizeof(struct cfi_reg)))
-				continue;
-
-			WARN_FUNC("stack state mismatch: reg1[%d]=%d%+d reg2[%d]=%d%+d",
-				  insn->sec, insn->offset,
-				  i, cfi1->regs[i].base, cfi1->regs[i].offset,
-				  i, cfi2->regs[i].base, cfi2->regs[i].offset);
-			break;
-		}
-
-	} else if (cfi1->type != cfi2->type) {
-
-		WARN_FUNC("stack state mismatch: type1=%d type2=%d",
-			  insn->sec, insn->offset, cfi1->type, cfi2->type);
-
-	} else if (cfi1->drap != cfi2->drap ||
-		   (cfi1->drap && cfi1->drap_reg != cfi2->drap_reg) ||
-		   (cfi1->drap && cfi1->drap_offset != cfi2->drap_offset)) {
-
-		WARN_FUNC("stack state mismatch: drap1=%d(%d,%d) drap2=%d(%d,%d)",
-			  insn->sec, insn->offset,
-			  cfi1->drap, cfi1->drap_reg, cfi1->drap_offset,
-			  cfi2->drap, cfi2->drap_reg, cfi2->drap_offset);
-
-	} else
-		return true;
-
-	return false;
-}
-
 static inline bool func_uaccess_safe(struct symbol *func)
 {
 	if (func)
diff --git a/tools/objtool/include/objtool/check.h b/tools/objtool/include/objtool/check.h
index 3e7c7004f7df..450ebc092b1f 100644
--- a/tools/objtool/include/objtool/check.h
+++ b/tools/objtool/include/objtool/check.h
@@ -7,17 +7,7 @@
 #define _CHECK_H
 
 #include <stdbool.h>
-#include <objtool/cfi.h>
-#include <objtool/arch.h>
-
-struct insn_state {
-	struct cfi_state cfi;
-	unsigned int uaccess_stack;
-	bool uaccess;
-	bool df;
-	bool noinstr;
-	s8 instr;
-};
+#include <objtool/insn.h>
 
 struct alt_group {
 	/*
@@ -36,89 +26,9 @@ struct alt_group {
 	struct cfi_state **cfi;
 };
 
-#define INSN_CHUNK_BITS		8
-#define INSN_CHUNK_SIZE		(1 << INSN_CHUNK_BITS)
-#define INSN_CHUNK_MAX		(INSN_CHUNK_SIZE - 1)
-
-struct instruction {
-	struct hlist_node hash;
-	struct list_head call_node;
-	struct section *sec;
-	unsigned long offset;
-	unsigned long immediate;
-
-	u8 len;
-	u8 prev_len;
-	u8 type;
-	s8 instr;
-
-	u32 idx			: INSN_CHUNK_BITS,
-	    dead_end		: 1,
-	    ignore		: 1,
-	    ignore_alts		: 1,
-	    hint		: 1,
-	    save		: 1,
-	    restore		: 1,
-	    retpoline_safe	: 1,
-	    noendbr		: 1,
-	    entry		: 1,
-	    visited		: 4,
-	    no_reloc		: 1;
-		/* 10 bit hole */
-
-	struct alt_group *alt_group;
-	struct instruction *jump_dest;
-	struct instruction *first_jump_src;
-	union {
-		struct symbol *_call_dest;
-		struct reloc *_jump_table;
-	};
-	struct alternative *alts;
-	struct symbol *sym;
-	struct stack_op *stack_ops;
-	struct cfi_state *cfi;
-};
-
-static inline struct symbol *insn_func(struct instruction *insn)
-{
-	struct symbol *sym = insn->sym;
-
-	if (sym && sym->type != STT_FUNC)
-		sym = NULL;
-
-	return sym;
-}
-
 #define VISITED_BRANCH		0x01
 #define VISITED_BRANCH_UACCESS	0x02
 #define VISITED_BRANCH_MASK	0x03
 #define VISITED_ENTRY		0x04
 
-static inline bool is_static_jump(struct instruction *insn)
-{
-	return insn->type == INSN_JUMP_CONDITIONAL ||
-	       insn->type == INSN_JUMP_UNCONDITIONAL;
-}
-
-static inline bool is_dynamic_jump(struct instruction *insn)
-{
-	return insn->type == INSN_JUMP_DYNAMIC ||
-	       insn->type == INSN_JUMP_DYNAMIC_CONDITIONAL;
-}
-
-static inline bool is_jump(struct instruction *insn)
-{
-	return is_static_jump(insn) || is_dynamic_jump(insn);
-}
-
-struct instruction *find_insn(struct objtool_file *file,
-			      struct section *sec, unsigned long offset);
-
-struct instruction *next_insn_same_sec(struct objtool_file *file, struct instruction *insn);
-
-#define sec_for_each_insn(file, _sec, insn)				\
-	for (insn = find_insn(file, _sec, 0);				\
-	     insn && insn->sec == _sec;					\
-	     insn = next_insn_same_sec(file, insn))
-
 #endif /* _CHECK_H */
diff --git a/tools/objtool/include/objtool/insn.h b/tools/objtool/include/objtool/insn.h
new file mode 100644
index 000000000000..edd46b5ea1e4
--- /dev/null
+++ b/tools/objtool/include/objtool/insn.h
@@ -0,0 +1,163 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com>
+ */
+
+#ifndef _INSN_H
+#define _INSN_H
+
+#include <objtool/objtool.h>
+#include <objtool/arch.h>
+
+#define INSN_CHUNK_BITS		8
+#define INSN_CHUNK_SIZE		(1 << INSN_CHUNK_BITS)
+#define INSN_CHUNK_MAX		(INSN_CHUNK_SIZE - 1)
+
+struct insn_state {
+	struct cfi_state cfi;
+	unsigned int uaccess_stack;
+	bool uaccess;
+	bool df;
+	bool noinstr;
+	s8 instr;
+};
+
+struct instruction {
+	struct hlist_node hash;
+	struct list_head call_node;
+	struct section *sec;
+	unsigned long offset;
+	unsigned long immediate;
+
+	u8 len;
+	u8 prev_len;
+	u8 type;
+	s8 instr;
+
+	u32 idx			: INSN_CHUNK_BITS,
+	    dead_end		: 1,
+	    ignore		: 1,
+	    ignore_alts		: 1,
+	    hint		: 1,
+	    save		: 1,
+	    restore		: 1,
+	    retpoline_safe	: 1,
+	    noendbr		: 1,
+	    entry		: 1,
+	    visited		: 4,
+	    no_reloc		: 1;
+		/* 10 bit hole */
+
+	struct alt_group *alt_group;
+	struct instruction *jump_dest;
+	struct instruction *first_jump_src;
+	union {
+		struct symbol *_call_dest;
+		struct reloc *_jump_table;
+	};
+	struct alternative *alts;
+	struct symbol *sym;
+	struct stack_op *stack_ops;
+	struct cfi_state *cfi;
+};
+
+static inline struct symbol *insn_func(struct instruction *insn)
+{
+	struct symbol *sym = insn->sym;
+
+	if (sym && sym->type != STT_FUNC)
+		sym = NULL;
+
+	return sym;
+}
+
+static inline bool is_static_jump(struct instruction *insn)
+{
+	return insn->type == INSN_JUMP_CONDITIONAL ||
+	       insn->type == INSN_JUMP_UNCONDITIONAL;
+}
+
+static inline bool is_dynamic_jump(struct instruction *insn)
+{
+	return insn->type == INSN_JUMP_DYNAMIC ||
+	       insn->type == INSN_JUMP_DYNAMIC_CONDITIONAL;
+}
+
+static inline bool is_jump(struct instruction *insn)
+{
+	return is_static_jump(insn) || is_dynamic_jump(insn);
+}
+
+static inline struct symbol *insn_call_dest(struct instruction *insn)
+{
+	if (insn->type == INSN_JUMP_DYNAMIC ||
+	    insn->type == INSN_CALL_DYNAMIC)
+		return NULL;
+
+	return insn->_call_dest;
+}
+
+static inline struct reloc *insn_jump_table(struct instruction *insn)
+{
+	if (insn->type == INSN_JUMP_DYNAMIC ||
+	    insn->type == INSN_CALL_DYNAMIC)
+		return insn->_jump_table;
+
+	return NULL;
+}
+
+void init_insn_state(struct objtool_file *file, struct insn_state *state,
+		     struct section *sec);
+struct instruction *find_insn(struct objtool_file *file,
+			      struct section *sec, unsigned long offset);
+struct instruction *find_last_insn(struct objtool_file *file,
+				   struct section *sec);
+struct instruction *prev_insn_same_sec(struct objtool_file *file,
+				       struct instruction *insn);
+struct instruction *prev_insn_same_sym(struct objtool_file *file,
+				       struct instruction *insn);
+struct instruction *next_insn_same_sec(struct objtool_file *file,
+				       struct instruction *insn);
+struct instruction *next_insn_same_func(struct objtool_file *file,
+					struct instruction *insn);
+struct reloc *insn_reloc(struct objtool_file *file, struct instruction *insn);
+bool insn_cfi_match(struct instruction *insn, struct cfi_state *cfi2);
+bool same_function(struct instruction *insn1, struct instruction *insn2);
+bool is_first_func_insn(struct objtool_file *file,
+			       struct instruction *insn, struct symbol *sym);
+
+
+#define for_each_insn(file, insn)					\
+	for (struct section *__sec, *__fake = (struct section *)1;	\
+	     __fake; __fake = NULL)					\
+		for_each_sec(file, __sec)				\
+			sec_for_each_insn(file, __sec, insn)
+
+#define sec_for_each_insn(file, _sec, insn)				\
+	for (insn = find_insn(file, _sec, 0);				\
+	     insn && insn->sec == _sec;					\
+	     insn = next_insn_same_sec(file, insn))
+
+#define func_for_each_insn(file, func, insn)				\
+	for (insn = find_insn(file, func->sec, func->offset);		\
+	     insn;							\
+	     insn = next_insn_same_func(file, insn))
+
+#define sym_for_each_insn(file, sym, insn)				\
+	for (insn = find_insn(file, sym->sec, sym->offset);		\
+	     insn && insn->offset < sym->offset + sym->len;		\
+	     insn = next_insn_same_sec(file, insn))
+
+#define sym_for_each_insn_continue_reverse(file, sym, insn)		\
+	for (insn = prev_insn_same_sec(file, insn);			\
+	     insn && insn->offset >= sym->offset;			\
+	     insn = prev_insn_same_sec(file, insn))
+
+#define sec_for_each_insn_from(file, insn)				\
+	for (; insn; insn = next_insn_same_sec(file, insn))
+
+#define sec_for_each_insn_continue(file, insn)				\
+	for (insn = next_insn_same_sec(file, insn); insn;		\
+	     insn = next_insn_same_sec(file, insn))
+
+#endif /* _INSN_H */
diff --git a/tools/objtool/insn.c b/tools/objtool/insn.c
new file mode 100644
index 000000000000..c020cb84489d
--- /dev/null
+++ b/tools/objtool/insn.c
@@ -0,0 +1,195 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2015-2017 Josh Poimboeuf <jpoimboe@redhat.com>
+ */
+
+#include <string.h>
+
+#include <objtool/builtin.h>
+#include <objtool/insn.h>
+#include <objtool/warn.h>
+
+struct instruction *find_insn(struct objtool_file *file,
+			      struct section *sec, unsigned long offset)
+{
+	struct instruction *insn;
+
+	hash_for_each_possible(file->insn_hash, insn, hash, sec_offset_hash(sec, offset)) {
+		if (insn->sec == sec && insn->offset == offset)
+			return insn;
+	}
+
+	return NULL;
+}
+
+struct instruction *next_insn_same_sec(struct objtool_file *file,
+				       struct instruction *insn)
+{
+	if (insn->idx == INSN_CHUNK_MAX)
+		return find_insn(file, insn->sec, insn->offset + insn->len);
+
+	insn++;
+	if (!insn->len)
+		return NULL;
+
+	return insn;
+}
+
+struct instruction *next_insn_same_func(struct objtool_file *file,
+					struct instruction *insn)
+{
+	struct instruction *next = next_insn_same_sec(file, insn);
+	struct symbol *func = insn_func(insn);
+
+	if (!func)
+		return NULL;
+
+	if (next && insn_func(next) == 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);
+}
+
+struct instruction *prev_insn_same_sec(struct objtool_file *file,
+				       struct instruction *insn)
+{
+	if (insn->idx == 0) {
+		if (insn->prev_len)
+			return find_insn(file, insn->sec, insn->offset - insn->prev_len);
+		return NULL;
+	}
+
+	return insn - 1;
+}
+
+struct instruction *prev_insn_same_sym(struct objtool_file *file,
+				       struct instruction *insn)
+{
+	struct instruction *prev = prev_insn_same_sec(file, insn);
+
+	if (prev && insn_func(prev) == insn_func(insn))
+		return prev;
+
+	return NULL;
+}
+
+void init_insn_state(struct objtool_file *file, struct insn_state *state,
+		     struct section *sec)
+{
+	memset(state, 0, sizeof(*state));
+	init_cfi_state(&state->cfi);
+
+	/*
+	 * We need the full vmlinux for noinstr validation, otherwise we can
+	 * not correctly determine insn_call_dest(insn)->sec (external symbols
+	 * do not have a section).
+	 */
+	if (opts.link && opts.noinstr && sec)
+		state->noinstr = sec->noinstr;
+}
+
+struct instruction *find_last_insn(struct objtool_file *file,
+				   struct section *sec)
+{
+	struct instruction *insn = NULL;
+	unsigned int offset;
+	unsigned int end = (sec->sh.sh_size > 10) ? sec->sh.sh_size - 10 : 0;
+
+	for (offset = sec->sh.sh_size - 1; offset >= end && !insn; offset--)
+		insn = find_insn(file, sec, offset);
+
+	return insn;
+}
+
+struct reloc *insn_reloc(struct objtool_file *file, struct instruction *insn)
+{
+	struct reloc *reloc;
+
+	if (insn->no_reloc)
+		return NULL;
+
+	if (!file)
+		return NULL;
+
+	reloc = find_reloc_by_dest_range(file->elf, insn->sec,
+					 insn->offset, insn->len);
+	if (!reloc) {
+		insn->no_reloc = 1;
+		return NULL;
+	}
+
+	return reloc;
+}
+
+bool is_first_func_insn(struct objtool_file *file,
+			       struct instruction *insn, struct symbol *sym)
+{
+	if (insn->offset == sym->offset)
+		return true;
+
+	/* Allow direct CALL/JMP past ENDBR */
+	if (opts.ibt) {
+		struct instruction *prev = prev_insn_same_sym(file, insn);
+
+		if (prev && prev->type == INSN_ENDBR &&
+		    insn->offset == sym->offset + prev->len)
+			return true;
+	}
+
+	return false;
+}
+
+bool insn_cfi_match(struct instruction *insn, struct cfi_state *cfi2)
+{
+	struct cfi_state *cfi1 = insn->cfi;
+	int i;
+
+	if (!cfi1) {
+		WARN("CFI missing");
+		return false;
+	}
+
+	if (memcmp(&cfi1->cfa, &cfi2->cfa, sizeof(cfi1->cfa))) {
+
+		WARN_FUNC("stack state mismatch: cfa1=%d%+d cfa2=%d%+d",
+			  insn->sec, insn->offset,
+			  cfi1->cfa.base, cfi1->cfa.offset,
+			  cfi2->cfa.base, cfi2->cfa.offset);
+
+	} else if (memcmp(&cfi1->regs, &cfi2->regs, sizeof(cfi1->regs))) {
+		for (i = 0; i < CFI_NUM_REGS; i++) {
+			if (!memcmp(&cfi1->regs[i], &cfi2->regs[i],
+				    sizeof(struct cfi_reg)))
+				continue;
+
+			WARN_FUNC("stack state mismatch: reg1[%d]=%d%+d reg2[%d]=%d%+d",
+				  insn->sec, insn->offset,
+				  i, cfi1->regs[i].base, cfi1->regs[i].offset,
+				  i, cfi2->regs[i].base, cfi2->regs[i].offset);
+			break;
+		}
+
+	} else if (cfi1->type != cfi2->type) {
+
+		WARN_FUNC("stack state mismatch: type1=%d type2=%d",
+			  insn->sec, insn->offset, cfi1->type, cfi2->type);
+
+	} else if (cfi1->drap != cfi2->drap ||
+		   (cfi1->drap && cfi1->drap_reg != cfi2->drap_reg) ||
+		   (cfi1->drap && cfi1->drap_offset != cfi2->drap_offset)) {
+
+		WARN_FUNC("stack state mismatch: drap1=%d(%d,%d) drap2=%d(%d,%d)",
+			  insn->sec, insn->offset,
+			  cfi1->drap, cfi1->drap_reg, cfi1->drap_offset,
+			  cfi2->drap, cfi2->drap_reg, cfi2->drap_offset);
+
+	} else
+		return true;
+
+	return false;
+}
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [RFC PATCH v1 03/23] objtool: Move decode_instructions() to a separate file
  2023-06-20  7:46 [RFC PATCH v1 00/23] LoongArch: Add objtool and ORC unwinder support Youling Tang
  2023-06-20  7:46 ` [RFC PATCH v1 01/23] objtool: Reorganize CFI code Youling Tang
  2023-06-20  7:46 ` [RFC PATCH v1 02/23] objtool: Reorganize instruction-related code Youling Tang
@ 2023-06-20  7:46 ` Youling Tang
  2023-06-20  7:46 ` [RFC PATCH v1 04/23] objtool: Reorganize Unwind hint code Youling Tang
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 12+ messages in thread
From: Youling Tang @ 2023-06-20  7:46 UTC (permalink / raw)
  To: Josh Poimboeuf, Peter Zijlstra, Huacai Chen, madvenka
  Cc: chenzhongjin, WANG Xuerui, Xi Ruoyao, live-patching, linux-kernel,
	loongarch, tangyouling00, youling.tang

From: "Madhavan T. Venkataraman" <madvenka@linux.microsoft.com>

check.c implements static stack validation. But decode_instructions() which
resides in it can be shared with other types of validation. E.g., dynamic
FP validation. Move the function to its own file - decode.c.

Signed-off-by: Madhavan T. Venkataraman <madvenka@linux.microsoft.com>
---
 tools/objtool/Build                   |   1 +
 tools/objtool/check.c                 | 127 +-----------------------
 tools/objtool/decode.c                | 136 ++++++++++++++++++++++++++
 tools/objtool/include/objtool/check.h |   2 +
 tools/objtool/include/objtool/insn.h  |   2 +
 5 files changed, 142 insertions(+), 126 deletions(-)
 create mode 100644 tools/objtool/decode.c

diff --git a/tools/objtool/Build b/tools/objtool/Build
index c04e36267379..64ccae49cd5f 100644
--- a/tools/objtool/Build
+++ b/tools/objtool/Build
@@ -7,6 +7,7 @@ objtool-y += special.o
 objtool-y += builtin-check.o
 objtool-y += cfi.o
 objtool-y += insn.o
+objtool-y += decode.o
 objtool-y += elf.o
 objtool-y += objtool.o
 
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 619f7467e39c..26ed9b0b8f49 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -167,134 +167,9 @@ static bool dead_end_function(struct objtool_file *file, struct symbol *func)
 	return __dead_end_function(file, func, 0);
 }
 
-static unsigned long nr_insns;
+unsigned long nr_insns;
 static unsigned long nr_insns_visited;
 
-/*
- * Call the arch-specific instruction decoder for all the instructions and add
- * them to the global instruction list.
- */
-static int decode_instructions(struct objtool_file *file)
-{
-	struct section *sec;
-	struct symbol *func;
-	unsigned long offset;
-	struct instruction *insn;
-	int ret;
-
-	for_each_sec(file, sec) {
-		struct instruction *insns = NULL;
-		u8 prev_len = 0;
-		u8 idx = 0;
-
-		if (!(sec->sh.sh_flags & SHF_EXECINSTR))
-			continue;
-
-		if (strcmp(sec->name, ".altinstr_replacement") &&
-		    strcmp(sec->name, ".altinstr_aux") &&
-		    strncmp(sec->name, ".discard.", 9))
-			sec->text = true;
-
-		if (!strcmp(sec->name, ".noinstr.text") ||
-		    !strcmp(sec->name, ".entry.text") ||
-		    !strcmp(sec->name, ".cpuidle.text") ||
-		    !strncmp(sec->name, ".text.__x86.", 12))
-			sec->noinstr = true;
-
-		/*
-		 * .init.text code is ran before userspace and thus doesn't
-		 * strictly need retpolines, except for modules which are
-		 * loaded late, they very much do need retpoline in their
-		 * .init.text
-		 */
-		if (!strcmp(sec->name, ".init.text") && !opts.module)
-			sec->init = true;
-
-		for (offset = 0; offset < sec->sh.sh_size; offset += insn->len) {
-			if (!insns || idx == INSN_CHUNK_MAX) {
-				insns = calloc(sizeof(*insn), INSN_CHUNK_SIZE);
-				if (!insns) {
-					WARN("malloc failed");
-					return -1;
-				}
-				idx = 0;
-			} else {
-				idx++;
-			}
-			insn = &insns[idx];
-			insn->idx = idx;
-
-			INIT_LIST_HEAD(&insn->call_node);
-			insn->sec = sec;
-			insn->offset = offset;
-			insn->prev_len = prev_len;
-
-			ret = arch_decode_instruction(file, sec, offset,
-						      sec->sh.sh_size - offset,
-						      insn);
-			if (ret)
-				return ret;
-
-			prev_len = insn->len;
-
-			/*
-			 * By default, "ud2" is a dead end unless otherwise
-			 * annotated, because GCC 7 inserts it for certain
-			 * divide-by-zero cases.
-			 */
-			if (insn->type == INSN_BUG)
-				insn->dead_end = true;
-
-			hash_add(file->insn_hash, &insn->hash, sec_offset_hash(sec, insn->offset));
-			nr_insns++;
-		}
-
-//		printf("%s: last chunk used: %d\n", sec->name, (int)idx);
-
-		list_for_each_entry(func, &sec->symbol_list, list) {
-			if (func->type != STT_NOTYPE && func->type != STT_FUNC)
-				continue;
-
-			if (func->offset == sec->sh.sh_size) {
-				/* Heuristic: likely an "end" symbol */
-				if (func->type == STT_NOTYPE)
-					continue;
-				WARN("%s(): STT_FUNC at end of section",
-				     func->name);
-				return -1;
-			}
-
-			if (func->return_thunk || func->alias != func)
-				continue;
-
-			if (!find_insn(file, sec, func->offset)) {
-				WARN("%s(): can't find starting instruction",
-				     func->name);
-				return -1;
-			}
-
-			sym_for_each_insn(file, func, insn) {
-				insn->sym = func;
-				if (func->type == STT_FUNC &&
-				    insn->type == INSN_ENDBR &&
-				    list_empty(&insn->call_node)) {
-					if (insn->offset == func->offset) {
-						list_add_tail(&insn->call_node, &file->endbr_list);
-						file->nr_endbr++;
-					} else {
-						file->nr_endbr_int++;
-					}
-				}
-			}
-		}
-	}
-
-	if (opts.stats)
-		printf("nr_insns: %lu\n", nr_insns);
-
-	return 0;
-}
-
 /*
  * Read the pv_ops[] .data table to find the static initialized values.
  */
diff --git a/tools/objtool/decode.c b/tools/objtool/decode.c
new file mode 100644
index 000000000000..f369412ffce1
--- /dev/null
+++ b/tools/objtool/decode.c
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2015-2017 Josh Poimboeuf <jpoimboe@redhat.com>
+ */
+#include <linux/objtool.h>
+
+#include <objtool/builtin.h>
+#include <objtool/check.h>
+#include <objtool/insn.h>
+#include <objtool/warn.h>
+
+/*
+ * Call the arch-specific instruction decoder for all the instructions and add
+ * them to the global instruction list.
+ */
+int decode_instructions(struct objtool_file *file)
+{
+	struct section *sec;
+	struct symbol *func;
+	unsigned long offset;
+	struct instruction *insn;
+	int ret;
+
+	for_each_sec(file, sec) {
+		struct instruction *insns = NULL;
+		u8 prev_len = 0;
+		u8 idx = 0;
+
+		if (!(sec->sh.sh_flags & SHF_EXECINSTR))
+			continue;
+
+		if (strcmp(sec->name, ".altinstr_replacement") &&
+		    strcmp(sec->name, ".altinstr_aux") &&
+		    strncmp(sec->name, ".discard.", 9))
+			sec->text = true;
+
+		if (!strcmp(sec->name, ".noinstr.text") ||
+		    !strcmp(sec->name, ".entry.text") ||
+		    !strcmp(sec->name, ".cpuidle.text") ||
+		    !strncmp(sec->name, ".text.__x86.", 12))
+			sec->noinstr = true;
+
+		/*
+		 * .init.text code is ran before userspace and thus doesn't
+		 * strictly need retpolines, except for modules which are
+		 * loaded late, they very much do need retpoline in their
+		 * .init.text
+		 */
+		if (!strcmp(sec->name, ".init.text") && !opts.module)
+			sec->init = true;
+
+		for (offset = 0; offset < sec->sh.sh_size; offset += insn->len) {
+			if (!insns || idx == INSN_CHUNK_MAX) {
+				insns = calloc(sizeof(*insn), INSN_CHUNK_SIZE);
+				if (!insns) {
+					WARN("malloc failed");
+					return -1;
+				}
+				idx = 0;
+			} else {
+				idx++;
+			}
+			insn = &insns[idx];
+			insn->idx = idx;
+
+			INIT_LIST_HEAD(&insn->call_node);
+			insn->sec = sec;
+			insn->offset = offset;
+			insn->prev_len = prev_len;
+
+			ret = arch_decode_instruction(file, sec, offset,
+						      sec->sh.sh_size - offset,
+						      insn);
+			if (ret)
+				return ret;
+
+			prev_len = insn->len;
+
+			/*
+			 * By default, "ud2" is a dead end unless otherwise
+			 * annotated, because GCC 7 inserts it for certain
+			 * divide-by-zero cases.
+			 */
+			if (insn->type == INSN_BUG)
+				insn->dead_end = true;
+
+			hash_add(file->insn_hash, &insn->hash, sec_offset_hash(sec, insn->offset));
+			nr_insns++;
+		}
+
+//		printf("%s: last chunk used: %d\n", sec->name, (int)idx);
+
+		list_for_each_entry(func, &sec->symbol_list, list) {
+			if (func->type != STT_NOTYPE && func->type != STT_FUNC)
+				continue;
+
+			if (func->offset == sec->sh.sh_size) {
+				/* Heuristic: likely an "end" symbol */
+				if (func->type == STT_NOTYPE)
+					continue;
+				WARN("%s(): STT_FUNC at end of section",
+				     func->name);
+				return -1;
+			}
+
+			if (func->return_thunk || func->alias != func)
+				continue;
+
+			if (!find_insn(file, sec, func->offset)) {
+				WARN("%s(): can't find starting instruction",
+				     func->name);
+				return -1;
+			}
+
+			sym_for_each_insn(file, func, insn) {
+				insn->sym = func;
+				if (func->type == STT_FUNC &&
+				    insn->type == INSN_ENDBR &&
+				    list_empty(&insn->call_node)) {
+					if (insn->offset == func->offset) {
+						list_add_tail(&insn->call_node, &file->endbr_list);
+						file->nr_endbr++;
+					} else {
+						file->nr_endbr_int++;
+					}
+				}
+			}
+		}
+	}
+
+	if (opts.stats)
+		printf("nr_insns: %lu\n", nr_insns);
+
+	return 0;
+}
+
diff --git a/tools/objtool/include/objtool/check.h b/tools/objtool/include/objtool/check.h
index 450ebc092b1f..34898364bf03 100644
--- a/tools/objtool/include/objtool/check.h
+++ b/tools/objtool/include/objtool/check.h
@@ -31,4 +31,6 @@ struct alt_group {
 #define VISITED_BRANCH_MASK	0x03
 #define VISITED_ENTRY		0x04
 
+extern unsigned long nr_insns;
+
 #endif /* _CHECK_H */
diff --git a/tools/objtool/include/objtool/insn.h b/tools/objtool/include/objtool/insn.h
index edd46b5ea1e4..92f8f1ff6c09 100644
--- a/tools/objtool/include/objtool/insn.h
+++ b/tools/objtool/include/objtool/insn.h
@@ -127,6 +127,8 @@ bool is_first_func_insn(struct objtool_file *file,
 			       struct instruction *insn, struct symbol *sym);
 
 
+int decode_instructions(struct objtool_file *file);
+
 #define for_each_insn(file, insn)					\
 	for (struct section *__sec, *__fake = (struct section *)1;	\
 	     __fake; __fake = NULL)					\
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [RFC PATCH v1 04/23] objtool: Reorganize Unwind hint code
  2023-06-20  7:46 [RFC PATCH v1 00/23] LoongArch: Add objtool and ORC unwinder support Youling Tang
                   ` (2 preceding siblings ...)
  2023-06-20  7:46 ` [RFC PATCH v1 03/23] objtool: Move decode_instructions() to a separate file Youling Tang
@ 2023-06-20  7:46 ` Youling Tang
  2023-06-20  8:15 ` [RFC PATCH v1 00/23] LoongArch: Add objtool and ORC unwinder support Xi Ruoyao
  2023-06-20  8:42 ` Peter Zijlstra
  5 siblings, 0 replies; 12+ messages in thread
From: Youling Tang @ 2023-06-20  7:46 UTC (permalink / raw)
  To: Josh Poimboeuf, Peter Zijlstra, Huacai Chen, madvenka
  Cc: chenzhongjin, WANG Xuerui, Xi Ruoyao, live-patching, linux-kernel,
	loongarch, tangyouling00, youling.tang

From: "Madhavan T. Venkataraman" <madvenka@linux.microsoft.com>

Unwind hint macros and struct unwind_hint are arch-specific. Move them
into the arch-specific file asm/unwind_hints.h. But the unwind hint
types are generic. Retain them in linux/objtool.h.

Unwind hints can be used with static stack validation as well as other
forms of validation such as dynamic FP validation. Move the function
read_unwind_hints() from check.c to a new file unwind_hints.c so that
it can be shared across validation schemes.

Signed-off-by: Madhavan T. Venkataraman <madvenka@linux.microsoft.com>
---
 arch/x86/include/asm/unwind_hints.h       |  86 ++++++++++++
 arch/x86/kernel/unwind_orc.c              |   2 +-
 include/linux/objtool.h                   |  70 ----------
 tools/arch/x86/include/asm/unwind_hints.h | 160 ++++++++++++++++++++++
 tools/include/linux/objtool.h             |  70 ----------
 tools/objtool/Build                       |   1 +
 tools/objtool/check.c                     |  97 -------------
 tools/objtool/include/objtool/insn.h      |   1 +
 tools/objtool/sync-check.sh               |   1 +
 tools/objtool/unwind_hints.c              | 107 +++++++++++++++
 10 files changed, 357 insertions(+), 238 deletions(-)
 create mode 100644 tools/arch/x86/include/asm/unwind_hints.h
 create mode 100644 tools/objtool/unwind_hints.c

diff --git a/arch/x86/include/asm/unwind_hints.h b/arch/x86/include/asm/unwind_hints.h
index e7c71750b309..2570edfa8c35 100644
--- a/arch/x86/include/asm/unwind_hints.h
+++ b/arch/x86/include/asm/unwind_hints.h
@@ -1,10 +1,96 @@
 #ifndef _ASM_X86_UNWIND_HINTS_H
 #define _ASM_X86_UNWIND_HINTS_H
 
+#ifndef __ASSEMBLY__
+
+#include <linux/types.h>
+
+/*
+ * This struct is used by asm and inline asm code to manually annotate the
+ * location of registers on the stack.
+ */
+struct unwind_hint {
+	u32		ip;
+	s16		sp_offset;
+	u8		sp_reg;
+	u8		type;
+	u8		signal;
+	u8		end;
+};
+#endif
+
 #include <linux/objtool.h>
 
 #include "orc_types.h"
 
+#ifdef CONFIG_OBJTOOL
+
+#ifndef __ASSEMBLY__
+
+#define UNWIND_HINT(sp_reg, sp_offset, type, signal, end)	\
+	"987: \n\t"						\
+	".pushsection .discard.unwind_hints\n\t"		\
+	/* struct unwind_hint */				\
+	".long 987b - .\n\t"					\
+	".short " __stringify(sp_offset) "\n\t"			\
+	".byte " __stringify(sp_reg) "\n\t"			\
+	".byte " __stringify(type) "\n\t"			\
+	".byte " __stringify(signal) "\n\t"			\
+	".byte " __stringify(end) "\n\t"			\
+	".balign 4 \n\t"					\
+	".popsection\n\t"
+
+#else /* __ASSEMBLY__ */
+
+/*
+ * In asm, there are two kinds of code: normal C-type callable functions and
+ * the rest.  The normal callable functions can be called by other code, and
+ * don't do anything unusual with the stack.  Such normal callable functions
+ * are annotated with the ENTRY/ENDPROC macros.  Most asm code falls in this
+ * category.  In this case, no special debugging annotations are needed because
+ * objtool can automatically generate the ORC data for the ORC unwinder to read
+ * at runtime.
+ *
+ * Anything which doesn't fall into the above category, such as syscall and
+ * interrupt handlers, tends to not be called directly by other functions, and
+ * often does unusual non-C-function-type things with the stack pointer.  Such
+ * code needs to be annotated such that objtool can understand it.  The
+ * following CFI hint macros are for this type of code.
+ *
+ * These macros provide hints to objtool about the state of the stack at each
+ * instruction.  Objtool starts from the hints and follows the code flow,
+ * making automatic CFI adjustments when it sees pushes and pops, filling out
+ * the debuginfo as necessary.  It will also warn if it sees any
+ * inconsistencies.
+ */
+.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 signal=0 end=0
+.Lunwind_hint_ip_\@:
+	.pushsection .discard.unwind_hints
+		/* struct unwind_hint */
+		.long .Lunwind_hint_ip_\@ - .
+		.short \sp_offset
+		.byte \sp_reg
+		.byte \type
+		.byte \signal
+		.byte \end
+		.balign 4
+	.popsection
+.endm
+
+#endif /* __ASSEMBLY__ */
+
+#else /* !CONFIG_OBJTOOL */
+
+#ifndef __ASSEMBLY__
+#define UNWIND_HINT(sp_reg, sp_offset, type, signal, end)	\
+	"\n\t"
+#else
+.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 signal=0 end=0
+.endm
+#endif
+
+#endif /* CONFIG_OBJTOOL */
+
 #ifdef __ASSEMBLY__
 
 .macro UNWIND_HINT_EMPTY
diff --git a/arch/x86/kernel/unwind_orc.c b/arch/x86/kernel/unwind_orc.c
index 37307b40f8da..01b89f2039c3 100644
--- a/arch/x86/kernel/unwind_orc.c
+++ b/arch/x86/kernel/unwind_orc.c
@@ -1,10 +1,10 @@
 // SPDX-License-Identifier: GPL-2.0-only
-#include <linux/objtool.h>
 #include <linux/module.h>
 #include <linux/sort.h>
 #include <asm/ptrace.h>
 #include <asm/stacktrace.h>
 #include <asm/unwind.h>
+#include <asm/unwind_hints.h>
 #include <asm/orc_types.h>
 #include <asm/orc_lookup.h>
 
diff --git a/include/linux/objtool.h b/include/linux/objtool.h
index 9ac3df3fccf0..1af295efc12c 100644
--- a/include/linux/objtool.h
+++ b/include/linux/objtool.h
@@ -2,24 +2,6 @@
 #ifndef _LINUX_OBJTOOL_H
 #define _LINUX_OBJTOOL_H
 
-#ifndef __ASSEMBLY__
-
-#include <linux/types.h>
-
-/*
- * This struct is used by asm and inline asm code to manually annotate the
- * location of registers on the stack.
- */
-struct unwind_hint {
-	u32		ip;
-	s16		sp_offset;
-	u8		sp_reg;
-	u8		type;
-	u8		signal;
-	u8		end;
-};
-#endif
-
 /*
  * UNWIND_HINT_TYPE_CALL: Indicates that sp_reg+sp_offset resolves to PREV_SP
  * (the caller's SP right before it made the call).  Used for all callable
@@ -50,19 +32,6 @@ struct unwind_hint {
 
 #ifndef __ASSEMBLY__
 
-#define UNWIND_HINT(sp_reg, sp_offset, type, signal, end)	\
-	"987: \n\t"						\
-	".pushsection .discard.unwind_hints\n\t"		\
-	/* struct unwind_hint */				\
-	".long 987b - .\n\t"					\
-	".short " __stringify(sp_offset) "\n\t"			\
-	".byte " __stringify(sp_reg) "\n\t"			\
-	".byte " __stringify(type) "\n\t"			\
-	".byte " __stringify(signal) "\n\t"			\
-	".byte " __stringify(end) "\n\t"			\
-	".balign 4 \n\t"					\
-	".popsection\n\t"
-
 /*
  * This macro marks the given function's stack frame as "non-standard", which
  * tells objtool to ignore the function when doing stack metadata validation.
@@ -110,41 +79,6 @@ struct unwind_hint {
 	.long 999b;						\
 	.popsection;
 
-/*
- * In asm, there are two kinds of code: normal C-type callable functions and
- * the rest.  The normal callable functions can be called by other code, and
- * don't do anything unusual with the stack.  Such normal callable functions
- * are annotated with the ENTRY/ENDPROC macros.  Most asm code falls in this
- * category.  In this case, no special debugging annotations are needed because
- * objtool can automatically generate the ORC data for the ORC unwinder to read
- * at runtime.
- *
- * Anything which doesn't fall into the above category, such as syscall and
- * interrupt handlers, tends to not be called directly by other functions, and
- * often does unusual non-C-function-type things with the stack pointer.  Such
- * code needs to be annotated such that objtool can understand it.  The
- * following CFI hint macros are for this type of code.
- *
- * These macros provide hints to objtool about the state of the stack at each
- * instruction.  Objtool starts from the hints and follows the code flow,
- * making automatic CFI adjustments when it sees pushes and pops, filling out
- * the debuginfo as necessary.  It will also warn if it sees any
- * inconsistencies.
- */
-.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 signal=0 end=0
-.Lunwind_hint_ip_\@:
-	.pushsection .discard.unwind_hints
-		/* struct unwind_hint */
-		.long .Lunwind_hint_ip_\@ - .
-		.short \sp_offset
-		.byte \sp_reg
-		.byte \type
-		.byte \signal
-		.byte \end
-		.balign 4
-	.popsection
-.endm
-
 .macro STACK_FRAME_NON_STANDARD func:req
 	.pushsection .discard.func_stack_frame_non_standard, "aw"
 	_ASM_PTR \func
@@ -177,16 +111,12 @@ struct unwind_hint {
 
 #ifndef __ASSEMBLY__
 
-#define UNWIND_HINT(sp_reg, sp_offset, type, signal, end) \
-	"\n\t"
 #define STACK_FRAME_NON_STANDARD(func)
 #define STACK_FRAME_NON_STANDARD_FP(func)
 #define ANNOTATE_NOENDBR
 #define ASM_REACHABLE
 #else
 #define ANNOTATE_INTRA_FUNCTION_CALL
-.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 signal=0 end=0
-.endm
 .macro STACK_FRAME_NON_STANDARD func:req
 .endm
 .macro ANNOTATE_NOENDBR
diff --git a/tools/arch/x86/include/asm/unwind_hints.h b/tools/arch/x86/include/asm/unwind_hints.h
new file mode 100644
index 000000000000..2570edfa8c35
--- /dev/null
+++ b/tools/arch/x86/include/asm/unwind_hints.h
@@ -0,0 +1,160 @@
+#ifndef _ASM_X86_UNWIND_HINTS_H
+#define _ASM_X86_UNWIND_HINTS_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/types.h>
+
+/*
+ * This struct is used by asm and inline asm code to manually annotate the
+ * location of registers on the stack.
+ */
+struct unwind_hint {
+	u32		ip;
+	s16		sp_offset;
+	u8		sp_reg;
+	u8		type;
+	u8		signal;
+	u8		end;
+};
+#endif
+
+#include <linux/objtool.h>
+
+#include "orc_types.h"
+
+#ifdef CONFIG_OBJTOOL
+
+#ifndef __ASSEMBLY__
+
+#define UNWIND_HINT(sp_reg, sp_offset, type, signal, end)	\
+	"987: \n\t"						\
+	".pushsection .discard.unwind_hints\n\t"		\
+	/* struct unwind_hint */				\
+	".long 987b - .\n\t"					\
+	".short " __stringify(sp_offset) "\n\t"			\
+	".byte " __stringify(sp_reg) "\n\t"			\
+	".byte " __stringify(type) "\n\t"			\
+	".byte " __stringify(signal) "\n\t"			\
+	".byte " __stringify(end) "\n\t"			\
+	".balign 4 \n\t"					\
+	".popsection\n\t"
+
+#else /* __ASSEMBLY__ */
+
+/*
+ * In asm, there are two kinds of code: normal C-type callable functions and
+ * the rest.  The normal callable functions can be called by other code, and
+ * don't do anything unusual with the stack.  Such normal callable functions
+ * are annotated with the ENTRY/ENDPROC macros.  Most asm code falls in this
+ * category.  In this case, no special debugging annotations are needed because
+ * objtool can automatically generate the ORC data for the ORC unwinder to read
+ * at runtime.
+ *
+ * Anything which doesn't fall into the above category, such as syscall and
+ * interrupt handlers, tends to not be called directly by other functions, and
+ * often does unusual non-C-function-type things with the stack pointer.  Such
+ * code needs to be annotated such that objtool can understand it.  The
+ * following CFI hint macros are for this type of code.
+ *
+ * These macros provide hints to objtool about the state of the stack at each
+ * instruction.  Objtool starts from the hints and follows the code flow,
+ * making automatic CFI adjustments when it sees pushes and pops, filling out
+ * the debuginfo as necessary.  It will also warn if it sees any
+ * inconsistencies.
+ */
+.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 signal=0 end=0
+.Lunwind_hint_ip_\@:
+	.pushsection .discard.unwind_hints
+		/* struct unwind_hint */
+		.long .Lunwind_hint_ip_\@ - .
+		.short \sp_offset
+		.byte \sp_reg
+		.byte \type
+		.byte \signal
+		.byte \end
+		.balign 4
+	.popsection
+.endm
+
+#endif /* __ASSEMBLY__ */
+
+#else /* !CONFIG_OBJTOOL */
+
+#ifndef __ASSEMBLY__
+#define UNWIND_HINT(sp_reg, sp_offset, type, signal, end)	\
+	"\n\t"
+#else
+.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 signal=0 end=0
+.endm
+#endif
+
+#endif /* CONFIG_OBJTOOL */
+
+#ifdef __ASSEMBLY__
+
+.macro UNWIND_HINT_EMPTY
+	UNWIND_HINT type=UNWIND_HINT_TYPE_CALL end=1
+.endm
+
+.macro UNWIND_HINT_ENTRY
+	UNWIND_HINT type=UNWIND_HINT_TYPE_ENTRY end=1
+.endm
+
+.macro UNWIND_HINT_REGS base=%rsp offset=0 indirect=0 extra=1 partial=0 signal=1
+	.if \base == %rsp
+		.if \indirect
+			.set sp_reg, ORC_REG_SP_INDIRECT
+		.else
+			.set sp_reg, ORC_REG_SP
+		.endif
+	.elseif \base == %rbp
+		.set sp_reg, ORC_REG_BP
+	.elseif \base == %rdi
+		.set sp_reg, ORC_REG_DI
+	.elseif \base == %rdx
+		.set sp_reg, ORC_REG_DX
+	.elseif \base == %r10
+		.set sp_reg, ORC_REG_R10
+	.else
+		.error "UNWIND_HINT_REGS: bad base register"
+	.endif
+
+	.set sp_offset, \offset
+
+	.if \partial
+		.set type, UNWIND_HINT_TYPE_REGS_PARTIAL
+	.elseif \extra == 0
+		.set type, UNWIND_HINT_TYPE_REGS_PARTIAL
+		.set sp_offset, \offset + (16*8)
+	.else
+		.set type, UNWIND_HINT_TYPE_REGS
+	.endif
+
+	UNWIND_HINT sp_reg=sp_reg sp_offset=sp_offset type=type signal=\signal
+.endm
+
+.macro UNWIND_HINT_IRET_REGS base=%rsp offset=0 signal=1
+	UNWIND_HINT_REGS base=\base offset=\offset partial=1 signal=\signal
+.endm
+
+.macro UNWIND_HINT_FUNC
+	UNWIND_HINT sp_reg=ORC_REG_SP sp_offset=8 type=UNWIND_HINT_TYPE_FUNC
+.endm
+
+.macro UNWIND_HINT_SAVE
+	UNWIND_HINT type=UNWIND_HINT_TYPE_SAVE
+.endm
+
+.macro UNWIND_HINT_RESTORE
+	UNWIND_HINT type=UNWIND_HINT_TYPE_RESTORE
+.endm
+
+#else
+
+#define UNWIND_HINT_FUNC \
+	UNWIND_HINT(ORC_REG_SP, 8, UNWIND_HINT_TYPE_FUNC, 0, 0)
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_X86_UNWIND_HINTS_H */
diff --git a/tools/include/linux/objtool.h b/tools/include/linux/objtool.h
index 9ac3df3fccf0..1af295efc12c 100644
--- a/tools/include/linux/objtool.h
+++ b/tools/include/linux/objtool.h
@@ -2,24 +2,6 @@
 #ifndef _LINUX_OBJTOOL_H
 #define _LINUX_OBJTOOL_H
 
-#ifndef __ASSEMBLY__
-
-#include <linux/types.h>
-
-/*
- * This struct is used by asm and inline asm code to manually annotate the
- * location of registers on the stack.
- */
-struct unwind_hint {
-	u32		ip;
-	s16		sp_offset;
-	u8		sp_reg;
-	u8		type;
-	u8		signal;
-	u8		end;
-};
-#endif
-
 /*
  * UNWIND_HINT_TYPE_CALL: Indicates that sp_reg+sp_offset resolves to PREV_SP
  * (the caller's SP right before it made the call).  Used for all callable
@@ -50,19 +32,6 @@ struct unwind_hint {
 
 #ifndef __ASSEMBLY__
 
-#define UNWIND_HINT(sp_reg, sp_offset, type, signal, end)	\
-	"987: \n\t"						\
-	".pushsection .discard.unwind_hints\n\t"		\
-	/* struct unwind_hint */				\
-	".long 987b - .\n\t"					\
-	".short " __stringify(sp_offset) "\n\t"			\
-	".byte " __stringify(sp_reg) "\n\t"			\
-	".byte " __stringify(type) "\n\t"			\
-	".byte " __stringify(signal) "\n\t"			\
-	".byte " __stringify(end) "\n\t"			\
-	".balign 4 \n\t"					\
-	".popsection\n\t"
-
 /*
  * This macro marks the given function's stack frame as "non-standard", which
  * tells objtool to ignore the function when doing stack metadata validation.
@@ -110,41 +79,6 @@ struct unwind_hint {
 	.long 999b;						\
 	.popsection;
 
-/*
- * In asm, there are two kinds of code: normal C-type callable functions and
- * the rest.  The normal callable functions can be called by other code, and
- * don't do anything unusual with the stack.  Such normal callable functions
- * are annotated with the ENTRY/ENDPROC macros.  Most asm code falls in this
- * category.  In this case, no special debugging annotations are needed because
- * objtool can automatically generate the ORC data for the ORC unwinder to read
- * at runtime.
- *
- * Anything which doesn't fall into the above category, such as syscall and
- * interrupt handlers, tends to not be called directly by other functions, and
- * often does unusual non-C-function-type things with the stack pointer.  Such
- * code needs to be annotated such that objtool can understand it.  The
- * following CFI hint macros are for this type of code.
- *
- * These macros provide hints to objtool about the state of the stack at each
- * instruction.  Objtool starts from the hints and follows the code flow,
- * making automatic CFI adjustments when it sees pushes and pops, filling out
- * the debuginfo as necessary.  It will also warn if it sees any
- * inconsistencies.
- */
-.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 signal=0 end=0
-.Lunwind_hint_ip_\@:
-	.pushsection .discard.unwind_hints
-		/* struct unwind_hint */
-		.long .Lunwind_hint_ip_\@ - .
-		.short \sp_offset
-		.byte \sp_reg
-		.byte \type
-		.byte \signal
-		.byte \end
-		.balign 4
-	.popsection
-.endm
-
 .macro STACK_FRAME_NON_STANDARD func:req
 	.pushsection .discard.func_stack_frame_non_standard, "aw"
 	_ASM_PTR \func
@@ -177,16 +111,12 @@ struct unwind_hint {
 
 #ifndef __ASSEMBLY__
 
-#define UNWIND_HINT(sp_reg, sp_offset, type, signal, end) \
-	"\n\t"
 #define STACK_FRAME_NON_STANDARD(func)
 #define STACK_FRAME_NON_STANDARD_FP(func)
 #define ANNOTATE_NOENDBR
 #define ASM_REACHABLE
 #else
 #define ANNOTATE_INTRA_FUNCTION_CALL
-.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 signal=0 end=0
-.endm
 .macro STACK_FRAME_NON_STANDARD func:req
 .endm
 .macro ANNOTATE_NOENDBR
diff --git a/tools/objtool/Build b/tools/objtool/Build
index 64ccae49cd5f..4e9ec210f134 100644
--- a/tools/objtool/Build
+++ b/tools/objtool/Build
@@ -8,6 +8,7 @@ objtool-y += builtin-check.o
 objtool-y += cfi.o
 objtool-y += insn.o
 objtool-y += decode.o
+objtool-y += unwind_hints.o
 objtool-y += elf.o
 objtool-y += objtool.o
 
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 26ed9b0b8f49..f91723010d6b 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -1842,103 +1842,6 @@ static int add_jump_table_alts(struct objtool_file *file)
 	return 0;
 }
 
-static int read_unwind_hints(struct objtool_file *file)
-{
-	struct cfi_state cfi = init_cfi;
-	struct section *sec, *relocsec;
-	struct unwind_hint *hint;
-	struct instruction *insn;
-	struct reloc *reloc;
-	int i;
-
-	sec = find_section_by_name(file->elf, ".discard.unwind_hints");
-	if (!sec)
-		return 0;
-
-	relocsec = sec->reloc;
-	if (!relocsec) {
-		WARN("missing .rela.discard.unwind_hints section");
-		return -1;
-	}
-
-	if (sec->sh.sh_size % sizeof(struct unwind_hint)) {
-		WARN("struct unwind_hint size mismatch");
-		return -1;
-	}
-
-	file->hints = true;
-
-	for (i = 0; i < sec->sh.sh_size / sizeof(struct unwind_hint); i++) {
-		hint = (struct unwind_hint *)sec->data->d_buf + i;
-
-		reloc = find_reloc_by_dest(file->elf, sec, i * sizeof(*hint));
-		if (!reloc) {
-			WARN("can't find reloc for unwind_hints[%d]", i);
-			return -1;
-		}
-
-		insn = find_insn(file, reloc->sym->sec, reloc->addend);
-		if (!insn) {
-			WARN("can't find insn for unwind_hints[%d]", i);
-			return -1;
-		}
-
-		insn->hint = true;
-
-		if (hint->type == UNWIND_HINT_TYPE_SAVE) {
-			insn->hint = false;
-			insn->save = true;
-			continue;
-		}
-
-		if (hint->type == UNWIND_HINT_TYPE_RESTORE) {
-			insn->restore = true;
-			continue;
-		}
-
-		if (hint->type == UNWIND_HINT_TYPE_REGS_PARTIAL) {
-			struct symbol *sym = find_symbol_by_offset(insn->sec, insn->offset);
-
-			if (sym && sym->bind == STB_GLOBAL) {
-				if (opts.ibt && insn->type != INSN_ENDBR && !insn->noendbr) {
-					WARN_FUNC("UNWIND_HINT_IRET_REGS without ENDBR",
-						  insn->sec, insn->offset);
-				}
-
-				insn->entry = 1;
-			}
-		}
-
-		if (hint->type == UNWIND_HINT_TYPE_ENTRY) {
-			hint->type = UNWIND_HINT_TYPE_CALL;
-			insn->entry = 1;
-		}
-
-		if (hint->type == UNWIND_HINT_TYPE_FUNC) {
-			insn->cfi = &func_cfi;
-			continue;
-		}
-
-		if (insn->cfi)
-			cfi = *(insn->cfi);
-
-		if (arch_decode_hint_reg(hint->sp_reg, &cfi.cfa.base)) {
-			WARN_FUNC("unsupported unwind_hint sp base reg %d",
-				  insn->sec, insn->offset, hint->sp_reg);
-			return -1;
-		}
-
-		cfi.cfa.offset = bswap_if_needed(file->elf, hint->sp_offset);
-		cfi.type = hint->type;
-		cfi.signal = hint->signal;
-		cfi.end = hint->end;
-
-		insn->cfi = cfi_hash_find_or_add(&cfi);
-	}
-
-	return 0;
-}
-
 static int read_noendbr_hints(struct objtool_file *file)
 {
 	struct section *sec;
diff --git a/tools/objtool/include/objtool/insn.h b/tools/objtool/include/objtool/insn.h
index 92f8f1ff6c09..0b37d72f06eb 100644
--- a/tools/objtool/include/objtool/insn.h
+++ b/tools/objtool/include/objtool/insn.h
@@ -128,6 +128,7 @@ bool is_first_func_insn(struct objtool_file *file,
 
 
 int decode_instructions(struct objtool_file *file);
+int read_unwind_hints(struct objtool_file *file);
 
 #define for_each_insn(file, insn)					\
 	for (struct section *__sec, *__fake = (struct section *)1;	\
diff --git a/tools/objtool/sync-check.sh b/tools/objtool/sync-check.sh
index 105a291ff8e7..ee49b4e9e72c 100755
--- a/tools/objtool/sync-check.sh
+++ b/tools/objtool/sync-check.sh
@@ -14,6 +14,7 @@ arch/x86/include/asm/nops.h
 arch/x86/include/asm/inat_types.h
 arch/x86/include/asm/orc_types.h
 arch/x86/include/asm/emulate_prefix.h
+arch/x86/include/asm/unwind_hints.h
 arch/x86/lib/x86-opcode-map.txt
 arch/x86/tools/gen-insn-attr-x86.awk
 include/linux/static_call_types.h
diff --git a/tools/objtool/unwind_hints.c b/tools/objtool/unwind_hints.c
new file mode 100644
index 000000000000..a5aaeaafc16e
--- /dev/null
+++ b/tools/objtool/unwind_hints.c
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2015-2017 Josh Poimboeuf <jpoimboe@redhat.com>
+ */
+#include <asm/unwind_hints.h>
+
+#include <objtool/builtin.h>
+#include <objtool/endianness.h>
+#include <objtool/insn.h>
+#include <objtool/warn.h>
+
+int read_unwind_hints(struct objtool_file *file)
+{
+	struct cfi_state cfi = init_cfi;
+	struct section *sec, *relocsec;
+	struct unwind_hint *hint;
+	struct instruction *insn;
+	struct reloc *reloc;
+	int i;
+
+	sec = find_section_by_name(file->elf, ".discard.unwind_hints");
+	if (!sec)
+		return 0;
+
+	relocsec = sec->reloc;
+	if (!relocsec) {
+		WARN("missing .rela.discard.unwind_hints section");
+		return -1;
+	}
+
+	if (sec->sh.sh_size % sizeof(struct unwind_hint)) {
+		WARN("struct unwind_hint size mismatch");
+		return -1;
+	}
+
+	file->hints = true;
+
+	for (i = 0; i < sec->sh.sh_size / sizeof(struct unwind_hint); i++) {
+		hint = (struct unwind_hint *)sec->data->d_buf + i;
+
+		reloc = find_reloc_by_dest(file->elf, sec, i * sizeof(*hint));
+		if (!reloc) {
+			WARN("can't find reloc for unwind_hints[%d]", i);
+			return -1;
+		}
+
+		insn = find_insn(file, reloc->sym->sec, reloc->addend);
+		if (!insn) {
+			WARN("can't find insn for unwind_hints[%d]", i);
+			return -1;
+		}
+
+		insn->hint = true;
+
+		if (hint->type == UNWIND_HINT_TYPE_SAVE) {
+			insn->hint = false;
+			insn->save = true;
+			continue;
+		}
+
+		if (hint->type == UNWIND_HINT_TYPE_RESTORE) {
+			insn->restore = true;
+			continue;
+		}
+
+		if (hint->type == UNWIND_HINT_TYPE_REGS_PARTIAL) {
+			struct symbol *sym = find_symbol_by_offset(insn->sec, insn->offset);
+
+			if (sym && sym->bind == STB_GLOBAL) {
+				if (opts.ibt && insn->type != INSN_ENDBR && !insn->noendbr) {
+					WARN_FUNC("UNWIND_HINT_IRET_REGS without ENDBR",
+						  insn->sec, insn->offset);
+				}
+
+				insn->entry = 1;
+			}
+		}
+
+		if (hint->type == UNWIND_HINT_TYPE_ENTRY) {
+			hint->type = UNWIND_HINT_TYPE_CALL;
+			insn->entry = 1;
+		}
+
+		if (hint->type == UNWIND_HINT_TYPE_FUNC) {
+			insn->cfi = &func_cfi;
+			continue;
+		}
+
+		if (insn->cfi)
+			cfi = *(insn->cfi);
+
+		if (arch_decode_hint_reg(hint->sp_reg, &cfi.cfa.base)) {
+			WARN_FUNC("unsupported unwind_hint sp base reg %d",
+				  insn->sec, insn->offset, hint->sp_reg);
+			return -1;
+		}
+
+		cfi.cfa.offset = bswap_if_needed(file->elf, hint->sp_offset);
+		cfi.type = hint->type;
+		cfi.signal = hint->signal;
+		cfi.end = hint->end;
+
+		insn->cfi = cfi_hash_find_or_add(&cfi);
+	}
+
+	return 0;
+}
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [RFC PATCH v1 00/23] LoongArch: Add objtool and ORC unwinder support
  2023-06-20  7:46 [RFC PATCH v1 00/23] LoongArch: Add objtool and ORC unwinder support Youling Tang
                   ` (3 preceding siblings ...)
  2023-06-20  7:46 ` [RFC PATCH v1 04/23] objtool: Reorganize Unwind hint code Youling Tang
@ 2023-06-20  8:15 ` Xi Ruoyao
  2023-06-20  8:29   ` Youling Tang
  2023-06-20  8:42 ` Peter Zijlstra
  5 siblings, 1 reply; 12+ messages in thread
From: Xi Ruoyao @ 2023-06-20  8:15 UTC (permalink / raw)
  To: Youling Tang, Josh Poimboeuf, Peter Zijlstra, Huacai Chen,
	madvenka
  Cc: chenzhongjin, WANG Xuerui, live-patching, linux-kernel, loongarch,
	tangyouling00, youling.tang

It looks like only 19 patches are successfully delivered, out of 23.

And AFAIK objtool needs libelf from elfutils, and the LoongArch support
in elfutils is not complete (there are about ten failures in the test
suite as at the latest 0.189 release).  Do we need to add more LoongArch
support into libelf and/or declare a minimal needed libelf version for
LoongArch objtool?

On Tue, 2023-06-20 at 15:46 +0800, Youling Tang wrote:
> This series of patches adds objtool and ORC unwinder support for
> LoongArch.
> 
> Patch 01 - 07 are from "Madhavan T. Venkataraman" [1] with minor
> code tweaks. The "objtool: Reorganize ORC types" patch was not
> added, because LoongArch cannot share `strcut orc_entry`, it also
> needs to include ra_offset and ra_reg.
> 
> Since the changes in Patch 01 - 08 in [1] are architecture-
> independent,
> it might be better if they could be separated separately from the
> series
> of patches.
> 
> ORC unwinder can get a reliable stack trace, which provides a
> prerequisite
> for the subsequent addition of livepatch support.
> 
> 
> Instruction decoder
> ===================
> 
> To do this, an instruction decoder needs to be implemented. I have
> implemented
> a simple, table-driven decoder for LoongArch. Only a subset of the
> instructions
> needs to be fully decoded for this purpose:
> 
>         - Load-Store instructions
>         - Add instructions
>         - Branch instructions
>         - Call instructions
>         - Return instructions
>         - Stack pointer authentication instruction
> 
> 
> Unwind hints
> ============
> 
> Unwind hints are collected in a special section. Objtool converts
> unwind hints
> to ORC data. The unwinder processes unwind hints to handle special
> cases
> mentioned above.
> 
> 
> ORC unwinder
> ============
> 
> Before vmlinux created, we check all metadata, find the stack
> operation,
> note stack state and create orc data. Objtool insert two sections into
> vmlinux. '.orc_unwind_ip' and '.orc_unwind'. (For modules, insert
> '.rela.orc_unwind_ip' to relocate '.orc_unwind_ip'.) Each insn has
> only
> one stack state in .orc_unwind and orc_unwind_ip hint its pc address.
> Through unwinding orc data, we can get stack info both kernel and
> module.
> 
> 
> This is a series of RFC patches, which may require long-term
> discussions
> and revisions. It is not based on the latest code but based on 6.3-
> rc3.
> Any ideas or suggestions are welcome.
> 
> base-commit: e8d018dd0257f744ca50a729e3d042cf2ec9da65 (Linux 6.3-rc3)
> 
> Link:
> [1]:
> https://lore.kernel.org/lkml/20230202074036.507249-1-madvenka@linux.microsoft.com/#r
> 
> Madhavan T. Venkataraman (7):
>   objtool: Reorganize CFI code
>   objtool: Reorganize instruction-related code
>   objtool: Move decode_instructions() to a separate file
>   objtool: Reorganize Unwind hint code
>   objtool: Reorganize ORC code
>   objtool: Reorganize ORC kernel code
>   objtool: Introduce STATIC_CHECK
> 
> Youling Tang (16):
>   tools: LoongArch: Copy inst.h and asm.h to tools
>   objtool: LoongArch: Add base definition for LoongArch
>   objtool: LoongArch: Implement decoder
>   objtool: Add annotate_reachable() for objtools
>   LoongArch: bug: Add reachable annotation to warning macros
>   objtool: Add next member in struct reloc
>   objtool: Add orc_print_dump() package
>   objtool: Add ORC support for LoongArch
>   LoongArch: Add ORC unwinder support
>   LoongArch: Support R_LARCH_32_PCREL relocation type in kernel module
>   LoongArch: Fix fpu.S objtool warning
>   LoongArch: Annotate unwind_hint
>   LoongArch: Move some data definitions into the .data section
>   objtool: Add arch-specific "noreturn" function handling
>   objtool: Make update_cfi_state() arch-specific function
>   LoongArch: objtool: Mark non-standard object files and directories
> 
>  arch/loongarch/Kconfig                        |   2 +
>  arch/loongarch/Kconfig.debug                  |  11 +
>  arch/loongarch/Makefile                       |   4 +
>  arch/loongarch/include/asm/bug.h              |   1 +
>  arch/loongarch/include/asm/module.h           |   7 +
>  arch/loongarch/include/asm/orc_types.h        |  58 ++
>  arch/loongarch/include/asm/stackframe.h       |   3 +
>  arch/loongarch/include/asm/unwind.h           |  17 +-
>  arch/loongarch/include/asm/unwind_hints.h     | 110 +++
>  arch/loongarch/kernel/Makefile                |   3 +
>  arch/loongarch/kernel/entry.S                 |   2 +
>  arch/loongarch/kernel/fpu.S                   |  11 +-
>  arch/loongarch/kernel/genex.S                 |   2 +
>  arch/loongarch/kernel/head.S                  |   1 +
>  arch/loongarch/kernel/module.c                |  21 +-
>  arch/loongarch/kernel/relocate_kernel.S       |  12 +-
>  arch/loongarch/kernel/setup.c                 |   2 +
>  arch/loongarch/kernel/stacktrace.c            |   1 +
>  arch/loongarch/kernel/unwind_orc.c            | 301 +++++++++
>  arch/loongarch/kernel/vmlinux.lds.S           |   3 +
>  arch/loongarch/power/Makefile                 |   2 +
>  arch/loongarch/vdso/Makefile                  |   2 +
>  arch/x86/include/asm/unwind.h                 |   5 -
>  arch/x86/include/asm/unwind_hints.h           |  86 +++
>  arch/x86/kernel/module.c                      |   7 +-
>  arch/x86/kernel/unwind_orc.c                  | 268 +-------
>  arch/x86/kernel/vmlinux.lds.S                 |   2 +-
>  .../asm => include/asm-generic}/orc_lookup.h  |  43 ++
>  include/linux/compiler.h                      |   9 +
>  include/linux/objtool.h                       |  70 --
>  kernel/Makefile                               |   2 +
>  kernel/orc_lookup.c                           | 261 ++++++++
>  scripts/Makefile                              |   5 +-
>  tools/arch/loongarch/include/asm/asm.h        | 201 ++++++
>  tools/arch/loongarch/include/asm/inst.h       | 629
> ++++++++++++++++++
>  tools/arch/loongarch/include/asm/orc_types.h  |  58 ++
>  .../arch/loongarch/include/asm/unwind_hints.h | 110 +++
>  tools/arch/x86/include/asm/unwind_hints.h     | 160 +++++
>  tools/include/linux/bitops.h                  |  10 +
>  tools/include/linux/objtool.h                 |  70 --
>  tools/objtool/Build                           |   8 +-
>  tools/objtool/Makefile                        |   9 +-
>  tools/objtool/arch/loongarch/Build            |   3 +
>  tools/objtool/arch/loongarch/decode.c         | 352 ++++++++++
>  .../arch/loongarch/include/arch/cfi_regs.h    |  14 +
>  .../objtool/arch/loongarch/include/arch/elf.h |  15 +
>  .../arch/loongarch/include/arch/special.h     |  21 +
>  tools/objtool/arch/loongarch/orc.c            | 155 +++++
>  tools/objtool/arch/loongarch/special.c        |  25 +
>  tools/objtool/arch/powerpc/special.c          |   3 +
>  tools/objtool/arch/x86/Build                  |   1 +
>  tools/objtool/arch/x86/include/arch/elf.h     |   1 +
>  tools/objtool/arch/x86/orc.c                  | 164 +++++
>  tools/objtool/arch/x86/special.c              |   4 +
>  tools/objtool/cfi.c                           | 108 +++
>  tools/objtool/check.c                         | 568 +---------------
>  tools/objtool/decode.c                        | 136 ++++
>  tools/objtool/elf.c                           |  11 +-
>  tools/objtool/include/objtool/arch.h          |   3 +
>  tools/objtool/include/objtool/cfi.h           |  12 +
>  tools/objtool/include/objtool/check.h         |  97 +--
>  tools/objtool/include/objtool/elf.h           |   1 +
>  tools/objtool/include/objtool/insn.h          | 166 +++++
>  tools/objtool/include/objtool/objtool.h       |   3 +
>  tools/objtool/include/objtool/orc.h           |  15 +
>  tools/objtool/include/objtool/special.h       |   3 +
>  tools/objtool/insn.c                          | 195 ++++++
>  tools/objtool/orc_dump.c                      |  67 +-
>  tools/objtool/orc_gen.c                       |  79 +--
>  tools/objtool/sync-check.sh                   |   9 +
>  tools/objtool/unwind_hints.c                  | 107 +++
>  71 files changed, 3721 insertions(+), 1206 deletions(-)
>  create mode 100644 arch/loongarch/include/asm/orc_types.h
>  create mode 100644 arch/loongarch/include/asm/unwind_hints.h
>  create mode 100644 arch/loongarch/kernel/unwind_orc.c
>  rename {arch/x86/include/asm => include/asm-generic}/orc_lookup.h
> (50%)
>  create mode 100644 kernel/orc_lookup.c
>  create mode 100644 tools/arch/loongarch/include/asm/asm.h
>  create mode 100644 tools/arch/loongarch/include/asm/inst.h
>  create mode 100644 tools/arch/loongarch/include/asm/orc_types.h
>  create mode 100644 tools/arch/loongarch/include/asm/unwind_hints.h
>  create mode 100644 tools/arch/x86/include/asm/unwind_hints.h
>  create mode 100644 tools/objtool/arch/loongarch/Build
>  create mode 100644 tools/objtool/arch/loongarch/decode.c
>  create mode 100644
> tools/objtool/arch/loongarch/include/arch/cfi_regs.h
>  create mode 100644 tools/objtool/arch/loongarch/include/arch/elf.h
>  create mode 100644
> tools/objtool/arch/loongarch/include/arch/special.h
>  create mode 100644 tools/objtool/arch/loongarch/orc.c
>  create mode 100644 tools/objtool/arch/loongarch/special.c
>  create mode 100644 tools/objtool/arch/x86/orc.c
>  create mode 100644 tools/objtool/cfi.c
>  create mode 100644 tools/objtool/decode.c
>  create mode 100644 tools/objtool/include/objtool/insn.h
>  create mode 100644 tools/objtool/include/objtool/orc.h
>  create mode 100644 tools/objtool/insn.c
>  create mode 100644 tools/objtool/unwind_hints.c
> 

-- 
Xi Ruoyao <xry111@xry111.site>
School of Aerospace Science and Technology, Xidian University

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [RFC PATCH v1 00/23] LoongArch: Add objtool and ORC unwinder support
  2023-06-20  8:15 ` [RFC PATCH v1 00/23] LoongArch: Add objtool and ORC unwinder support Xi Ruoyao
@ 2023-06-20  8:29   ` Youling Tang
  2023-06-20  8:32     ` Xi Ruoyao
  2023-06-20  8:38     ` Peter Zijlstra
  0 siblings, 2 replies; 12+ messages in thread
From: Youling Tang @ 2023-06-20  8:29 UTC (permalink / raw)
  To: Xi Ruoyao
  Cc: Josh Poimboeuf, Peter Zijlstra, Huacai Chen, madvenka,
	chenzhongjin, WANG Xuerui, live-patching, linux-kernel, loongarch,
	tangyouling00, youling.tang

Hi, Ruoyao

On 06/20/2023 04:15 PM, Xi Ruoyao wrote:
> It looks like only 19 patches are successfully delivered, out of 23.
I'm sorry, somehow the patchset didn't reach the mailing list. Probably
due to the sending limit being reached.

>
> And AFAIK objtool needs libelf from elfutils, and the LoongArch support
> in elfutils is not complete (there are about ten failures in the test
> suite as at the latest 0.189 release).  Do we need to add more LoongArch
> support into libelf and/or declare a minimal needed libelf version for
> LoongArch objtool?
After the following series of patches [1], the elfutils test results
are passed.

[1]: https://sourceware.org/pipermail/elfutils-devel/2023q2/006107.html

Thanks,
Youling
>
> On Tue, 2023-06-20 at 15:46 +0800, Youling Tang wrote:
>> This series of patches adds objtool and ORC unwinder support for
>> LoongArch.
>>
>> Patch 01 - 07 are from "Madhavan T. Venkataraman" [1] with minor
>> code tweaks. The "objtool: Reorganize ORC types" patch was not
>> added, because LoongArch cannot share `strcut orc_entry`, it also
>> needs to include ra_offset and ra_reg.
>>
>> Since the changes in Patch 01 - 08 in [1] are architecture-
>> independent,
>> it might be better if they could be separated separately from the
>> series
>> of patches.
>>
>> ORC unwinder can get a reliable stack trace, which provides a
>> prerequisite
>> for the subsequent addition of livepatch support.
>>
>>
>> Instruction decoder
>> ===================
>>
>> To do this, an instruction decoder needs to be implemented. I have
>> implemented
>> a simple, table-driven decoder for LoongArch. Only a subset of the
>> instructions
>> needs to be fully decoded for this purpose:
>>
>>         - Load-Store instructions
>>         - Add instructions
>>         - Branch instructions
>>         - Call instructions
>>         - Return instructions
>>         - Stack pointer authentication instruction
>>
>>
>> Unwind hints
>> ============
>>
>> Unwind hints are collected in a special section. Objtool converts
>> unwind hints
>> to ORC data. The unwinder processes unwind hints to handle special
>> cases
>> mentioned above.
>>
>>
>> ORC unwinder
>> ============
>>
>> Before vmlinux created, we check all metadata, find the stack
>> operation,
>> note stack state and create orc data. Objtool insert two sections into
>> vmlinux. '.orc_unwind_ip' and '.orc_unwind'. (For modules, insert
>> '.rela.orc_unwind_ip' to relocate '.orc_unwind_ip'.) Each insn has
>> only
>> one stack state in .orc_unwind and orc_unwind_ip hint its pc address.
>> Through unwinding orc data, we can get stack info both kernel and
>> module.
>>
>>
>> This is a series of RFC patches, which may require long-term
>> discussions
>> and revisions. It is not based on the latest code but based on 6.3-
>> rc3.
>> Any ideas or suggestions are welcome.
>>
>> base-commit: e8d018dd0257f744ca50a729e3d042cf2ec9da65 (Linux 6.3-rc3)
>>
>> Link:
>> [1]:
>> https://lore.kernel.org/lkml/20230202074036.507249-1-madvenka@linux.microsoft.com/#r
>>
>> Madhavan T. Venkataraman (7):
>>   objtool: Reorganize CFI code
>>   objtool: Reorganize instruction-related code
>>   objtool: Move decode_instructions() to a separate file
>>   objtool: Reorganize Unwind hint code
>>   objtool: Reorganize ORC code
>>   objtool: Reorganize ORC kernel code
>>   objtool: Introduce STATIC_CHECK
>>
>> Youling Tang (16):
>>   tools: LoongArch: Copy inst.h and asm.h to tools
>>   objtool: LoongArch: Add base definition for LoongArch
>>   objtool: LoongArch: Implement decoder
>>   objtool: Add annotate_reachable() for objtools
>>   LoongArch: bug: Add reachable annotation to warning macros
>>   objtool: Add next member in struct reloc
>>   objtool: Add orc_print_dump() package
>>   objtool: Add ORC support for LoongArch
>>   LoongArch: Add ORC unwinder support
>>   LoongArch: Support R_LARCH_32_PCREL relocation type in kernel module
>>   LoongArch: Fix fpu.S objtool warning
>>   LoongArch: Annotate unwind_hint
>>   LoongArch: Move some data definitions into the .data section
>>   objtool: Add arch-specific "noreturn" function handling
>>   objtool: Make update_cfi_state() arch-specific function
>>   LoongArch: objtool: Mark non-standard object files and directories
>>
>>  arch/loongarch/Kconfig                        |   2 +
>>  arch/loongarch/Kconfig.debug                  |  11 +
>>  arch/loongarch/Makefile                       |   4 +
>>  arch/loongarch/include/asm/bug.h              |   1 +
>>  arch/loongarch/include/asm/module.h           |   7 +
>>  arch/loongarch/include/asm/orc_types.h        |  58 ++
>>  arch/loongarch/include/asm/stackframe.h       |   3 +
>>  arch/loongarch/include/asm/unwind.h           |  17 +-
>>  arch/loongarch/include/asm/unwind_hints.h     | 110 +++
>>  arch/loongarch/kernel/Makefile                |   3 +
>>  arch/loongarch/kernel/entry.S                 |   2 +
>>  arch/loongarch/kernel/fpu.S                   |  11 +-
>>  arch/loongarch/kernel/genex.S                 |   2 +
>>  arch/loongarch/kernel/head.S                  |   1 +
>>  arch/loongarch/kernel/module.c                |  21 +-
>>  arch/loongarch/kernel/relocate_kernel.S       |  12 +-
>>  arch/loongarch/kernel/setup.c                 |   2 +
>>  arch/loongarch/kernel/stacktrace.c            |   1 +
>>  arch/loongarch/kernel/unwind_orc.c            | 301 +++++++++
>>  arch/loongarch/kernel/vmlinux.lds.S           |   3 +
>>  arch/loongarch/power/Makefile                 |   2 +
>>  arch/loongarch/vdso/Makefile                  |   2 +
>>  arch/x86/include/asm/unwind.h                 |   5 -
>>  arch/x86/include/asm/unwind_hints.h           |  86 +++
>>  arch/x86/kernel/module.c                      |   7 +-
>>  arch/x86/kernel/unwind_orc.c                  | 268 +-------
>>  arch/x86/kernel/vmlinux.lds.S                 |   2 +-
>>  .../asm => include/asm-generic}/orc_lookup.h  |  43 ++
>>  include/linux/compiler.h                      |   9 +
>>  include/linux/objtool.h                       |  70 --
>>  kernel/Makefile                               |   2 +
>>  kernel/orc_lookup.c                           | 261 ++++++++
>>  scripts/Makefile                              |   5 +-
>>  tools/arch/loongarch/include/asm/asm.h        | 201 ++++++
>>  tools/arch/loongarch/include/asm/inst.h       | 629
>> ++++++++++++++++++
>>  tools/arch/loongarch/include/asm/orc_types.h  |  58 ++
>>  .../arch/loongarch/include/asm/unwind_hints.h | 110 +++
>>  tools/arch/x86/include/asm/unwind_hints.h     | 160 +++++
>>  tools/include/linux/bitops.h                  |  10 +
>>  tools/include/linux/objtool.h                 |  70 --
>>  tools/objtool/Build                           |   8 +-
>>  tools/objtool/Makefile                        |   9 +-
>>  tools/objtool/arch/loongarch/Build            |   3 +
>>  tools/objtool/arch/loongarch/decode.c         | 352 ++++++++++
>>  .../arch/loongarch/include/arch/cfi_regs.h    |  14 +
>>  .../objtool/arch/loongarch/include/arch/elf.h |  15 +
>>  .../arch/loongarch/include/arch/special.h     |  21 +
>>  tools/objtool/arch/loongarch/orc.c            | 155 +++++
>>  tools/objtool/arch/loongarch/special.c        |  25 +
>>  tools/objtool/arch/powerpc/special.c          |   3 +
>>  tools/objtool/arch/x86/Build                  |   1 +
>>  tools/objtool/arch/x86/include/arch/elf.h     |   1 +
>>  tools/objtool/arch/x86/orc.c                  | 164 +++++
>>  tools/objtool/arch/x86/special.c              |   4 +
>>  tools/objtool/cfi.c                           | 108 +++
>>  tools/objtool/check.c                         | 568 +---------------
>>  tools/objtool/decode.c                        | 136 ++++
>>  tools/objtool/elf.c                           |  11 +-
>>  tools/objtool/include/objtool/arch.h          |   3 +
>>  tools/objtool/include/objtool/cfi.h           |  12 +
>>  tools/objtool/include/objtool/check.h         |  97 +--
>>  tools/objtool/include/objtool/elf.h           |   1 +
>>  tools/objtool/include/objtool/insn.h          | 166 +++++
>>  tools/objtool/include/objtool/objtool.h       |   3 +
>>  tools/objtool/include/objtool/orc.h           |  15 +
>>  tools/objtool/include/objtool/special.h       |   3 +
>>  tools/objtool/insn.c                          | 195 ++++++
>>  tools/objtool/orc_dump.c                      |  67 +-
>>  tools/objtool/orc_gen.c                       |  79 +--
>>  tools/objtool/sync-check.sh                   |   9 +
>>  tools/objtool/unwind_hints.c                  | 107 +++
>>  71 files changed, 3721 insertions(+), 1206 deletions(-)
>>  create mode 100644 arch/loongarch/include/asm/orc_types.h
>>  create mode 100644 arch/loongarch/include/asm/unwind_hints.h
>>  create mode 100644 arch/loongarch/kernel/unwind_orc.c
>>  rename {arch/x86/include/asm => include/asm-generic}/orc_lookup.h
>> (50%)
>>  create mode 100644 kernel/orc_lookup.c
>>  create mode 100644 tools/arch/loongarch/include/asm/asm.h
>>  create mode 100644 tools/arch/loongarch/include/asm/inst.h
>>  create mode 100644 tools/arch/loongarch/include/asm/orc_types.h
>>  create mode 100644 tools/arch/loongarch/include/asm/unwind_hints.h
>>  create mode 100644 tools/arch/x86/include/asm/unwind_hints.h
>>  create mode 100644 tools/objtool/arch/loongarch/Build
>>  create mode 100644 tools/objtool/arch/loongarch/decode.c
>>  create mode 100644
>> tools/objtool/arch/loongarch/include/arch/cfi_regs.h
>>  create mode 100644 tools/objtool/arch/loongarch/include/arch/elf.h
>>  create mode 100644
>> tools/objtool/arch/loongarch/include/arch/special.h
>>  create mode 100644 tools/objtool/arch/loongarch/orc.c
>>  create mode 100644 tools/objtool/arch/loongarch/special.c
>>  create mode 100644 tools/objtool/arch/x86/orc.c
>>  create mode 100644 tools/objtool/cfi.c
>>  create mode 100644 tools/objtool/decode.c
>>  create mode 100644 tools/objtool/include/objtool/insn.h
>>  create mode 100644 tools/objtool/include/objtool/orc.h
>>  create mode 100644 tools/objtool/insn.c
>>  create mode 100644 tools/objtool/unwind_hints.c
>>
>


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [RFC PATCH v1 00/23] LoongArch: Add objtool and ORC unwinder support
  2023-06-20  8:29   ` Youling Tang
@ 2023-06-20  8:32     ` Xi Ruoyao
  2023-06-20  8:38     ` Peter Zijlstra
  1 sibling, 0 replies; 12+ messages in thread
From: Xi Ruoyao @ 2023-06-20  8:32 UTC (permalink / raw)
  To: Youling Tang
  Cc: Josh Poimboeuf, Peter Zijlstra, Huacai Chen, madvenka,
	chenzhongjin, WANG Xuerui, live-patching, linux-kernel, loongarch,
	tangyouling00, youling.tang

On Tue, 2023-06-20 at 16:29 +0800, Youling Tang wrote:
> Hi, Ruoyao
> 
> On 06/20/2023 04:15 PM, Xi Ruoyao wrote:
> > It looks like only 19 patches are successfully delivered, out of 23.
> I'm sorry, somehow the patchset didn't reach the mailing list. Probably
> due to the sending limit being reached.

They've reached now.  Thanks!

> > And AFAIK objtool needs libelf from elfutils, and the LoongArch support
> > in elfutils is not complete (there are about ten failures in the test
> > suite as at the latest 0.189 release).  Do we need to add more LoongArch
> > support into libelf and/or declare a minimal needed libelf version for
> > LoongArch objtool?

> After the following series of patches [1], the elfutils test results
> are passed.
> 
> [1]: https://sourceware.org/pipermail/elfutils-devel/2023q2/006107.html

Wow thanks, I'll add them into my build.  But I'm not sure if we need a
libelf version check or something in the kernel building system.

-- 
Xi Ruoyao <xry111@xry111.site>
School of Aerospace Science and Technology, Xidian University

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [RFC PATCH v1 00/23] LoongArch: Add objtool and ORC unwinder support
  2023-06-20  8:29   ` Youling Tang
  2023-06-20  8:32     ` Xi Ruoyao
@ 2023-06-20  8:38     ` Peter Zijlstra
  2023-06-20  8:48       ` Xi Ruoyao
  2023-06-20  8:49       ` Youling Tang
  1 sibling, 2 replies; 12+ messages in thread
From: Peter Zijlstra @ 2023-06-20  8:38 UTC (permalink / raw)
  To: Youling Tang
  Cc: Xi Ruoyao, Josh Poimboeuf, Huacai Chen, madvenka, chenzhongjin,
	WANG Xuerui, live-patching, linux-kernel, loongarch,
	tangyouling00, youling.tang

On Tue, Jun 20, 2023 at 04:29:12PM +0800, Youling Tang wrote:
> Hi, Ruoyao
> 
> On 06/20/2023 04:15 PM, Xi Ruoyao wrote:
> > It looks like only 19 patches are successfully delivered, out of 23.
> I'm sorry, somehow the patchset didn't reach the mailing list. Probably
> due to the sending limit being reached.

I got all the patches, but their threading is broken, they come in
chunks of 5 or :/

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [RFC PATCH v1 00/23] LoongArch: Add objtool and ORC unwinder support
  2023-06-20  7:46 [RFC PATCH v1 00/23] LoongArch: Add objtool and ORC unwinder support Youling Tang
                   ` (4 preceding siblings ...)
  2023-06-20  8:15 ` [RFC PATCH v1 00/23] LoongArch: Add objtool and ORC unwinder support Xi Ruoyao
@ 2023-06-20  8:42 ` Peter Zijlstra
  5 siblings, 0 replies; 12+ messages in thread
From: Peter Zijlstra @ 2023-06-20  8:42 UTC (permalink / raw)
  To: Youling Tang
  Cc: Josh Poimboeuf, Huacai Chen, madvenka, chenzhongjin, WANG Xuerui,
	Xi Ruoyao, live-patching, linux-kernel, loongarch, tangyouling00,
	youling.tang

On Tue, Jun 20, 2023 at 03:46:26PM +0800, Youling Tang wrote:
> This series of patches adds objtool and ORC unwinder support for
> LoongArch.
> 
> Patch 01 - 07 are from "Madhavan T. Venkataraman" [1] with minor
> code tweaks. The "objtool: Reorganize ORC types" patch was not
> added, because LoongArch cannot share `strcut orc_entry`, it also
> needs to include ra_offset and ra_reg.

Yeah, I wish you would not have done that :-( I really don't like those
patches. I just don't much believe in that dynamic validation thing, and
doubly not for the patches you did pick not including any actual
rationale for it.


Also, the patches very much do not apply to tip/objtool/core,
specifically Josh recently reworked the reloc stuff quite dramatically.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [RFC PATCH v1 00/23] LoongArch: Add objtool and ORC unwinder support
  2023-06-20  8:38     ` Peter Zijlstra
@ 2023-06-20  8:48       ` Xi Ruoyao
  2023-06-20  8:49       ` Youling Tang
  1 sibling, 0 replies; 12+ messages in thread
From: Xi Ruoyao @ 2023-06-20  8:48 UTC (permalink / raw)
  To: Peter Zijlstra, Youling Tang
  Cc: Josh Poimboeuf, Huacai Chen, madvenka, chenzhongjin, WANG Xuerui,
	live-patching, linux-kernel, loongarch, tangyouling00,
	youling.tang

On Tue, 2023-06-20 at 10:38 +0200, Peter Zijlstra wrote:
> On Tue, Jun 20, 2023 at 04:29:12PM +0800, Youling Tang wrote:
> > Hi, Ruoyao
> > 
> > On 06/20/2023 04:15 PM, Xi Ruoyao wrote:
> > > It looks like only 19 patches are successfully delivered, out of 23.
> > I'm sorry, somehow the patchset didn't reach the mailing list. Probably
> > due to the sending limit being reached.
> 
> I got all the patches, but their threading is broken, they come in
> chunks of 5 or :/

Youling: when you need to resend a part of the series next time, you can
use the "--in-reply-to=" option of git send-email to avoid such an
issue.  See the man page of git send-email for details :).

-- 
Xi Ruoyao <xry111@xry111.site>
School of Aerospace Science and Technology, Xidian University

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [RFC PATCH v1 00/23] LoongArch: Add objtool and ORC unwinder support
  2023-06-20  8:38     ` Peter Zijlstra
  2023-06-20  8:48       ` Xi Ruoyao
@ 2023-06-20  8:49       ` Youling Tang
  1 sibling, 0 replies; 12+ messages in thread
From: Youling Tang @ 2023-06-20  8:49 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Xi Ruoyao, Josh Poimboeuf, Huacai Chen, madvenka, chenzhongjin,
	WANG Xuerui, live-patching, linux-kernel, loongarch,
	tangyouling00, youling.tang

Hi, Peter

On 06/20/2023 04:38 PM, Peter Zijlstra wrote:
> On Tue, Jun 20, 2023 at 04:29:12PM +0800, Youling Tang wrote:
>> Hi, Ruoyao
>>
>> On 06/20/2023 04:15 PM, Xi Ruoyao wrote:
>>> It looks like only 19 patches are successfully delivered, out of 23.
>> I'm sorry, somehow the patchset didn't reach the mailing list. Probably
>> due to the sending limit being reached.
>
> I got all the patches, but their threading is broken, they come in
> chunks of 5 or :/

Yes, due to the limitation of the mailbox, only 5 patches can be sent
at a time (the number of patches multiplied by the number of people
sent), so the thread was interrupted, which caused inconvenience to the
review code, I am very sorry.

Thanks,
Youling


^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2023-06-20  8:49 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-06-20  7:46 [RFC PATCH v1 00/23] LoongArch: Add objtool and ORC unwinder support Youling Tang
2023-06-20  7:46 ` [RFC PATCH v1 01/23] objtool: Reorganize CFI code Youling Tang
2023-06-20  7:46 ` [RFC PATCH v1 02/23] objtool: Reorganize instruction-related code Youling Tang
2023-06-20  7:46 ` [RFC PATCH v1 03/23] objtool: Move decode_instructions() to a separate file Youling Tang
2023-06-20  7:46 ` [RFC PATCH v1 04/23] objtool: Reorganize Unwind hint code Youling Tang
2023-06-20  8:15 ` [RFC PATCH v1 00/23] LoongArch: Add objtool and ORC unwinder support Xi Ruoyao
2023-06-20  8:29   ` Youling Tang
2023-06-20  8:32     ` Xi Ruoyao
2023-06-20  8:38     ` Peter Zijlstra
2023-06-20  8:48       ` Xi Ruoyao
2023-06-20  8:49       ` Youling Tang
2023-06-20  8:42 ` Peter Zijlstra

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox