From nobody Tue Apr 23 06:20:23 2024 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1F468C433FE for ; Tue, 24 May 2022 00:16:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231383AbiEXAQw (ORCPT ); Mon, 23 May 2022 20:16:52 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58164 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229453AbiEXAQu (ORCPT ); Mon, 23 May 2022 20:16:50 -0400 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 7B8B36BFE2; Mon, 23 May 2022 17:16:48 -0700 (PDT) Received: from x64host.home (unknown [47.189.24.195]) by linux.microsoft.com (Postfix) with ESMTPSA id 69AFD20B6C7C; Mon, 23 May 2022 17:16:47 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 69AFD20B6C7C DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1653351408; bh=/tONLk1QXRDCTsXJLk+T4mjehc+6vK0E7p5YrpSTPtk=; h=From:To:Subject:Date:In-Reply-To:References:From; b=NtS0Q9D8QbZiGnNIvmshLwN+aeWRo/Unp38H0DrQs7OH58PS0FtYYPCjwFgHliFnp YRh9KMzz+qaWjpyB6+aDgGoXPMC9H1DdzQIfj8RDD9Tdf8DZvEY7DMmj49rpiWPT6E M9R40O6YRiI6c3DNueI5Lnw/B3tngTedfG2cNVhg= From: madvenka@linux.microsoft.com To: jpoimboe@redhat.com, peterz@infradead.org, chenzhongjin@huawei.com, mark.rutland@arm.com, broonie@kernel.org, nobuta.keiya@fujitsu.com, sjitindarsingh@gmail.com, catalin.marinas@arm.com, will@kernel.org, jamorris@linux.microsoft.com, linux-arm-kernel@lists.infradead.org, live-patching@vger.kernel.org, linux-kernel@vger.kernel.org, madvenka@linux.microsoft.com Subject: [RFC PATCH v2 01/20] objtool: Reorganize CFI code Date: Mon, 23 May 2022 19:16:18 -0500 Message-Id: <20220524001637.1707472-2-madvenka@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220524001637.1707472-1-madvenka@linux.microsoft.com> References: <20220524001637.1707472-1-madvenka@linux.microsoft.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: "Madhavan T. Venkataraman" 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 --- tools/objtool/Build | 2 + tools/objtool/cfi.c | 108 ++++++++++++++++++++++++++++ tools/objtool/check.c | 96 ------------------------- tools/objtool/include/objtool/cfi.h | 12 ++++ 4 files changed, 122 insertions(+), 96 deletions(-) create mode 100644 tools/objtool/cfi.c diff --git a/tools/objtool/Build b/tools/objtool/Build index b7222d5cc7bc..695cfee5cfde 100644 --- a/tools/objtool/Build +++ b/tools/objtool/Build @@ -3,8 +3,10 @@ objtool-y +=3D arch/$(SRCARCH)/ objtool-y +=3D weak.o =20 objtool-$(SUBCMD_CHECK) +=3D check.o +objtool-$(SUBCMD_CHECK) +=3D cfi.o objtool-$(SUBCMD_CHECK) +=3D special.o objtool-$(SUBCMD_ORC) +=3D check.o +objtool-$(SUBCMD_ORC) +=3D cfi.o objtool-$(SUBCMD_ORC) +=3D orc_gen.o objtool-$(SUBCMD_ORC) +=3D orc_dump.o =20 diff --git a/tools/objtool/cfi.c b/tools/objtool/cfi.c new file mode 100644 index 000000000000..d5de6df59d72 --- /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 + */ + +#include +#include + +#include +#include +#include + +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 =3D 0; i < CFI_NUM_REGS; i++) { + cfi->regs[i].base =3D CFI_UNDEFINED; + cfi->vals[i].base =3D CFI_UNDEFINED; + } + cfi->cfa.base =3D CFI_UNDEFINED; + cfi->drap_reg =3D CFI_UNDEFINED; + cfi->drap_offset =3D -1; +} + +static struct cfi_state *cfi_alloc(void) +{ + struct cfi_state *cfi =3D 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; + +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 =3D &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 =3D cfi_alloc(); + *obj =3D *cfi; + hlist_add_head(&obj->hash, head); + + return obj; +} + +void cfi_hash_add(struct cfi_state *cfi) +{ + struct hlist_head *head =3D &cfi_hash[hash_min(cfi_key(cfi), cfi_bits)]; + + hlist_add_head(&cfi->hash, head); +} + +void *cfi_hash_alloc(unsigned long size) +{ + cfi_bits =3D max(10, ilog2(size)); + cfi_hash =3D mmap(NULL, sizeof(struct hlist_head) << cfi_bits, + PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_ANON, -1, 0); + if (cfi_hash =3D=3D (void *)-1L) { + WARN("mmap fail cfi_hash"); + cfi_hash =3D NULL; + } else if (stats) { + printf("cfi_bits: %d\n", cfi_bits); + } + + return cfi_hash; +} + +void set_func_state(struct cfi_state *state) +{ + state->cfa =3D initial_func_cfi.cfa; + memcpy(&state->regs, &initial_func_cfi.regs, + CFI_NUM_REGS * sizeof(struct cfi_reg)); + state->stack_size =3D initial_func_cfi.cfa.offset; +} diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 6de5085e3e5a..12acc9d329de 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -27,12 +27,6 @@ struct alternative { bool skip_orig; }; =20 -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) { @@ -249,19 +243,6 @@ static bool dead_end_function(struct objtool_file *fil= e, struct symbol *func) return __dead_end_function(file, func, 0); } =20 -static void init_cfi_state(struct cfi_state *cfi) -{ - int i; - - for (i =3D 0; i < CFI_NUM_REGS; i++) { - cfi->regs[i].base =3D CFI_UNDEFINED; - cfi->vals[i].base =3D CFI_UNDEFINED; - } - cfi->cfa.base =3D CFI_UNDEFINED; - cfi->drap_reg =3D CFI_UNDEFINED; - cfi->drap_offset =3D -1; -} - static void init_insn_state(struct insn_state *state, struct section *sec) { memset(state, 0, sizeof(*state)); @@ -276,75 +257,6 @@ static void init_insn_state(struct insn_state *state, = struct section *sec) state->noinstr =3D sec->noinstr; } =20 -static struct cfi_state *cfi_alloc(void) -{ - struct cfi_state *cfi =3D 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 =3D &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 =3D cfi_alloc(); - *obj =3D *cfi; - hlist_add_head(&obj->hash, head); - - return obj; -} - -static void cfi_hash_add(struct cfi_state *cfi) -{ - struct hlist_head *head =3D &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 =3D max(10, ilog2(size)); - cfi_hash =3D mmap(NULL, sizeof(struct hlist_head) << cfi_bits, - PROT_READ|PROT_WRITE, - MAP_PRIVATE|MAP_ANON, -1, 0); - if (cfi_hash =3D=3D (void *)-1L) { - WARN("mmap fail cfi_hash"); - cfi_hash =3D NULL; - } else if (stats) { - printf("cfi_bits: %d\n", cfi_bits); - } - - return cfi_hash; -} - static unsigned long nr_insns; static unsigned long nr_insns_visited; =20 @@ -1866,14 +1778,6 @@ static int add_jump_table_alts(struct objtool_file *= file) return 0; } =20 -static void set_func_state(struct cfi_state *state) -{ - state->cfa =3D initial_func_cfi.cfa; - memcpy(&state->regs, &initial_func_cfi.regs, - CFI_NUM_REGS * sizeof(struct cfi_reg)); - state->stack_size =3D initial_func_cfi.cfa.offset; -} - static int read_unwind_hints(struct objtool_file *file) { struct cfi_state cfi =3D init_cfi; diff --git a/tools/objtool/include/objtool/cfi.h b/tools/objtool/include/ob= jtool/cfi.h index f11d1ac1dadf..7d54f1058655 100644 --- a/tools/objtool/include/objtool/cfi.h +++ b/tools/objtool/include/objtool/cfi.h @@ -37,4 +37,16 @@ struct cfi_state { bool end; }; =20 +void init_cfi_state(struct cfi_state *cfi); +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); +bool cficmp(struct cfi_state *cfi1, struct cfi_state *cfi2); +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 */ --=20 2.25.1 From nobody Tue Apr 23 06:20:23 2024 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id AF61CC433F5 for ; Tue, 24 May 2022 00:17:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231859AbiEXARE (ORCPT ); Mon, 23 May 2022 20:17:04 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58252 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231388AbiEXAQw (ORCPT ); Mon, 23 May 2022 20:16:52 -0400 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 82A3A6CF4A; Mon, 23 May 2022 17:16:49 -0700 (PDT) Received: from x64host.home (unknown [47.189.24.195]) by linux.microsoft.com (Postfix) with ESMTPSA id 6B09120B87F3; Mon, 23 May 2022 17:16:48 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 6B09120B87F3 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1653351409; bh=9y9cKfbuBrO4EQ8RsLvl2cKNoiaW3hR9J0HP0SgQ7u0=; h=From:To:Subject:Date:In-Reply-To:References:From; b=i404wv+sEbiZeISJwXrV6WeDh+LN1W9HkOvwtb9lKhqKCwjzbUyjC6IvG81oaTtUU e89NHGe+cavsthhRcY6+Pl0S4FbdAgo5pA/r4aZLc7H3o9NnzsAMw3PN2FFkd3EGAT jIpueh+uizFJX1JyOj9Nv9ORukALbNDuckET/4bc= From: madvenka@linux.microsoft.com To: jpoimboe@redhat.com, peterz@infradead.org, chenzhongjin@huawei.com, mark.rutland@arm.com, broonie@kernel.org, nobuta.keiya@fujitsu.com, sjitindarsingh@gmail.com, catalin.marinas@arm.com, will@kernel.org, jamorris@linux.microsoft.com, linux-arm-kernel@lists.infradead.org, live-patching@vger.kernel.org, linux-kernel@vger.kernel.org, madvenka@linux.microsoft.com Subject: [RFC PATCH v2 02/20] objtool: Reorganize instruction-related code Date: Mon, 23 May 2022 19:16:19 -0500 Message-Id: <20220524001637.1707472-3-madvenka@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220524001637.1707472-1-madvenka@linux.microsoft.com> References: <20220524001637.1707472-1-madvenka@linux.microsoft.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: "Madhavan T. Venkataraman" 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 --- tools/objtool/Build | 2 + tools/objtool/check.c | 191 -------------------------- tools/objtool/include/objtool/check.h | 74 +--------- tools/objtool/include/objtool/insn.h | 121 ++++++++++++++++ tools/objtool/insn.c | 177 ++++++++++++++++++++++++ 5 files changed, 301 insertions(+), 264 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 695cfee5cfde..52ed2f710d2a 100644 --- a/tools/objtool/Build +++ b/tools/objtool/Build @@ -4,9 +4,11 @@ objtool-y +=3D weak.o =20 objtool-$(SUBCMD_CHECK) +=3D check.o objtool-$(SUBCMD_CHECK) +=3D cfi.o +objtool-$(SUBCMD_CHECK) +=3D insn.o objtool-$(SUBCMD_CHECK) +=3D special.o objtool-$(SUBCMD_ORC) +=3D check.o objtool-$(SUBCMD_ORC) +=3D cfi.o +objtool-$(SUBCMD_ORC) +=3D insn.o objtool-$(SUBCMD_ORC) +=3D orc_gen.o objtool-$(SUBCMD_ORC) +=3D orc_dump.o =20 diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 12acc9d329de..78168e0ad2bf 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -27,86 +27,6 @@ struct alternative { bool skip_orig; }; =20 -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 =3D=3D sec && insn->offset =3D=3D offset) - return insn; - } - - return NULL; -} - -static struct instruction *next_insn_same_sec(struct objtool_file *file, - struct instruction *insn) -{ - struct instruction *next =3D list_next_entry(insn, list); - - if (!next || &next->list =3D=3D &file->insn_list || next->sec !=3D insn->= sec) - return NULL; - - return next; -} - -static struct instruction *next_insn_same_func(struct objtool_file *file, - struct instruction *insn) -{ - struct instruction *next =3D list_next_entry(insn, list); - struct symbol *func =3D insn->func; - - if (!func) - return NULL; - - if (&next->list !=3D &file->insn_list && next->func =3D=3D func) - return next; - - /* Check if we're already in the subfunction: */ - if (func =3D=3D func->cfunc) - return NULL; - - /* Move to the subfunction: */ - return find_insn(file, func->cfunc->sec, func->cfunc->offset); -} - -static struct instruction *prev_insn_same_sym(struct objtool_file *file, - struct instruction *insn) -{ - struct instruction *prev =3D list_prev_entry(insn, list); - - if (&prev->list !=3D &file->insn_list && prev->func =3D=3D insn->func) - return prev; - - return NULL; -} - -#define func_for_each_insn(file, func, insn) \ - for (insn =3D find_insn(file, func->sec, func->offset); \ - insn; \ - insn =3D next_insn_same_func(file, insn)) - -#define sym_for_each_insn(file, sym, insn) \ - for (insn =3D find_insn(file, sym->sec, sym->offset); \ - insn && &insn->list !=3D &file->insn_list && \ - insn->sec =3D=3D sym->sec && \ - insn->offset < sym->offset + sym->len; \ - insn =3D list_next_entry(insn, list)) - -#define sym_for_each_insn_continue_reverse(file, sym, insn) \ - for (insn =3D list_prev_entry(insn, list); \ - &insn->list !=3D &file->insn_list && \ - insn->sec =3D=3D sym->sec && insn->offset >=3D sym->offset; \ - insn =3D list_prev_entry(insn, list)) - -#define sec_for_each_insn_from(file, insn) \ - for (; insn; insn =3D next_insn_same_sec(file, insn)) - -#define sec_for_each_insn_continue(file, insn) \ - for (insn =3D next_insn_same_sec(file, insn); insn; \ - insn =3D next_insn_same_sec(file, insn)) - static bool is_jump_table_jump(struct instruction *insn) { struct alt_group *alt_group =3D insn->alt_group; @@ -243,20 +163,6 @@ static bool dead_end_function(struct objtool_file *fil= e, struct symbol *func) return __dead_end_function(file, func, 0); } =20 -static void init_insn_state(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->sec (external symbols do - * not have a section). - */ - if (vmlinux && noinstr && sec) - state->noinstr =3D sec->noinstr; -} - static unsigned long nr_insns; static unsigned long nr_insns_visited; =20 @@ -431,19 +337,6 @@ static int init_pv_ops(struct objtool_file *file) return 0; } =20 -static struct instruction *find_last_insn(struct objtool_file *file, - struct section *sec) -{ - struct instruction *insn =3D NULL; - unsigned int offset; - unsigned int end =3D (sec->sh.sh_size > 10) ? sec->sh.sh_size - 10 : 0; - - for (offset =3D sec->sh.sh_size - 1; offset >=3D end && !insn; offset--) - insn =3D find_insn(file, sec, offset); - - return insn; -} - /* * Mark "ud2" instructions and manually annotated dead ends. */ @@ -990,28 +883,6 @@ __weak bool arch_is_retpoline(struct symbol *sym) return false; } =20 -#define NEGATIVE_RELOC ((void *)-1L) - -static struct reloc *insn_reloc(struct objtool_file *file, struct instruct= ion *insn) -{ - if (insn->reloc =3D=3D NEGATIVE_RELOC) - return NULL; - - if (!insn->reloc) { - if (!file) - return NULL; - - insn->reloc =3D find_reloc_by_dest_range(file->elf, insn->sec, - insn->offset, insn->len); - if (!insn->reloc) { - insn->reloc =3D NEGATIVE_RELOC; - return NULL; - } - } - - return insn->reloc; -} - static void remove_insn_ops(struct instruction *insn) { struct stack_op *op, *tmp; @@ -1146,18 +1017,6 @@ static void add_retpoline_call(struct objtool_file *= file, struct instruction *in annotate_call_site(file, insn, false); } =20 -static bool same_function(struct instruction *insn1, struct instruction *i= nsn2) -{ - return insn1->func->pfunc =3D=3D insn2->func->pfunc; -} - -static bool is_first_func_insn(struct instruction *insn) -{ - return insn->offset =3D=3D insn->func->offset || - (insn->type =3D=3D INSN_ENDBR && - insn->offset =3D=3D insn->func->offset + insn->len); -} - /* * Find the destination instructions for all jumps. */ @@ -2826,56 +2685,6 @@ static int handle_insn_ops(struct instruction *insn, return 0; } =20 -static bool insn_cfi_match(struct instruction *insn, struct cfi_state *cfi= 2) -{ - struct cfi_state *cfi1 =3D 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=3D%d%+d cfa2=3D%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 =3D 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]=3D%d%+d reg2[%d]=3D%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 !=3D cfi2->type) { - - WARN_FUNC("stack state mismatch: type1=3D%d type2=3D%d", - insn->sec, insn->offset, cfi1->type, cfi2->type); - - } else if (cfi1->drap !=3D cfi2->drap || - (cfi1->drap && cfi1->drap_reg !=3D cfi2->drap_reg) || - (cfi1->drap && cfi1->drap_offset !=3D cfi2->drap_offset)) { - - WARN_FUNC("stack state mismatch: drap1=3D%d(%d,%d) drap2=3D%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 f10d7374f388..7c9d55319986 100644 --- a/tools/objtool/include/objtool/check.h +++ b/tools/objtool/include/objtool/check.h @@ -7,17 +7,7 @@ #define _CHECK_H =20 #include -#include -#include - -struct insn_state { - struct cfi_state cfi; - unsigned int uaccess_stack; - bool uaccess; - bool df; - bool noinstr; - s8 instr; -}; +#include =20 struct alt_group { /* @@ -36,66 +26,4 @@ struct alt_group { struct cfi_state **cfi; }; =20 -struct instruction { - struct list_head list; - struct hlist_node hash; - struct list_head call_node; - struct section *sec; - unsigned long offset; - unsigned int len; - enum insn_type type; - unsigned long immediate; - - u8 dead_end : 1, - ignore : 1, - ignore_alts : 1, - hint : 1, - retpoline_safe : 1, - noendbr : 1; - /* 2 bit hole */ - s8 instr; - u8 visited; - /* u8 hole */ - - struct alt_group *alt_group; - struct symbol *call_dest; - struct instruction *jump_dest; - struct instruction *first_jump_src; - struct reloc *jump_table; - struct reloc *reloc; - struct list_head alts; - struct symbol *func; - struct list_head stack_ops; - struct cfi_state *cfi; -}; - -static inline bool is_static_jump(struct instruction *insn) -{ - return insn->type =3D=3D INSN_JUMP_CONDITIONAL || - insn->type =3D=3D INSN_JUMP_UNCONDITIONAL; -} - -static inline bool is_dynamic_jump(struct instruction *insn) -{ - return insn->type =3D=3D INSN_JUMP_DYNAMIC || - insn->type =3D=3D 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); - -#define for_each_insn(file, insn) \ - list_for_each_entry(insn, &file->insn_list, list) - -#define sec_for_each_insn(file, sec, insn) \ - for (insn =3D find_insn(file, sec, 0); \ - insn && &insn->list !=3D &file->insn_list && \ - insn->sec =3D=3D sec; \ - insn =3D list_next_entry(insn, list)) - #endif /* _CHECK_H */ diff --git a/tools/objtool/include/objtool/insn.h b/tools/objtool/include/o= bjtool/insn.h new file mode 100644 index 000000000000..1b9fce586679 --- /dev/null +++ b/tools/objtool/include/objtool/insn.h @@ -0,0 +1,121 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2017 Josh Poimboeuf + */ + +#ifndef _INSN_H +#define _INSN_H + +#include +#include + +struct insn_state { + struct cfi_state cfi; + unsigned int uaccess_stack; + bool uaccess; + bool df; + bool noinstr; + s8 instr; +}; + +struct instruction { + struct list_head list; + struct hlist_node hash; + struct list_head call_node; + struct section *sec; + unsigned long offset; + unsigned int len; + enum insn_type type; + unsigned long immediate; + + u8 dead_end : 1, + ignore : 1, + ignore_alts : 1, + hint : 1, + retpoline_safe : 1, + noendbr : 1; + /* 2 bit hole */ + s8 instr; + u8 visited; + /* u8 hole */ + + struct alt_group *alt_group; + struct symbol *call_dest; + struct instruction *jump_dest; + struct instruction *first_jump_src; + struct reloc *jump_table; + struct reloc *reloc; + struct list_head alts; + struct symbol *func; + struct list_head stack_ops; + struct cfi_state *cfi; +}; + +static inline bool is_static_jump(struct instruction *insn) +{ + return insn->type =3D=3D INSN_JUMP_CONDITIONAL || + insn->type =3D=3D INSN_JUMP_UNCONDITIONAL; +} + +static inline bool is_dynamic_jump(struct instruction *insn) +{ + return insn->type =3D=3D INSN_JUMP_DYNAMIC || + insn->type =3D=3D INSN_JUMP_DYNAMIC_CONDITIONAL; +} + +static inline bool is_jump(struct instruction *insn) +{ + return is_static_jump(insn) || is_dynamic_jump(insn); +} + +void init_insn_state(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_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 *in= sn); +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 instruction *insn); + +#define for_each_insn(file, insn) \ + list_for_each_entry(insn, &file->insn_list, list) + +#define sec_for_each_insn(file, sec, insn) \ + for (insn =3D find_insn(file, sec, 0); \ + insn && &insn->list !=3D &file->insn_list && \ + insn->sec =3D=3D sec; \ + insn =3D list_next_entry(insn, list)) + +#define func_for_each_insn(file, func, insn) \ + for (insn =3D find_insn(file, func->sec, func->offset); \ + insn; \ + insn =3D next_insn_same_func(file, insn)) + +#define sym_for_each_insn(file, sym, insn) \ + for (insn =3D find_insn(file, sym->sec, sym->offset); \ + insn && &insn->list !=3D &file->insn_list && \ + insn->sec =3D=3D sym->sec && \ + insn->offset < sym->offset + sym->len; \ + insn =3D list_next_entry(insn, list)) + +#define sym_for_each_insn_continue_reverse(file, sym, insn) \ + for (insn =3D list_prev_entry(insn, list); \ + &insn->list !=3D &file->insn_list && \ + insn->sec =3D=3D sym->sec && insn->offset >=3D sym->offset; \ + insn =3D list_prev_entry(insn, list)) + +#define sec_for_each_insn_from(file, insn) \ + for (; insn; insn =3D next_insn_same_sec(file, insn)) + +#define sec_for_each_insn_continue(file, insn) \ + for (insn =3D next_insn_same_sec(file, insn); insn; \ + insn =3D 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..669fca9b8e0d --- /dev/null +++ b/tools/objtool/insn.c @@ -0,0 +1,177 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2015-2017 Josh Poimboeuf + */ + +#include + +#include +#include +#include + +struct instruction *find_insn(struct objtool_file *file, + struct section *sec, unsigned long offset) +{ + struct instruction *insn; + + offset -=3D sec->sh.sh_addr; + hash_for_each_possible(file->insn_hash, insn, hash, sec_offset_hash(sec, = offset)) { + if (insn->sec =3D=3D sec && insn->offset =3D=3D offset) + return insn; + } + + return NULL; +} + +struct instruction *next_insn_same_sec(struct objtool_file *file, + struct instruction *insn) +{ + struct instruction *next =3D list_next_entry(insn, list); + + if (!next || &next->list =3D=3D &file->insn_list || next->sec !=3D insn->= sec) + return NULL; + + return next; +} + +struct instruction *next_insn_same_func(struct objtool_file *file, + struct instruction *insn) +{ + struct instruction *next =3D list_next_entry(insn, list); + struct symbol *func =3D insn->func; + + if (!func) + return NULL; + + if (&next->list !=3D &file->insn_list && next->func =3D=3D func) + return next; + + /* Check if we're already in the subfunction: */ + if (func =3D=3D func->cfunc) + return NULL; + + /* Move to the subfunction: */ + return find_insn(file, func->cfunc->sec, func->cfunc->offset); +} + +struct instruction *prev_insn_same_sym(struct objtool_file *file, + struct instruction *insn) +{ + struct instruction *prev =3D list_prev_entry(insn, list); + + if (&prev->list !=3D &file->insn_list && prev->func =3D=3D insn->func) + return prev; + + return NULL; +} + +struct instruction *find_last_insn(struct objtool_file *file, + struct section *sec) +{ + struct instruction *insn =3D NULL; + unsigned int offset; + unsigned int end =3D (sec->sh.sh_size > 10) ? sec->sh.sh_size - 10 : 0; + + for (offset =3D sec->sh.sh_size - 1; offset >=3D end && !insn; offset--) + insn =3D find_insn(file, sec, offset); + + return insn; +} + +bool same_function(struct instruction *insn1, struct instruction *insn2) +{ + return insn1->func->pfunc =3D=3D insn2->func->pfunc; +} + +bool is_first_func_insn(struct instruction *insn) +{ + return insn->offset =3D=3D insn->func->offset || + (insn->type =3D=3D INSN_ENDBR && + insn->offset =3D=3D insn->func->offset + insn->len); +} + +bool insn_cfi_match(struct instruction *insn, struct cfi_state *cfi2) +{ + struct cfi_state *cfi1 =3D 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=3D%d%+d cfa2=3D%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 =3D 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]=3D%d%+d reg2[%d]=3D%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 !=3D cfi2->type) { + + WARN_FUNC("stack state mismatch: type1=3D%d type2=3D%d", + insn->sec, insn->offset, cfi1->type, cfi2->type); + + } else if (cfi1->drap !=3D cfi2->drap || + (cfi1->drap && cfi1->drap_reg !=3D cfi2->drap_reg) || + (cfi1->drap && cfi1->drap_offset !=3D cfi2->drap_offset)) { + + WARN_FUNC("stack state mismatch: drap1=3D%d(%d,%d) drap2=3D%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; +} + +void init_insn_state(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->sec (external symbols do + * not have a section). + */ + if (vmlinux && noinstr && sec) + state->noinstr =3D sec->noinstr; +} + +#define NEGATIVE_RELOC ((void *)-1L) + +struct reloc *insn_reloc(struct objtool_file *file, struct instruction *in= sn) +{ + if (insn->reloc =3D=3D NEGATIVE_RELOC) + return NULL; + + if (!insn->reloc) { + if (!file) + return NULL; + + insn->reloc =3D find_reloc_by_dest_range(file->elf, insn->sec, + insn->offset, insn->len); + if (!insn->reloc) { + insn->reloc =3D NEGATIVE_RELOC; + return NULL; + } + } + + return insn->reloc; +} --=20 2.25.1 From nobody Tue Apr 23 06:20:23 2024 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 40087C433EF for ; Tue, 24 May 2022 00:16:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231682AbiEXAQz (ORCPT ); Mon, 23 May 2022 20:16:55 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58254 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231405AbiEXAQw (ORCPT ); Mon, 23 May 2022 20:16:52 -0400 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 7D11B6CF4E; Mon, 23 May 2022 17:16:50 -0700 (PDT) Received: from x64host.home (unknown [47.189.24.195]) by linux.microsoft.com (Postfix) with ESMTPSA id 7A49E20B87F6; Mon, 23 May 2022 17:16:49 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 7A49E20B87F6 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1653351410; bh=PrjM6sNWCbaOpnfA+c2bSGMaKIm9RjxL72wTSFxI6qc=; h=From:To:Subject:Date:In-Reply-To:References:From; b=N5oJapbEd2k+mIf2MT3PqvMssXV2Hg5mEIlndw3toTXfRJIqSFIq8DFKNsEdXLRmA NaQd7x4nC43KjAcSSYr3lhrX4iSOmcQkNxWsaxLDP4octNv5y2mcSSXufmzLw6RNdl RaK+pdtWBUqFBdG54tIPJpI5LN0kSv1iiGTwfFAM= From: madvenka@linux.microsoft.com To: jpoimboe@redhat.com, peterz@infradead.org, chenzhongjin@huawei.com, mark.rutland@arm.com, broonie@kernel.org, nobuta.keiya@fujitsu.com, sjitindarsingh@gmail.com, catalin.marinas@arm.com, will@kernel.org, jamorris@linux.microsoft.com, linux-arm-kernel@lists.infradead.org, live-patching@vger.kernel.org, linux-kernel@vger.kernel.org, madvenka@linux.microsoft.com Subject: [RFC PATCH v2 03/20] objtool: Move decode_instructions() to a separate file Date: Mon, 23 May 2022 19:16:20 -0500 Message-Id: <20220524001637.1707472-4-madvenka@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220524001637.1707472-1-madvenka@linux.microsoft.com> References: <20220524001637.1707472-1-madvenka@linux.microsoft.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: "Madhavan T. Venkataraman" 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 --- tools/objtool/Build | 2 + tools/objtool/check.c | 96 ------------------------ tools/objtool/decode.c | 106 +++++++++++++++++++++++++++ tools/objtool/include/objtool/insn.h | 1 + 4 files changed, 109 insertions(+), 96 deletions(-) create mode 100644 tools/objtool/decode.c diff --git a/tools/objtool/Build b/tools/objtool/Build index 52ed2f710d2a..199561f86c1e 100644 --- a/tools/objtool/Build +++ b/tools/objtool/Build @@ -5,10 +5,12 @@ objtool-y +=3D weak.o objtool-$(SUBCMD_CHECK) +=3D check.o objtool-$(SUBCMD_CHECK) +=3D cfi.o objtool-$(SUBCMD_CHECK) +=3D insn.o +objtool-$(SUBCMD_CHECK) +=3D decode.o objtool-$(SUBCMD_CHECK) +=3D special.o objtool-$(SUBCMD_ORC) +=3D check.o objtool-$(SUBCMD_ORC) +=3D cfi.o objtool-$(SUBCMD_ORC) +=3D insn.o +objtool-$(SUBCMD_ORC) +=3D decode.o objtool-$(SUBCMD_ORC) +=3D orc_gen.o objtool-$(SUBCMD_ORC) +=3D orc_dump.o =20 diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 78168e0ad2bf..334ddc737bf9 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -163,104 +163,8 @@ static bool dead_end_function(struct objtool_file *fi= le, struct symbol *func) return __dead_end_function(file, func, 0); } =20 -static unsigned long nr_insns; static unsigned long nr_insns_visited; =20 -/* - * 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) { - - 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 =3D true; - - if (!strcmp(sec->name, ".noinstr.text") || - !strcmp(sec->name, ".entry.text")) - sec->noinstr =3D true; - - for (offset =3D 0; offset < sec->sh.sh_size; offset +=3D insn->len) { - insn =3D malloc(sizeof(*insn)); - if (!insn) { - WARN("malloc failed"); - return -1; - } - memset(insn, 0, sizeof(*insn)); - INIT_LIST_HEAD(&insn->alts); - INIT_LIST_HEAD(&insn->stack_ops); - INIT_LIST_HEAD(&insn->call_node); - - insn->sec =3D sec; - insn->offset =3D offset; - - ret =3D arch_decode_instruction(file, sec, offset, - sec->sh.sh_size - offset, - &insn->len, &insn->type, - &insn->immediate, - &insn->stack_ops); - if (ret) - goto err; - - /* - * By default, "ud2" is a dead end unless otherwise - * annotated, because GCC 7 inserts it for certain - * divide-by-zero cases. - */ - if (insn->type =3D=3D INSN_BUG) - insn->dead_end =3D true; - - hash_add(file->insn_hash, &insn->hash, sec_offset_hash(sec, insn->offse= t)); - list_add_tail(&insn->list, &file->insn_list); - nr_insns++; - } - - list_for_each_entry(func, &sec->symbol_list, list) { - if (func->type !=3D STT_FUNC || func->alias !=3D 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->func =3D func; - if (insn->type =3D=3D INSN_ENDBR && list_empty(&insn->call_node)) { - if (insn->offset =3D=3D insn->func->offset) { - list_add_tail(&insn->call_node, &file->endbr_list); - file->nr_endbr++; - } else { - file->nr_endbr_int++; - } - } - } - } - } - - if (stats) - printf("nr_insns: %lu\n", nr_insns); - - return 0; - -err: - free(insn); - return ret; -} - /* * 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..4ed438ccc07f --- /dev/null +++ b/tools/objtool/decode.c @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2015-2017 Josh Poimboeuf + */ +#include + +#include +#include +#include + +static unsigned long nr_insns; + +/* + * 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) { + + 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 =3D true; + + if (!strcmp(sec->name, ".noinstr.text") || + !strcmp(sec->name, ".entry.text")) + sec->noinstr =3D true; + + for (offset =3D 0; offset < sec->sh.sh_size; offset +=3D insn->len) { + insn =3D malloc(sizeof(*insn)); + if (!insn) { + WARN("malloc failed"); + return -1; + } + memset(insn, 0, sizeof(*insn)); + INIT_LIST_HEAD(&insn->alts); + INIT_LIST_HEAD(&insn->stack_ops); + INIT_LIST_HEAD(&insn->call_node); + + insn->sec =3D sec; + insn->offset =3D offset; + + ret =3D arch_decode_instruction(file, sec, offset, + sec->sh.sh_size - offset, + &insn->len, &insn->type, + &insn->immediate, + &insn->stack_ops); + if (ret) + goto err; + + /* + * By default, "ud2" is a dead end unless otherwise + * annotated, because GCC 7 inserts it for certain + * divide-by-zero cases. + */ + if (insn->type =3D=3D INSN_BUG) + insn->dead_end =3D true; + + hash_add(file->insn_hash, &insn->hash, sec_offset_hash(sec, insn->offse= t)); + list_add_tail(&insn->list, &file->insn_list); + nr_insns++; + } + + list_for_each_entry(func, &sec->symbol_list, list) { + if (func->type !=3D STT_FUNC || func->alias !=3D 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->func =3D func; + if (insn->type =3D=3D INSN_ENDBR && list_empty(&insn->call_node)) { + if (insn->offset =3D=3D insn->func->offset) { + list_add_tail(&insn->call_node, &file->endbr_list); + file->nr_endbr++; + } else { + file->nr_endbr_int++; + } + } + } + } + } + + if (stats) + printf("nr_insns: %lu\n", nr_insns); + + return 0; + +err: + free(insn); + return ret; +} diff --git a/tools/objtool/include/objtool/insn.h b/tools/objtool/include/o= bjtool/insn.h index 1b9fce586679..5f01fd0ce8ed 100644 --- a/tools/objtool/include/objtool/insn.h +++ b/tools/objtool/include/objtool/insn.h @@ -83,6 +83,7 @@ struct reloc *insn_reloc(struct objtool_file *file, struc= t 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 instruction *insn); +int decode_instructions(struct objtool_file *file); =20 #define for_each_insn(file, insn) \ list_for_each_entry(insn, &file->insn_list, list) --=20 2.25.1 From nobody Tue Apr 23 06:20:23 2024 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 718ECC433EF for ; Tue, 24 May 2022 00:17:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231656AbiEXARJ (ORCPT ); Mon, 23 May 2022 20:17:09 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58382 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231549AbiEXAQx (ORCPT ); Mon, 23 May 2022 20:16:53 -0400 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 840EB6D1BA; Mon, 23 May 2022 17:16:51 -0700 (PDT) Received: from x64host.home (unknown [47.189.24.195]) by linux.microsoft.com (Postfix) with ESMTPSA id 7D5EE20B894E; Mon, 23 May 2022 17:16:50 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 7D5EE20B894E DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1653351411; bh=6K1f7gtO5pFA0H990GU3QXDIIsrQWqqHKexvfsHsLu0=; h=From:To:Subject:Date:In-Reply-To:References:From; b=cmMTbX/hfEn/x/ZGQ9MMZljReSKrjJ818UryE5soz/YdfwGh6TLFrR4rHbMvBK9jm qU51OEWFkkzObIOVdn/5NFm6gA72u0Bj3cAAkZf5SdPUDrRaGJ07Gi5km65MSyJnqN UmW+9JWMD+vqfwgDzYoE6Jnms5RRU6htOiRCUiMA= From: madvenka@linux.microsoft.com To: jpoimboe@redhat.com, peterz@infradead.org, chenzhongjin@huawei.com, mark.rutland@arm.com, broonie@kernel.org, nobuta.keiya@fujitsu.com, sjitindarsingh@gmail.com, catalin.marinas@arm.com, will@kernel.org, jamorris@linux.microsoft.com, linux-arm-kernel@lists.infradead.org, live-patching@vger.kernel.org, linux-kernel@vger.kernel.org, madvenka@linux.microsoft.com Subject: [RFC PATCH v2 04/20] objtool: Reorganize Unwind hint code Date: Mon, 23 May 2022 19:16:21 -0500 Message-Id: <20220524001637.1707472-5-madvenka@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220524001637.1707472-1-madvenka@linux.microsoft.com> References: <20220524001637.1707472-1-madvenka@linux.microsoft.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: "Madhavan T. Venkataraman" 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 --- arch/x86/include/asm/unwind_hints.h | 85 +++++++++++++ arch/x86/kernel/unwind_orc.c | 2 +- include/linux/objtool.h | 67 ---------- tools/arch/x86/include/asm/unwind_hints.h | 147 ++++++++++++++++++++++ tools/include/linux/objtool.h | 67 ---------- tools/objtool/Build | 2 + tools/objtool/check.c | 77 ------------ tools/objtool/include/objtool/insn.h | 1 + tools/objtool/sync-check.sh | 1 + tools/objtool/unwind_hints.c | 87 +++++++++++++ 10 files changed, 324 insertions(+), 212 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/unw= ind_hints.h index 8b33674288ea..d5a33561a64e 100644 --- a/arch/x86/include/asm/unwind_hints.h +++ b/arch/x86/include/asm/unwind_hints.h @@ -1,10 +1,95 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ #ifndef _ASM_X86_UNWIND_HINTS_H #define _ASM_X86_UNWIND_HINTS_H =20 +#ifndef __ASSEMBLY__ + +#include + +/* + * 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 end; +}; +#endif + #include =20 #include "orc_types.h" =20 +#ifdef CONFIG_STACK_VALIDATION + +#ifndef __ASSEMBLY__ + +#define UNWIND_HINT(sp_reg, sp_offset, type, 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(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 a= nd + * the rest. The normal callable functions can be called by other code, a= nd + * don't do anything unusual with the stack. Such normal callable functio= ns + * are annotated with the ENTRY/ENDPROC macros. Most asm code falls in th= is + * category. In this case, no special debugging annotations are needed be= cause + * 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 e= ach + * 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 sp_reg:req sp_offset=3D0 type:req end=3D0 +.Lunwind_hint_ip_\@: + .pushsection .discard.unwind_hints + /* struct unwind_hint */ + .long .Lunwind_hint_ip_\@ - . + .short \sp_offset + .byte \sp_reg + .byte \type + .byte \end + .balign 4 + .popsection +.endm + +#endif /* __ASSEMBLY__ */ + +#else /* !CONFIG_STACK_VALIDATION */ + +#ifndef __ASSEMBLY__ + +#define UNWIND_HINT(sp_reg, sp_offset, type, end) \ + "\n\t" +#else +.macro UNWIND_HINT sp_reg:req sp_offset=3D0 type:req end=3D0 +.endm +#endif + +#endif /* CONFIG_STACK_VALIDATION */ + #ifdef __ASSEMBLY__ =20 .macro UNWIND_HINT_EMPTY diff --git a/arch/x86/kernel/unwind_orc.c b/arch/x86/kernel/unwind_orc.c index 794fdef2501a..7cae5bfa56c7 100644 --- a/arch/x86/kernel/unwind_orc.c +++ b/arch/x86/kernel/unwind_orc.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -#include +#include #include #include #include diff --git a/include/linux/objtool.h b/include/linux/objtool.h index 586d35720f13..00bb449777d0 100644 --- a/include/linux/objtool.h +++ b/include/linux/objtool.h @@ -2,23 +2,6 @@ #ifndef _LINUX_OBJTOOL_H #define _LINUX_OBJTOOL_H =20 -#ifndef __ASSEMBLY__ - -#include - -/* - * 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 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 @@ -42,18 +25,6 @@ struct unwind_hint { =20 #ifndef __ASSEMBLY__ =20 -#define UNWIND_HINT(sp_reg, sp_offset, type, 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(end) "\n\t" \ - ".balign 4 \n\t" \ - ".popsection\n\t" - /* * This macro marks the given function's stack frame as "non-standard", wh= ich * tells objtool to ignore the function when doing stack metadata validati= on. @@ -101,40 +72,6 @@ struct unwind_hint { .long 999b; \ .popsection; =20 -/* - * In asm, there are two kinds of code: normal C-type callable functions a= nd - * the rest. The normal callable functions can be called by other code, a= nd - * don't do anything unusual with the stack. Such normal callable functio= ns - * are annotated with the ENTRY/ENDPROC macros. Most asm code falls in th= is - * category. In this case, no special debugging annotations are needed be= cause - * 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 e= ach - * 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 sp_reg:req sp_offset=3D0 type:req end=3D0 -.Lunwind_hint_ip_\@: - .pushsection .discard.unwind_hints - /* struct unwind_hint */ - .long .Lunwind_hint_ip_\@ - . - .short \sp_offset - .byte \sp_reg - .byte \type - .byte \end - .balign 4 - .popsection -.endm - .macro STACK_FRAME_NON_STANDARD func:req .pushsection .discard.func_stack_frame_non_standard, "aw" .long \func - . @@ -161,16 +98,12 @@ struct unwind_hint { =20 #ifndef __ASSEMBLY__ =20 -#define UNWIND_HINT(sp_reg, sp_offset, type, 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 sp_reg:req sp_offset=3D0 type:req end=3D0 -.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/inc= lude/asm/unwind_hints.h new file mode 100644 index 000000000000..d5a33561a64e --- /dev/null +++ b/tools/arch/x86/include/asm/unwind_hints.h @@ -0,0 +1,147 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef _ASM_X86_UNWIND_HINTS_H +#define _ASM_X86_UNWIND_HINTS_H + +#ifndef __ASSEMBLY__ + +#include + +/* + * 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 end; +}; +#endif + +#include + +#include "orc_types.h" + +#ifdef CONFIG_STACK_VALIDATION + +#ifndef __ASSEMBLY__ + +#define UNWIND_HINT(sp_reg, sp_offset, type, 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(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 a= nd + * the rest. The normal callable functions can be called by other code, a= nd + * don't do anything unusual with the stack. Such normal callable functio= ns + * are annotated with the ENTRY/ENDPROC macros. Most asm code falls in th= is + * category. In this case, no special debugging annotations are needed be= cause + * 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 e= ach + * 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 sp_reg:req sp_offset=3D0 type:req end=3D0 +.Lunwind_hint_ip_\@: + .pushsection .discard.unwind_hints + /* struct unwind_hint */ + .long .Lunwind_hint_ip_\@ - . + .short \sp_offset + .byte \sp_reg + .byte \type + .byte \end + .balign 4 + .popsection +.endm + +#endif /* __ASSEMBLY__ */ + +#else /* !CONFIG_STACK_VALIDATION */ + +#ifndef __ASSEMBLY__ + +#define UNWIND_HINT(sp_reg, sp_offset, type, end) \ + "\n\t" +#else +.macro UNWIND_HINT sp_reg:req sp_offset=3D0 type:req end=3D0 +.endm +#endif + +#endif /* CONFIG_STACK_VALIDATION */ + +#ifdef __ASSEMBLY__ + +.macro UNWIND_HINT_EMPTY + UNWIND_HINT sp_reg=3DORC_REG_UNDEFINED type=3DUNWIND_HINT_TYPE_CALL end= =3D1 +.endm + +.macro UNWIND_HINT_REGS base=3D%rsp offset=3D0 indirect=3D0 extra=3D1 part= ial=3D0 + .if \base =3D=3D %rsp + .if \indirect + .set sp_reg, ORC_REG_SP_INDIRECT + .else + .set sp_reg, ORC_REG_SP + .endif + .elseif \base =3D=3D %rbp + .set sp_reg, ORC_REG_BP + .elseif \base =3D=3D %rdi + .set sp_reg, ORC_REG_DI + .elseif \base =3D=3D %rdx + .set sp_reg, ORC_REG_DX + .elseif \base =3D=3D %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 =3D=3D 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=3Dsp_reg sp_offset=3Dsp_offset type=3Dtype +.endm + +.macro UNWIND_HINT_IRET_REGS base=3D%rsp offset=3D0 + UNWIND_HINT_REGS base=3D\base offset=3D\offset partial=3D1 +.endm + +.macro UNWIND_HINT_FUNC + UNWIND_HINT sp_reg=3DORC_REG_SP sp_offset=3D8 type=3DUNWIND_HINT_TYPE_FUNC +.endm + +#else + +#define UNWIND_HINT_FUNC \ + UNWIND_HINT(ORC_REG_SP, 8, UNWIND_HINT_TYPE_FUNC, 0) + +#endif /* __ASSEMBLY__ */ + +#endif /* _ASM_X86_UNWIND_HINTS_H */ diff --git a/tools/include/linux/objtool.h b/tools/include/linux/objtool.h index 586d35720f13..00bb449777d0 100644 --- a/tools/include/linux/objtool.h +++ b/tools/include/linux/objtool.h @@ -2,23 +2,6 @@ #ifndef _LINUX_OBJTOOL_H #define _LINUX_OBJTOOL_H =20 -#ifndef __ASSEMBLY__ - -#include - -/* - * 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 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 @@ -42,18 +25,6 @@ struct unwind_hint { =20 #ifndef __ASSEMBLY__ =20 -#define UNWIND_HINT(sp_reg, sp_offset, type, 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(end) "\n\t" \ - ".balign 4 \n\t" \ - ".popsection\n\t" - /* * This macro marks the given function's stack frame as "non-standard", wh= ich * tells objtool to ignore the function when doing stack metadata validati= on. @@ -101,40 +72,6 @@ struct unwind_hint { .long 999b; \ .popsection; =20 -/* - * In asm, there are two kinds of code: normal C-type callable functions a= nd - * the rest. The normal callable functions can be called by other code, a= nd - * don't do anything unusual with the stack. Such normal callable functio= ns - * are annotated with the ENTRY/ENDPROC macros. Most asm code falls in th= is - * category. In this case, no special debugging annotations are needed be= cause - * 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 e= ach - * 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 sp_reg:req sp_offset=3D0 type:req end=3D0 -.Lunwind_hint_ip_\@: - .pushsection .discard.unwind_hints - /* struct unwind_hint */ - .long .Lunwind_hint_ip_\@ - . - .short \sp_offset - .byte \sp_reg - .byte \type - .byte \end - .balign 4 - .popsection -.endm - .macro STACK_FRAME_NON_STANDARD func:req .pushsection .discard.func_stack_frame_non_standard, "aw" .long \func - . @@ -161,16 +98,12 @@ struct unwind_hint { =20 #ifndef __ASSEMBLY__ =20 -#define UNWIND_HINT(sp_reg, sp_offset, type, 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 sp_reg:req sp_offset=3D0 type:req end=3D0 -.endm .macro STACK_FRAME_NON_STANDARD func:req .endm .macro ANNOTATE_NOENDBR diff --git a/tools/objtool/Build b/tools/objtool/Build index 199561f86c1e..9c2a332f61f3 100644 --- a/tools/objtool/Build +++ b/tools/objtool/Build @@ -6,11 +6,13 @@ objtool-$(SUBCMD_CHECK) +=3D check.o objtool-$(SUBCMD_CHECK) +=3D cfi.o objtool-$(SUBCMD_CHECK) +=3D insn.o objtool-$(SUBCMD_CHECK) +=3D decode.o +objtool-$(SUBCMD_CHECK) +=3D unwind_hints.o objtool-$(SUBCMD_CHECK) +=3D special.o objtool-$(SUBCMD_ORC) +=3D check.o objtool-$(SUBCMD_ORC) +=3D cfi.o objtool-$(SUBCMD_ORC) +=3D insn.o objtool-$(SUBCMD_ORC) +=3D decode.o +objtool-$(SUBCMD_ORC) +=3D unwind_hints.o objtool-$(SUBCMD_ORC) +=3D orc_gen.o objtool-$(SUBCMD_ORC) +=3D orc_dump.o =20 diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 334ddc737bf9..43f3d7819277 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -1541,83 +1541,6 @@ static int add_jump_table_alts(struct objtool_file *= file) return 0; } =20 -static int read_unwind_hints(struct objtool_file *file) -{ - struct cfi_state cfi =3D init_cfi; - struct section *sec, *relocsec; - struct unwind_hint *hint; - struct instruction *insn; - struct reloc *reloc; - int i; - - sec =3D find_section_by_name(file->elf, ".discard.unwind_hints"); - if (!sec) - return 0; - - relocsec =3D 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 =3D true; - - for (i =3D 0; i < sec->sh.sh_size / sizeof(struct unwind_hint); i++) { - hint =3D (struct unwind_hint *)sec->data->d_buf + i; - - reloc =3D 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 =3D find_insn(file, reloc->sym->sec, reloc->addend); - if (!insn) { - WARN("can't find insn for unwind_hints[%d]", i); - return -1; - } - - insn->hint =3D true; - - if (ibt && hint->type =3D=3D UNWIND_HINT_TYPE_REGS_PARTIAL) { - struct symbol *sym =3D find_symbol_by_offset(insn->sec, insn->offset); - - if (sym && sym->bind =3D=3D STB_GLOBAL && - insn->type !=3D INSN_ENDBR && !insn->noendbr) { - WARN_FUNC("UNWIND_HINT_IRET_REGS without ENDBR", - insn->sec, insn->offset); - } - } - - if (hint->type =3D=3D UNWIND_HINT_TYPE_FUNC) { - insn->cfi =3D &func_cfi; - continue; - } - - if (insn->cfi) - cfi =3D *(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 =3D bswap_if_needed(hint->sp_offset); - cfi.type =3D hint->type; - cfi.end =3D hint->end; - - insn->cfi =3D 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/o= bjtool/insn.h index 5f01fd0ce8ed..0b5596f8b12f 100644 --- a/tools/objtool/include/objtool/insn.h +++ b/tools/objtool/include/objtool/insn.h @@ -84,6 +84,7 @@ 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 instruction *insn); int decode_instructions(struct objtool_file *file); +int read_unwind_hints(struct objtool_file *file); =20 #define for_each_insn(file, insn) \ list_for_each_entry(insn, &file->insn_list, list) 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..d4e41c67403b --- /dev/null +++ b/tools/objtool/unwind_hints.c @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2015-2017 Josh Poimboeuf + */ +#include + +#include +#include +#include +#include + +int read_unwind_hints(struct objtool_file *file) +{ + struct cfi_state cfi =3D init_cfi; + struct section *sec, *relocsec; + struct unwind_hint *hint; + struct instruction *insn; + struct reloc *reloc; + int i; + + sec =3D find_section_by_name(file->elf, ".discard.unwind_hints"); + if (!sec) + return 0; + + relocsec =3D 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 =3D true; + + for (i =3D 0; i < sec->sh.sh_size / sizeof(struct unwind_hint); i++) { + hint =3D (struct unwind_hint *)sec->data->d_buf + i; + + reloc =3D 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 =3D find_insn(file, reloc->sym->sec, reloc->addend); + if (!insn) { + WARN("can't find insn for unwind_hints[%d]", i); + return -1; + } + + insn->hint =3D true; + + if (ibt && hint->type =3D=3D UNWIND_HINT_TYPE_REGS_PARTIAL) { + struct symbol *sym =3D find_symbol_by_offset(insn->sec, insn->offset); + + if (sym && sym->bind =3D=3D STB_GLOBAL && + insn->type !=3D INSN_ENDBR && !insn->noendbr) { + WARN_FUNC("UNWIND_HINT_IRET_REGS without ENDBR", + insn->sec, insn->offset); + } + } + + if (hint->type =3D=3D UNWIND_HINT_TYPE_FUNC) { + insn->cfi =3D &func_cfi; + continue; + } + + if (insn->cfi) + cfi =3D *(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 =3D bswap_if_needed(hint->sp_offset); + cfi.type =3D hint->type; + cfi.end =3D hint->end; + + insn->cfi =3D cfi_hash_find_or_add(&cfi); + } + + return 0; +} --=20 2.25.1 From nobody Tue Apr 23 06:20:23 2024 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2DFD4C433EF for ; Tue, 24 May 2022 00:17:27 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232073AbiEXARY (ORCPT ); Mon, 23 May 2022 20:17:24 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58448 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231642AbiEXAQy (ORCPT ); Mon, 23 May 2022 20:16:54 -0400 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 6ECD16D3BD; Mon, 23 May 2022 17:16:52 -0700 (PDT) Received: from x64host.home (unknown [47.189.24.195]) by linux.microsoft.com (Postfix) with ESMTPSA id 7D75F20B8952; Mon, 23 May 2022 17:16:51 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 7D75F20B8952 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1653351412; bh=hqr6+5sz0cEVD673vwUEknaY+FCv/C1YhbsmJe+cR/0=; h=From:To:Subject:Date:In-Reply-To:References:From; b=Tidu8vH+9Sk9BPmnSd6r6Kbv01dR+ZMc57shs+77Gq+m8Nddy+etACMw9hnl6/pbU QZDbPyT4cNEetQyQRPgRMKFw9z0bjkC0zxdLx87y74sGiOmP7Bi9/hBaqLiAW8DAKZ 5NAKXbjelI6neqbPUVHYuzE8w/m8s2dYfvBTvjt8= From: madvenka@linux.microsoft.com To: jpoimboe@redhat.com, peterz@infradead.org, chenzhongjin@huawei.com, mark.rutland@arm.com, broonie@kernel.org, nobuta.keiya@fujitsu.com, sjitindarsingh@gmail.com, catalin.marinas@arm.com, will@kernel.org, jamorris@linux.microsoft.com, linux-arm-kernel@lists.infradead.org, live-patching@vger.kernel.org, linux-kernel@vger.kernel.org, madvenka@linux.microsoft.com Subject: [RFC PATCH v2 05/20] objtool: Reorganize ORC types Date: Mon, 23 May 2022 19:16:22 -0500 Message-Id: <20220524001637.1707472-6-madvenka@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220524001637.1707472-1-madvenka@linux.microsoft.com> References: <20220524001637.1707472-1-madvenka@linux.microsoft.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: "Madhavan T. Venkataraman" The ORC code needs to be reorganized into arch-specific and generic parts so that architectures other than X86 can use the generic parts. orc_types.h contains the following ORC definitions shared between objtool and the kernel: - ORC register definitions which are arch-specific. - orc_entry structure which is generic. Move orc_entry into a new file include/linux/orc_entry.h. Also, the field names bp_reg and bp_offset in struct orc_entry are x86-specific. Change them to fp_reg and fp_offset. FP stands for frame pointer. Currently, the type field in orc_entry is only 2 bits. For other architectures, we will need more. So, expand this to 3 bits. Signed-off-by: Madhavan T. Venkataraman --- arch/x86/include/asm/orc_types.h | 37 +++++------------------- include/linux/orc_entry.h | 39 ++++++++++++++++++++++++++ tools/arch/x86/include/asm/orc_types.h | 37 +++++------------------- tools/include/linux/orc_entry.h | 39 ++++++++++++++++++++++++++ tools/objtool/orc_gen.c | 4 +-- tools/objtool/sync-check.sh | 1 + 6 files changed, 95 insertions(+), 62 deletions(-) create mode 100644 include/linux/orc_entry.h create mode 100644 tools/include/linux/orc_entry.h diff --git a/arch/x86/include/asm/orc_types.h b/arch/x86/include/asm/orc_ty= pes.h index 5a2baf28a1dc..851c9fb9f695 100644 --- a/arch/x86/include/asm/orc_types.h +++ b/arch/x86/include/asm/orc_types.h @@ -8,6 +8,13 @@ =20 #include #include +#include + +/* + * For x86, use the appripriate name for the frame pointer in orc_entry. + */ +#define bp_offset fp_offset +#define bp_reg fp_reg =20 /* * The ORC_REG_* registers are base registers which are used to find other @@ -39,34 +46,4 @@ #define ORC_REG_SP_INDIRECT 9 #define ORC_REG_MAX 15 =20 -#ifndef __ASSEMBLY__ -#include - -/* - * This struct is more or less a vastly simplified version of the DWARF Ca= ll - * Frame Information standard. It contains only the necessary parts of DW= ARF - * CFI, simplified for ease of access by the in-kernel unwinder. It tells= the - * unwinder how to find the previous SP and BP (and sometimes entry regs) = on - * the stack for a given code address. Each instance of the struct corres= ponds - * to one or more code locations. - */ -struct orc_entry { - s16 sp_offset; - s16 bp_offset; -#if defined(__LITTLE_ENDIAN_BITFIELD) - unsigned sp_reg:4; - unsigned bp_reg:4; - unsigned type:2; - unsigned end:1; -#elif defined(__BIG_ENDIAN_BITFIELD) - unsigned bp_reg:4; - unsigned sp_reg:4; - unsigned unused:5; - unsigned end:1; - unsigned type:2; -#endif -} __packed; - -#endif /* __ASSEMBLY__ */ - #endif /* _ORC_TYPES_H */ diff --git a/include/linux/orc_entry.h b/include/linux/orc_entry.h new file mode 100644 index 000000000000..3d49e3b9dabe --- /dev/null +++ b/include/linux/orc_entry.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2017 Josh Poimboeuf + */ + +#ifndef _ORC_ENTRY_H +#define _ORC_ENTRY_H + +#ifndef __ASSEMBLY__ +#include + +/* + * This struct is more or less a vastly simplified version of the DWARF Ca= ll + * Frame Information standard. It contains only the necessary parts of DW= ARF + * CFI, simplified for ease of access by the in-kernel unwinder. It tells= the + * unwinder how to find the previous SP and BP (and sometimes entry regs) = on + * the stack for a given code address. Each instance of the struct corres= ponds + * to one or more code locations. + */ +struct orc_entry { + s16 sp_offset; + s16 fp_offset; +#if defined(__LITTLE_ENDIAN_BITFIELD) + unsigned sp_reg:4; + unsigned fp_reg:4; + unsigned type:3; + unsigned end:1; +#elif defined(__BIG_ENDIAN_BITFIELD) + unsigned fp_reg:4; + unsigned sp_reg:4; + unsigned unused:4; + unsigned end:1; + unsigned type:3; +#endif +} __packed; + +#endif /* __ASSEMBLY__ */ + +#endif /* _ORC_ENTRY_H */ diff --git a/tools/arch/x86/include/asm/orc_types.h b/tools/arch/x86/includ= e/asm/orc_types.h index 5a2baf28a1dc..851c9fb9f695 100644 --- a/tools/arch/x86/include/asm/orc_types.h +++ b/tools/arch/x86/include/asm/orc_types.h @@ -8,6 +8,13 @@ =20 #include #include +#include + +/* + * For x86, use the appripriate name for the frame pointer in orc_entry. + */ +#define bp_offset fp_offset +#define bp_reg fp_reg =20 /* * The ORC_REG_* registers are base registers which are used to find other @@ -39,34 +46,4 @@ #define ORC_REG_SP_INDIRECT 9 #define ORC_REG_MAX 15 =20 -#ifndef __ASSEMBLY__ -#include - -/* - * This struct is more or less a vastly simplified version of the DWARF Ca= ll - * Frame Information standard. It contains only the necessary parts of DW= ARF - * CFI, simplified for ease of access by the in-kernel unwinder. It tells= the - * unwinder how to find the previous SP and BP (and sometimes entry regs) = on - * the stack for a given code address. Each instance of the struct corres= ponds - * to one or more code locations. - */ -struct orc_entry { - s16 sp_offset; - s16 bp_offset; -#if defined(__LITTLE_ENDIAN_BITFIELD) - unsigned sp_reg:4; - unsigned bp_reg:4; - unsigned type:2; - unsigned end:1; -#elif defined(__BIG_ENDIAN_BITFIELD) - unsigned bp_reg:4; - unsigned sp_reg:4; - unsigned unused:5; - unsigned end:1; - unsigned type:2; -#endif -} __packed; - -#endif /* __ASSEMBLY__ */ - #endif /* _ORC_TYPES_H */ diff --git a/tools/include/linux/orc_entry.h b/tools/include/linux/orc_entr= y.h new file mode 100644 index 000000000000..3d49e3b9dabe --- /dev/null +++ b/tools/include/linux/orc_entry.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2017 Josh Poimboeuf + */ + +#ifndef _ORC_ENTRY_H +#define _ORC_ENTRY_H + +#ifndef __ASSEMBLY__ +#include + +/* + * This struct is more or less a vastly simplified version of the DWARF Ca= ll + * Frame Information standard. It contains only the necessary parts of DW= ARF + * CFI, simplified for ease of access by the in-kernel unwinder. It tells= the + * unwinder how to find the previous SP and BP (and sometimes entry regs) = on + * the stack for a given code address. Each instance of the struct corres= ponds + * to one or more code locations. + */ +struct orc_entry { + s16 sp_offset; + s16 fp_offset; +#if defined(__LITTLE_ENDIAN_BITFIELD) + unsigned sp_reg:4; + unsigned fp_reg:4; + unsigned type:3; + unsigned end:1; +#elif defined(__BIG_ENDIAN_BITFIELD) + unsigned fp_reg:4; + unsigned sp_reg:4; + unsigned unused:4; + unsigned end:1; + unsigned type:3; +#endif +} __packed; + +#endif /* __ASSEMBLY__ */ + +#endif /* _ORC_ENTRY_H */ diff --git a/tools/objtool/orc_gen.c b/tools/objtool/orc_gen.c index dd3c64af9db2..68c317daadbf 100644 --- a/tools/objtool/orc_gen.c +++ b/tools/objtool/orc_gen.c @@ -98,7 +98,7 @@ static int write_orc_entry(struct elf *elf, struct sectio= n *orc_sec, orc =3D (struct orc_entry *)orc_sec->data->d_buf + idx; memcpy(orc, o, sizeof(*orc)); orc->sp_offset =3D bswap_if_needed(orc->sp_offset); - orc->bp_offset =3D bswap_if_needed(orc->bp_offset); + orc->fp_offset =3D bswap_if_needed(orc->fp_offset); =20 /* populate reloc for ip */ if (elf_add_reloc_to_insn(elf, ip_sec, idx * sizeof(int), R_X86_64_PC32, @@ -149,7 +149,7 @@ int orc_create(struct objtool_file *file) =20 struct orc_entry null =3D { .sp_reg =3D ORC_REG_UNDEFINED, - .bp_reg =3D ORC_REG_UNDEFINED, + .fp_reg =3D ORC_REG_UNDEFINED, .type =3D UNWIND_HINT_TYPE_CALL, }; =20 diff --git a/tools/objtool/sync-check.sh b/tools/objtool/sync-check.sh index ee49b4e9e72c..ef1acb064605 100755 --- a/tools/objtool/sync-check.sh +++ b/tools/objtool/sync-check.sh @@ -18,6 +18,7 @@ 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 +include/linux/orc_entry.h " =20 SYNC_CHECK_FILES=3D' --=20 2.25.1 From nobody Tue Apr 23 06:20:23 2024 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6D6ADC433FE for ; Tue, 24 May 2022 00:17:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231926AbiEXARN (ORCPT ); Mon, 23 May 2022 20:17:13 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58484 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231644AbiEXAQy (ORCPT ); Mon, 23 May 2022 20:16:54 -0400 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 6E7D86D1BA; Mon, 23 May 2022 17:16:53 -0700 (PDT) Received: from x64host.home (unknown [47.189.24.195]) by linux.microsoft.com (Postfix) with ESMTPSA id 7E30520B8955; Mon, 23 May 2022 17:16:52 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 7E30520B8955 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1653351413; bh=3jHaMbw9ANe8Y9jhqk+TmlvqJI4ymT7GLSNWj4FwVgI=; h=From:To:Subject:Date:In-Reply-To:References:From; b=B5hfm0Bg4yOn5hvyfGUqiTjQulP0otUoToQK59qyKx+VjhEZviaon5HIOhG+g1drc qHW/eI+CyqRg7rLO/bhoa8aWwTdMgKrgs2j/BcB6+u3YLHvjMWfmtPO8VA8bzZZckN o17tg8RmMhCFTLz+INtodvWwua90RdDEtfjDlKdA= From: madvenka@linux.microsoft.com To: jpoimboe@redhat.com, peterz@infradead.org, chenzhongjin@huawei.com, mark.rutland@arm.com, broonie@kernel.org, nobuta.keiya@fujitsu.com, sjitindarsingh@gmail.com, catalin.marinas@arm.com, will@kernel.org, jamorris@linux.microsoft.com, linux-arm-kernel@lists.infradead.org, live-patching@vger.kernel.org, linux-kernel@vger.kernel.org, madvenka@linux.microsoft.com Subject: [RFC PATCH v2 06/20] objtool: Reorganize ORC code Date: Mon, 23 May 2022 19:16:23 -0500 Message-Id: <20220524001637.1707472-7-madvenka@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220524001637.1707472-1-madvenka@linux.microsoft.com> References: <20220524001637.1707472-1-madvenka@linux.microsoft.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: "Madhavan T. Venkataraman" The ORC code needs to be reorganized into arch-specific and generic parts so that architectures other than X86 can avail the generic parts. Some arch-specific ORC code is present in orc_gen.c and orc_dump.c. Create the following two files for such code: - tools/objtool/include/objtool/orc.h - tools/objtool/arch/x86/orc.c Move the following arch-specific function from tools/objtool/orc_gen.c to tools/objtool/arch/x86/orc.c: - init_orc_entry() Move the following arch-specific functions from tools/objtool/orc_dump.c to tools/objtool/arch/x86/orc.c: - reg_name() - orc_type_name() - print_reg() Create arch-specific functions to print the names of the SP and FP registers. The relocation type for relocation entries for ORC structures is arch-specific. Define it in tools/objtool/arch/x86/include/arch/elf.h: #define R_PCREL R_X86_64_PC32 and use that in orc_gen.c so each architecture can provide its own relocation type. Signed-off-by: Madhavan T. Venkataraman --- tools/objtool/arch/x86/Build | 1 + tools/objtool/arch/x86/include/arch/elf.h | 1 + tools/objtool/arch/x86/orc.c | 150 ++++++++++++++++++++++ tools/objtool/include/objtool/orc.h | 18 +++ tools/objtool/orc_dump.c | 63 +-------- tools/objtool/orc_gen.c | 79 +----------- 6 files changed, 179 insertions(+), 133 deletions(-) create mode 100644 tools/objtool/arch/x86/orc.c create mode 100644 tools/objtool/include/objtool/orc.h diff --git a/tools/objtool/arch/x86/Build b/tools/objtool/arch/x86/Build index 9f7869b5c5e0..add541dbb3e3 100644 --- a/tools/objtool/arch/x86/Build +++ b/tools/objtool/arch/x86/Build @@ -1,5 +1,6 @@ objtool-y +=3D special.o objtool-y +=3D decode.o +objtool-$(SUBCMD_ORC) +=3D orc.o =20 inat_tables_script =3D ../arch/x86/tools/gen-insn-attr-x86.awk inat_tables_maps =3D ../arch/x86/lib/x86-opcode-map.txt diff --git a/tools/objtool/arch/x86/include/arch/elf.h b/tools/objtool/arch= /x86/include/arch/elf.h index 69cc4264b28a..3a7eb515dbb9 100644 --- a/tools/objtool/arch/x86/include/arch/elf.h +++ b/tools/objtool/arch/x86/include/arch/elf.h @@ -2,5 +2,6 @@ #define _OBJTOOL_ARCH_ELF =20 #define R_NONE R_X86_64_NONE +#define R_PCREL R_X86_64_PC32 =20 #endif /* _OBJTOOL_ARCH_ELF */ diff --git a/tools/objtool/arch/x86/orc.c b/tools/objtool/arch/x86/orc.c new file mode 100644 index 000000000000..a075737d4503 --- /dev/null +++ b/tools/objtool/arch/x86/orc.c @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2017 Josh Poimboeuf + */ + +#include +#include + +#include + +#include +#include +#include +#include + +int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, + struct instruction *insn) +{ + struct cfi_reg *bp =3D &cfi->regs[CFI_BP]; + + memset(orc, 0, sizeof(*orc)); + + if (!cfi) { + orc->end =3D 0; + orc->sp_reg =3D ORC_REG_UNDEFINED; + return 0; + } + + orc->end =3D cfi->end; + + if (cfi->cfa.base =3D=3D CFI_UNDEFINED) { + orc->sp_reg =3D ORC_REG_UNDEFINED; + return 0; + } + + switch (cfi->cfa.base) { + case CFI_SP: + orc->sp_reg =3D ORC_REG_SP; + break; + case CFI_SP_INDIRECT: + orc->sp_reg =3D ORC_REG_SP_INDIRECT; + break; + case CFI_BP: + orc->sp_reg =3D ORC_REG_BP; + break; + case CFI_BP_INDIRECT: + orc->sp_reg =3D ORC_REG_BP_INDIRECT; + break; + case CFI_R10: + orc->sp_reg =3D ORC_REG_R10; + break; + case CFI_R13: + orc->sp_reg =3D ORC_REG_R13; + break; + case CFI_DI: + orc->sp_reg =3D ORC_REG_DI; + break; + case CFI_DX: + orc->sp_reg =3D ORC_REG_DX; + break; + default: + WARN_FUNC("unknown CFA base reg %d", + insn->sec, insn->offset, cfi->cfa.base); + return -1; + } + + switch (bp->base) { + case CFI_UNDEFINED: + orc->bp_reg =3D ORC_REG_UNDEFINED; + break; + case CFI_CFA: + orc->bp_reg =3D ORC_REG_PREV_SP; + break; + case CFI_BP: + orc->bp_reg =3D ORC_REG_BP; + break; + default: + WARN_FUNC("unknown BP base reg %d", + insn->sec, insn->offset, bp->base); + return -1; + } + + orc->sp_offset =3D cfi->cfa.offset; + orc->bp_offset =3D bp->offset; + orc->type =3D cfi->type; + + return 0; +} + +static const char *reg_name(unsigned int reg) +{ + switch (reg) { + case ORC_REG_PREV_SP: + return "prevsp"; + case ORC_REG_DX: + return "dx"; + case ORC_REG_DI: + return "di"; + case ORC_REG_BP: + return "bp"; + case ORC_REG_SP: + return "sp"; + case ORC_REG_R10: + return "r10"; + case ORC_REG_R13: + return "r13"; + case ORC_REG_BP_INDIRECT: + return "bp(ind)"; + case ORC_REG_SP_INDIRECT: + return "sp(ind)"; + default: + return "?"; + } +} + +const char *orc_type_name(unsigned int type) +{ + switch (type) { + case UNWIND_HINT_TYPE_CALL: + return "call"; + case UNWIND_HINT_TYPE_REGS: + return "regs"; + case UNWIND_HINT_TYPE_REGS_PARTIAL: + return "regs (partial)"; + default: + return "?"; + } +} + +void orc_print_reg(unsigned int reg, int offset) +{ + if (reg =3D=3D ORC_REG_BP_INDIRECT) + printf("(bp%+d)", offset); + else if (reg =3D=3D ORC_REG_SP_INDIRECT) + printf("(sp)%+d", offset); + else if (reg =3D=3D ORC_REG_UNDEFINED) + printf("(und)"); + else + printf("%s%+d", reg_name(reg), offset); +} + +void orc_print_sp(void) +{ + printf(" sp:"); +} + +void orc_print_fp(void) +{ + printf(" bp:"); +} diff --git a/tools/objtool/include/objtool/orc.h b/tools/objtool/include/ob= jtool/orc.h new file mode 100644 index 000000000000..bf141134c56f --- /dev/null +++ b/tools/objtool/include/objtool/orc.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2015-2017 Josh Poimboeuf + */ + +#ifndef _OBJTOOL_ORC_H +#define _OBJTOOL_ORC_H + +#include + +int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, + struct instruction *insn); +const char *orc_type_name(unsigned int type); +void orc_print_reg(unsigned int reg, int offset); +void orc_print_sp(void); +void orc_print_fp(void); + +#endif /* _OBJTOOL_ORC_H */ diff --git a/tools/objtool/orc_dump.c b/tools/objtool/orc_dump.c index f5a8508c42d6..61b39960ab6a 100644 --- a/tools/objtool/orc_dump.c +++ b/tools/objtool/orc_dump.c @@ -5,63 +5,12 @@ =20 #include #include -#include #include +#include +#include #include #include =20 -static const char *reg_name(unsigned int reg) -{ - switch (reg) { - case ORC_REG_PREV_SP: - return "prevsp"; - case ORC_REG_DX: - return "dx"; - case ORC_REG_DI: - return "di"; - case ORC_REG_BP: - return "bp"; - case ORC_REG_SP: - return "sp"; - case ORC_REG_R10: - return "r10"; - case ORC_REG_R13: - return "r13"; - case ORC_REG_BP_INDIRECT: - return "bp(ind)"; - case ORC_REG_SP_INDIRECT: - return "sp(ind)"; - default: - return "?"; - } -} - -static const char *orc_type_name(unsigned int type) -{ - switch (type) { - case UNWIND_HINT_TYPE_CALL: - return "call"; - case UNWIND_HINT_TYPE_REGS: - return "regs"; - case UNWIND_HINT_TYPE_REGS_PARTIAL: - return "regs (partial)"; - default: - return "?"; - } -} - -static void print_reg(unsigned int reg, int offset) -{ - if (reg =3D=3D ORC_REG_BP_INDIRECT) - printf("(bp%+d)", offset); - else if (reg =3D=3D ORC_REG_SP_INDIRECT) - printf("(sp)%+d", offset); - else if (reg =3D=3D ORC_REG_UNDEFINED) - printf("(und)"); - else - printf("%s%+d", reg_name(reg), offset); -} - int orc_dump(const char *_objname) { int fd, nr_entries, i, *orc_ip =3D NULL, orc_size =3D 0; @@ -196,13 +145,13 @@ int orc_dump(const char *_objname) } =20 =20 - printf(" sp:"); + orc_print_sp(); =20 - print_reg(orc[i].sp_reg, bswap_if_needed(orc[i].sp_offset)); + orc_print_reg(orc[i].sp_reg, bswap_if_needed(orc[i].sp_offset)); =20 - printf(" bp:"); + orc_print_fp(); =20 - print_reg(orc[i].bp_reg, bswap_if_needed(orc[i].bp_offset)); + orc_print_reg(orc[i].fp_reg, bswap_if_needed(orc[i].fp_offset)); =20 printf(" type:%s end:%d\n", orc_type_name(orc[i].type), orc[i].end); diff --git a/tools/objtool/orc_gen.c b/tools/objtool/orc_gen.c index 68c317daadbf..ea2e361ff7bc 100644 --- a/tools/objtool/orc_gen.c +++ b/tools/objtool/orc_gen.c @@ -7,86 +7,13 @@ #include =20 #include -#include +#include =20 #include +#include #include #include =20 -static int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, - struct instruction *insn) -{ - struct cfi_reg *bp =3D &cfi->regs[CFI_BP]; - - memset(orc, 0, sizeof(*orc)); - - if (!cfi) { - orc->end =3D 0; - orc->sp_reg =3D ORC_REG_UNDEFINED; - return 0; - } - - orc->end =3D cfi->end; - - if (cfi->cfa.base =3D=3D CFI_UNDEFINED) { - orc->sp_reg =3D ORC_REG_UNDEFINED; - return 0; - } - - switch (cfi->cfa.base) { - case CFI_SP: - orc->sp_reg =3D ORC_REG_SP; - break; - case CFI_SP_INDIRECT: - orc->sp_reg =3D ORC_REG_SP_INDIRECT; - break; - case CFI_BP: - orc->sp_reg =3D ORC_REG_BP; - break; - case CFI_BP_INDIRECT: - orc->sp_reg =3D ORC_REG_BP_INDIRECT; - break; - case CFI_R10: - orc->sp_reg =3D ORC_REG_R10; - break; - case CFI_R13: - orc->sp_reg =3D ORC_REG_R13; - break; - case CFI_DI: - orc->sp_reg =3D ORC_REG_DI; - break; - case CFI_DX: - orc->sp_reg =3D ORC_REG_DX; - break; - default: - WARN_FUNC("unknown CFA base reg %d", - insn->sec, insn->offset, cfi->cfa.base); - return -1; - } - - switch (bp->base) { - case CFI_UNDEFINED: - orc->bp_reg =3D ORC_REG_UNDEFINED; - break; - case CFI_CFA: - orc->bp_reg =3D ORC_REG_PREV_SP; - break; - case CFI_BP: - orc->bp_reg =3D ORC_REG_BP; - break; - default: - WARN_FUNC("unknown BP base reg %d", - insn->sec, insn->offset, bp->base); - return -1; - } - - orc->sp_offset =3D cfi->cfa.offset; - orc->bp_offset =3D bp->offset; - orc->type =3D cfi->type; - - return 0; -} - static int write_orc_entry(struct elf *elf, struct section *orc_sec, struct section *ip_sec, unsigned int idx, struct section *insn_sec, unsigned long insn_off, @@ -101,7 +28,7 @@ static int write_orc_entry(struct elf *elf, struct secti= on *orc_sec, orc->fp_offset =3D bswap_if_needed(orc->fp_offset); =20 /* populate reloc for ip */ - if (elf_add_reloc_to_insn(elf, ip_sec, idx * sizeof(int), R_X86_64_PC32, + if (elf_add_reloc_to_insn(elf, ip_sec, idx * sizeof(int), R_PCREL, insn_sec, insn_off)) return -1; =20 --=20 2.25.1 From nobody Tue Apr 23 06:20:23 2024 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id AAD53C433F5 for ; Tue, 24 May 2022 00:17:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230243AbiEXARV (ORCPT ); Mon, 23 May 2022 20:17:21 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58594 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231710AbiEXAQ4 (ORCPT ); Mon, 23 May 2022 20:16:56 -0400 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 70F96719F4; Mon, 23 May 2022 17:16:54 -0700 (PDT) Received: from x64host.home (unknown [47.189.24.195]) by linux.microsoft.com (Postfix) with ESMTPSA id 7E36D20B8958; Mon, 23 May 2022 17:16:53 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 7E36D20B8958 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1653351414; bh=Rr2//iem1xjhfYP3RsVY0bD7J8s2uEkhagwtkNIGSQM=; h=From:To:Subject:Date:In-Reply-To:References:From; b=TUNOgWrQIBG4Lr+ooPILTzPW8QHXhwcbR4hXVEMWNeqEvmx/3ELNM71a+19BgotiX EAkake/AzIVIJqS6Zj0Oqll9d8GNJ9s47Ta8f5Pjqa6Bzgjn4QNirA03SBjqUTM7tZ 5SaGoujB6s5Xp59Kq08JhMnDoeIHrAQCdWlOY0/I= From: madvenka@linux.microsoft.com To: jpoimboe@redhat.com, peterz@infradead.org, chenzhongjin@huawei.com, mark.rutland@arm.com, broonie@kernel.org, nobuta.keiya@fujitsu.com, sjitindarsingh@gmail.com, catalin.marinas@arm.com, will@kernel.org, jamorris@linux.microsoft.com, linux-arm-kernel@lists.infradead.org, live-patching@vger.kernel.org, linux-kernel@vger.kernel.org, madvenka@linux.microsoft.com Subject: [RFC PATCH v2 07/20] objtool: Reorganize ORC kernel code Date: Mon, 23 May 2022 19:16:24 -0500 Message-Id: <20220524001637.1707472-8-madvenka@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220524001637.1707472-1-madvenka@linux.microsoft.com> References: <20220524001637.1707472-1-madvenka@linux.microsoft.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: "Madhavan T. Venkataraman" All of the ORC code in the kernel is currently under arch/x86. The following parts of that code can be shared by other architectures that wish to use ORC. (1) ORC lookup initialization for vmlinux (2) ORC lookup initialization for modules (3) ORC lookup functions Move arch/x86/include/asm/orc_lookup.h to include/asm-generic/orc_lookup.h. Move the ORC lookup code into kernel/orc_lookup.c. Rename the following init functions: unwind_module_init =3D=3D> orc_lookup_module_init unwind_init =3D=3D> orc_lookup_init since that is exactly what they do. orc_find() is the function that locates the ORC entry for a given PC. Currently, it contains an architecture-specific part to locate ftrace entries. Introduce a new arch-specific function called arch_orc_find() and move the ftrace-related lookup there. If orc_find() is unable to locate the ORC entry for a given PC in vmlinux or in the modules, it can call arch_orc_find() to find architecture-specific entries. Signed-off-by: Madhavan T. Venkataraman --- arch/x86/include/asm/unwind.h | 5 - arch/x86/kernel/module.c | 7 +- arch/x86/kernel/unwind_orc.c | 256 +---------------- arch/x86/kernel/vmlinux.lds.S | 2 +- .../asm =3D> include/asm-generic}/orc_lookup.h | 42 +++ kernel/Makefile | 2 + kernel/orc_lookup.c | 261 ++++++++++++++++++ 7 files changed, 316 insertions(+), 259 deletions(-) rename {arch/x86/include/asm =3D> include/asm-generic}/orc_lookup.h (51%) create mode 100644 kernel/orc_lookup.c diff --git a/arch/x86/include/asm/unwind.h b/arch/x86/include/asm/unwind.h index 7cede4dc21f0..71af8246c69e 100644 --- a/arch/x86/include/asm/unwind.h +++ b/arch/x86/include/asm/unwind.h @@ -94,13 +94,8 @@ static inline struct pt_regs *unwind_get_entry_regs(stru= ct unwind_state *state, =20 #ifdef CONFIG_UNWINDER_ORC void unwind_init(void); -void unwind_module_init(struct module *mod, void *orc_ip, size_t orc_ip_si= ze, - void *orc, size_t orc_size); #else static inline void unwind_init(void) {} -static inline -void unwind_module_init(struct module *mod, void *orc_ip, size_t orc_ip_si= ze, - void *orc, size_t orc_size) {} #endif =20 static inline diff --git a/arch/x86/kernel/module.c b/arch/x86/kernel/module.c index b98ffcf4d250..4ebc9eddcb6b 100644 --- a/arch/x86/kernel/module.c +++ b/arch/x86/kernel/module.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include =20 #if 0 #define DEBUGP(fmt, ...) \ @@ -308,8 +308,9 @@ int module_finalize(const Elf_Ehdr *hdr, jump_label_apply_nops(me); =20 if (orc && orc_ip) - unwind_module_init(me, (void *)orc_ip->sh_addr, orc_ip->sh_size, - (void *)orc->sh_addr, orc->sh_size); + orc_lookup_module_init(me, + (void *)orc_ip->sh_addr, orc_ip->sh_size, + (void *)orc->sh_addr, orc->sh_size); =20 return 0; } diff --git a/arch/x86/kernel/unwind_orc.c b/arch/x86/kernel/unwind_orc.c index 7cae5bfa56c7..0a99d5261c9d 100644 --- a/arch/x86/kernel/unwind_orc.c +++ b/arch/x86/kernel/unwind_orc.c @@ -6,80 +6,9 @@ #include #include #include -#include - -#define orc_warn(fmt, ...) \ - printk_deferred_once(KERN_WARNING "WARNING: " fmt, ##__VA_ARGS__) - -#define orc_warn_current(args...) \ -({ \ - if (state->task =3D=3D current && !state->error) \ - orc_warn(args); \ -}) - -extern int __start_orc_unwind_ip[]; -extern int __stop_orc_unwind_ip[]; -extern struct orc_entry __start_orc_unwind[]; -extern struct orc_entry __stop_orc_unwind[]; - -static bool orc_init __ro_after_init; -static unsigned int lookup_num_blocks __ro_after_init; - -static inline unsigned long orc_ip(const int *ip) -{ - return (unsigned long)ip + *ip; -} - -static struct orc_entry *__orc_find(int *ip_table, struct orc_entry *u_tab= le, - unsigned int num_entries, unsigned long ip) -{ - int *first =3D ip_table; - int *last =3D ip_table + num_entries - 1; - int *mid =3D first, *found =3D first; - - if (!num_entries) - return NULL; - - /* - * Do a binary range search to find the rightmost duplicate of a given - * starting address. Some entries are section terminators which are - * "weak" entries for ensuring there are no gaps. They should be - * ignored when they conflict with a real entry. - */ - while (first <=3D last) { - mid =3D first + ((last - first) / 2); - - if (orc_ip(mid) <=3D ip) { - found =3D mid; - first =3D mid + 1; - } else - last =3D mid - 1; - } - - return u_table + (found - ip_table); -} - -#ifdef CONFIG_MODULES -static struct orc_entry *orc_module_find(unsigned long ip) -{ - struct module *mod; - - mod =3D __module_address(ip); - if (!mod || !mod->arch.orc_unwind || !mod->arch.orc_unwind_ip) - return NULL; - return __orc_find(mod->arch.orc_unwind_ip, mod->arch.orc_unwind, - mod->arch.num_orcs, ip); -} -#else -static struct orc_entry *orc_module_find(unsigned long ip) -{ - return NULL; -} -#endif +#include =20 #ifdef CONFIG_DYNAMIC_FTRACE -static struct orc_entry *orc_find(unsigned long ip); - /* * Ftrace dynamic trampolines do not have orc entries of their own. * But they are copies of the ftrace entries that are static and @@ -117,19 +46,10 @@ static struct orc_entry *orc_ftrace_find(unsigned long= ip) } #endif =20 -/* - * If we crash with IP=3D=3D0, the last successfully executed instruction - * was probably an indirect function call with a NULL function pointer, - * and we don't have unwind information for NULL. - * This hardcoded ORC entry for IP=3D=3D0 allows us to unwind from a NULL = function - * pointer into its parent and then continue normally from there. - */ -static struct orc_entry null_orc_entry =3D { - .sp_offset =3D sizeof(long), - .sp_reg =3D ORC_REG_SP, - .bp_reg =3D ORC_REG_UNDEFINED, - .type =3D UNWIND_HINT_TYPE_CALL -}; +struct orc_entry *arch_orc_find(unsigned long ip) +{ + return orc_ftrace_find(ip); +} =20 /* Fake frame pointer entry -- used as a fallback for generated code */ static struct orc_entry orc_fp_entry =3D { @@ -141,173 +61,9 @@ static struct orc_entry orc_fp_entry =3D { .end =3D 0, }; =20 -static struct orc_entry *orc_find(unsigned long ip) -{ - static struct orc_entry *orc; - - if (ip =3D=3D 0) - return &null_orc_entry; - - /* For non-init vmlinux addresses, use the fast lookup table: */ - if (ip >=3D LOOKUP_START_IP && ip < LOOKUP_STOP_IP) { - unsigned int idx, start, stop; - - idx =3D (ip - LOOKUP_START_IP) / LOOKUP_BLOCK_SIZE; - - if (unlikely((idx >=3D lookup_num_blocks-1))) { - orc_warn("WARNING: bad lookup idx: idx=3D%u num=3D%u ip=3D%pB\n", - idx, lookup_num_blocks, (void *)ip); - return NULL; - } - - start =3D orc_lookup[idx]; - stop =3D orc_lookup[idx + 1] + 1; - - if (unlikely((__start_orc_unwind + start >=3D __stop_orc_unwind) || - (__start_orc_unwind + stop > __stop_orc_unwind))) { - orc_warn("WARNING: bad lookup value: idx=3D%u num=3D%u start=3D%u stop= =3D%u ip=3D%pB\n", - idx, lookup_num_blocks, start, stop, (void *)ip); - return NULL; - } - - return __orc_find(__start_orc_unwind_ip + start, - __start_orc_unwind + start, stop - start, ip); - } - - /* vmlinux .init slow lookup: */ - if (is_kernel_inittext(ip)) - return __orc_find(__start_orc_unwind_ip, __start_orc_unwind, - __stop_orc_unwind_ip - __start_orc_unwind_ip, ip); - - /* Module lookup: */ - orc =3D orc_module_find(ip); - if (orc) - return orc; - - return orc_ftrace_find(ip); -} - -#ifdef CONFIG_MODULES - -static DEFINE_MUTEX(sort_mutex); -static int *cur_orc_ip_table =3D __start_orc_unwind_ip; -static struct orc_entry *cur_orc_table =3D __start_orc_unwind; - -static void orc_sort_swap(void *_a, void *_b, int size) -{ - struct orc_entry *orc_a, *orc_b; - struct orc_entry orc_tmp; - int *a =3D _a, *b =3D _b, tmp; - int delta =3D _b - _a; - - /* Swap the .orc_unwind_ip entries: */ - tmp =3D *a; - *a =3D *b + delta; - *b =3D tmp - delta; - - /* Swap the corresponding .orc_unwind entries: */ - orc_a =3D cur_orc_table + (a - cur_orc_ip_table); - orc_b =3D cur_orc_table + (b - cur_orc_ip_table); - orc_tmp =3D *orc_a; - *orc_a =3D *orc_b; - *orc_b =3D orc_tmp; -} - -static int orc_sort_cmp(const void *_a, const void *_b) -{ - struct orc_entry *orc_a; - const int *a =3D _a, *b =3D _b; - unsigned long a_val =3D orc_ip(a); - unsigned long b_val =3D orc_ip(b); - - if (a_val > b_val) - return 1; - if (a_val < b_val) - return -1; - - /* - * The "weak" section terminator entries need to always be on the left - * to ensure the lookup code skips them in favor of real entries. - * These terminator entries exist to handle any gaps created by - * whitelisted .o files which didn't get objtool generation. - */ - orc_a =3D cur_orc_table + (a - cur_orc_ip_table); - return orc_a->sp_reg =3D=3D ORC_REG_UNDEFINED && !orc_a->end ? -1 : 1; -} - -void unwind_module_init(struct module *mod, void *_orc_ip, size_t orc_ip_s= ize, - void *_orc, size_t orc_size) -{ - int *orc_ip =3D _orc_ip; - struct orc_entry *orc =3D _orc; - unsigned int num_entries =3D orc_ip_size / sizeof(int); - - WARN_ON_ONCE(orc_ip_size % sizeof(int) !=3D 0 || - orc_size % sizeof(*orc) !=3D 0 || - num_entries !=3D orc_size / sizeof(*orc)); - - /* - * The 'cur_orc_*' globals allow the orc_sort_swap() callback to - * associate an .orc_unwind_ip table entry with its corresponding - * .orc_unwind entry so they can both be swapped. - */ - mutex_lock(&sort_mutex); - cur_orc_ip_table =3D orc_ip; - cur_orc_table =3D orc; - sort(orc_ip, num_entries, sizeof(int), orc_sort_cmp, orc_sort_swap); - mutex_unlock(&sort_mutex); - - mod->arch.orc_unwind_ip =3D orc_ip; - mod->arch.orc_unwind =3D orc; - mod->arch.num_orcs =3D num_entries; -} -#endif - void __init unwind_init(void) { - size_t orc_ip_size =3D (void *)__stop_orc_unwind_ip - (void *)__start_orc= _unwind_ip; - size_t orc_size =3D (void *)__stop_orc_unwind - (void *)__start_orc_unwin= d; - size_t num_entries =3D orc_ip_size / sizeof(int); - struct orc_entry *orc; - int i; - - if (!num_entries || orc_ip_size % sizeof(int) !=3D 0 || - orc_size % sizeof(struct orc_entry) !=3D 0 || - num_entries !=3D orc_size / sizeof(struct orc_entry)) { - orc_warn("WARNING: Bad or missing .orc_unwind table. Disabling unwinder= .\n"); - return; - } - - /* - * Note, the orc_unwind and orc_unwind_ip tables were already - * sorted at build time via the 'sorttable' tool. - * It's ready for binary search straight away, no need to sort it. - */ - - /* Initialize the fast lookup table: */ - lookup_num_blocks =3D orc_lookup_end - orc_lookup; - for (i =3D 0; i < lookup_num_blocks-1; i++) { - orc =3D __orc_find(__start_orc_unwind_ip, __start_orc_unwind, - num_entries, - LOOKUP_START_IP + (LOOKUP_BLOCK_SIZE * i)); - if (!orc) { - orc_warn("WARNING: Corrupt .orc_unwind table. Disabling unwinder.\n"); - return; - } - - orc_lookup[i] =3D orc - __start_orc_unwind; - } - - /* Initialize the ending block: */ - orc =3D __orc_find(__start_orc_unwind_ip, __start_orc_unwind, num_entries, - LOOKUP_STOP_IP); - if (!orc) { - orc_warn("WARNING: Corrupt .orc_unwind table. Disabling unwinder.\n"); - return; - } - orc_lookup[lookup_num_blocks-1] =3D orc - __start_orc_unwind; - - orc_init =3D true; + orc_lookup_init(); } =20 unsigned long unwind_get_return_address(struct unwind_state *state) diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S index 7fda7f27e762..1b0c6b4eafae 100644 --- a/arch/x86/kernel/vmlinux.lds.S +++ b/arch/x86/kernel/vmlinux.lds.S @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include =20 diff --git a/arch/x86/include/asm/orc_lookup.h b/include/asm-generic/orc_lo= okup.h similarity index 51% rename from arch/x86/include/asm/orc_lookup.h rename to include/asm-generic/orc_lookup.h index 241631282e43..f299fbf41cd0 100644 --- a/arch/x86/include/asm/orc_lookup.h +++ b/include/asm-generic/orc_lookup.h @@ -23,6 +23,8 @@ =20 #ifndef LINKER_SCRIPT =20 +#include + extern unsigned int orc_lookup[]; extern unsigned int orc_lookup_end[]; =20 @@ -31,4 +33,44 @@ extern unsigned int orc_lookup_end[]; =20 #endif /* LINKER_SCRIPT */ =20 +#ifndef __ASSEMBLY__ + +#include + +#ifdef CONFIG_UNWINDER_ORC +void orc_lookup_init(void); +void orc_lookup_module_init(struct module *mod, + void *orc_ip, size_t orc_ip_size, + void *orc, size_t orc_size); +#else +static inline void orc_lookup_init(void) {} +static inline +void orc_lookup_module_init(struct module *mod, + void *orc_ip, size_t orc_ip_size, + void *orc, size_t orc_size) +{ +} +#endif + +struct orc_entry *arch_orc_find(unsigned long ip); + +#define orc_warn(fmt, ...) \ + printk_deferred_once(KERN_WARNING "WARNING: " fmt, ##__VA_ARGS__) + +#define orc_warn_current(args...) \ +({ \ + if (state->task =3D=3D current && !state->error) \ + orc_warn(args); \ +}) + +struct orc_entry *orc_find(unsigned long ip); + +extern bool orc_init; +extern int __start_orc_unwind_ip[]; +extern int __stop_orc_unwind_ip[]; +extern struct orc_entry __start_orc_unwind[]; +extern struct orc_entry __stop_orc_unwind[]; + +#endif /* __ASSEMBLY__ */ + #endif /* _ORC_LOOKUP_H */ diff --git a/kernel/Makefile b/kernel/Makefile index 471d71935e90..f9f8eb61442f 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -133,6 +133,8 @@ obj-$(CONFIG_WATCH_QUEUE) +=3D watch_queue.o obj-$(CONFIG_RESOURCE_KUNIT_TEST) +=3D resource_kunit.o obj-$(CONFIG_SYSCTL_KUNIT_TEST) +=3D sysctl-test.o =20 +obj-$(CONFIG_UNWINDER_ORC) +=3D orc_lookup.o + CFLAGS_stackleak.o +=3D $(DISABLE_STACKLEAK_PLUGIN) obj-$(CONFIG_GCC_PLUGIN_STACKLEAK) +=3D stackleak.o KASAN_SANITIZE_stackleak.o :=3D n diff --git a/kernel/orc_lookup.c b/kernel/orc_lookup.c new file mode 100644 index 000000000000..88b783c41e94 --- /dev/null +++ b/kernel/orc_lookup.c @@ -0,0 +1,261 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include +#include +#include +#include + +bool orc_init __ro_after_init; +static unsigned int lookup_num_blocks __ro_after_init; + +static inline unsigned long orc_ip(const int *ip) +{ + return (unsigned long)ip + *ip; +} + +static struct orc_entry *__orc_find(int *ip_table, struct orc_entry *u_tab= le, + unsigned int num_entries, unsigned long ip) +{ + int *first =3D ip_table; + int *last =3D ip_table + num_entries - 1; + int *mid =3D first, *found =3D first; + + if (!num_entries) + return NULL; + + /* + * Do a binary range search to find the rightmost duplicate of a given + * starting address. Some entries are section terminators which are + * "weak" entries for ensuring there are no gaps. They should be + * ignored when they conflict with a real entry. + */ + while (first <=3D last) { + mid =3D first + ((last - first) / 2); + + if (orc_ip(mid) <=3D ip) { + found =3D mid; + first =3D mid + 1; + } else + last =3D mid - 1; + } + + return u_table + (found - ip_table); +} + +#ifdef CONFIG_MODULES +static struct orc_entry *orc_module_find(unsigned long ip) +{ + struct module *mod; + + mod =3D __module_address(ip); + if (!mod || !mod->arch.orc_unwind || !mod->arch.orc_unwind_ip) + return NULL; + return __orc_find(mod->arch.orc_unwind_ip, mod->arch.orc_unwind, + mod->arch.num_orcs, ip); +} +#else +static struct orc_entry *orc_module_find(unsigned long ip) +{ + return NULL; +} +#endif + +/* + * If we crash with IP=3D=3D0, the last successfully executed instruction + * was probably an indirect function call with a NULL function pointer, + * and we don't have unwind information for NULL. + * This hardcoded ORC entry for IP=3D=3D0 allows us to unwind from a NULL = function + * pointer into its parent and then continue normally from there. + */ +static struct orc_entry null_orc_entry =3D { + .sp_offset =3D sizeof(long), + .sp_reg =3D ORC_REG_SP, + .fp_reg =3D ORC_REG_UNDEFINED, + .type =3D UNWIND_HINT_TYPE_CALL +}; + +struct orc_entry *orc_find(unsigned long ip) +{ + static struct orc_entry *orc; + + if (ip =3D=3D 0) + return &null_orc_entry; + + /* For non-init vmlinux addresses, use the fast lookup table: */ + if (ip >=3D LOOKUP_START_IP && ip < LOOKUP_STOP_IP) { + unsigned int idx, start, stop; + + if (!orc_init) { + /* + * Take the slow path if the fast lookup tables have + * not yet been initialized. + */ + return __orc_find(__start_orc_unwind_ip, + __start_orc_unwind, + __stop_orc_unwind_ip - + __start_orc_unwind_ip, ip); + } + + idx =3D (ip - LOOKUP_START_IP) / LOOKUP_BLOCK_SIZE; + + if (unlikely((idx >=3D lookup_num_blocks-1))) { + orc_warn("WARNING: bad lookup idx: idx=3D%u num=3D%u ip=3D%pB\n", + idx, lookup_num_blocks, (void *)ip); + return NULL; + } + + start =3D orc_lookup[idx]; + stop =3D orc_lookup[idx + 1] + 1; + + if (unlikely((__start_orc_unwind + start >=3D __stop_orc_unwind) || + (__start_orc_unwind + stop > __stop_orc_unwind))) { + orc_warn("WARNING: bad lookup value: idx=3D%u num=3D%u start=3D%u stop= =3D%u ip=3D%pB\n", + idx, lookup_num_blocks, start, stop, (void *)ip); + return NULL; + } + + return __orc_find(__start_orc_unwind_ip + start, + __start_orc_unwind + start, stop - start, ip); + } + + /* vmlinux .init slow lookup: */ + if (is_kernel_inittext(ip)) + return __orc_find(__start_orc_unwind_ip, __start_orc_unwind, + __stop_orc_unwind_ip - __start_orc_unwind_ip, ip); + + /* Module lookup: */ + orc =3D orc_module_find(ip); + if (orc) + return orc; + + return arch_orc_find(ip); +} + +#ifdef CONFIG_MODULES + +static DEFINE_MUTEX(sort_mutex); +static int *cur_orc_ip_table =3D __start_orc_unwind_ip; +static struct orc_entry *cur_orc_table =3D __start_orc_unwind; + +static void orc_sort_swap(void *_a, void *_b, int size) +{ + struct orc_entry *orc_a, *orc_b; + struct orc_entry orc_tmp; + int *a =3D _a, *b =3D _b, tmp; + int delta =3D _b - _a; + + /* Swap the .orc_unwind_ip entries: */ + tmp =3D *a; + *a =3D *b + delta; + *b =3D tmp - delta; + + /* Swap the corresponding .orc_unwind entries: */ + orc_a =3D cur_orc_table + (a - cur_orc_ip_table); + orc_b =3D cur_orc_table + (b - cur_orc_ip_table); + orc_tmp =3D *orc_a; + *orc_a =3D *orc_b; + *orc_b =3D orc_tmp; +} + +static int orc_sort_cmp(const void *_a, const void *_b) +{ + struct orc_entry *orc_a; + const int *a =3D _a, *b =3D _b; + unsigned long a_val =3D orc_ip(a); + unsigned long b_val =3D orc_ip(b); + + if (a_val > b_val) + return 1; + if (a_val < b_val) + return -1; + + /* + * The "weak" section terminator entries need to always be on the left + * to ensure the lookup code skips them in favor of real entries. + * These terminator entries exist to handle any gaps created by + * whitelisted .o files which didn't get objtool generation. + */ + orc_a =3D cur_orc_table + (a - cur_orc_ip_table); + return orc_a->sp_reg =3D=3D ORC_REG_UNDEFINED && !orc_a->end ? -1 : 1; +} + +void orc_lookup_module_init(struct module *mod, + void *_orc_ip, size_t orc_ip_size, + void *_orc, size_t orc_size) +{ + int *orc_ip =3D _orc_ip; + struct orc_entry *orc =3D _orc; + unsigned int num_entries =3D orc_ip_size / sizeof(int); + + WARN_ON_ONCE(orc_ip_size % sizeof(int) !=3D 0 || + orc_size % sizeof(*orc) !=3D 0 || + num_entries !=3D orc_size / sizeof(*orc)); + + /* + * The 'cur_orc_*' globals allow the orc_sort_swap() callback to + * associate an .orc_unwind_ip table entry with its corresponding + * .orc_unwind entry so they can both be swapped. + */ + mutex_lock(&sort_mutex); + cur_orc_ip_table =3D orc_ip; + cur_orc_table =3D orc; + sort(orc_ip, num_entries, sizeof(int), orc_sort_cmp, orc_sort_swap); + mutex_unlock(&sort_mutex); + + mod->arch.orc_unwind_ip =3D orc_ip; + mod->arch.orc_unwind =3D orc; + mod->arch.num_orcs =3D num_entries; +} +#endif + +void __init orc_lookup_init(void) +{ + size_t orc_ip_size =3D (void *)__stop_orc_unwind_ip - (void *)__start_orc= _unwind_ip; + size_t orc_size =3D (void *)__stop_orc_unwind - (void *)__start_orc_unwin= d; + size_t num_entries =3D orc_ip_size / sizeof(int); + struct orc_entry *orc; + int i; + + if (!num_entries || orc_ip_size % sizeof(int) !=3D 0 || + orc_size % sizeof(struct orc_entry) !=3D 0 || + num_entries !=3D orc_size / sizeof(struct orc_entry)) { + orc_warn("WARNING: Bad or missing .orc_unwind table. Disabling unwinder= .\n"); + return; + } + + /* + * Note, the orc_unwind and orc_unwind_ip tables were already + * sorted at build time via the 'sorttable' tool. + * It's ready for binary search straight away, no need to sort it. + */ + + /* Initialize the fast lookup table: */ + lookup_num_blocks =3D orc_lookup_end - orc_lookup; + for (i =3D 0; i < lookup_num_blocks-1; i++) { + orc =3D __orc_find(__start_orc_unwind_ip, __start_orc_unwind, + num_entries, + LOOKUP_START_IP + (LOOKUP_BLOCK_SIZE * i)); + if (!orc) { + orc_warn("WARNING: Corrupt .orc_unwind table. Disabling unwinder.\n"); + return; + } + + orc_lookup[i] =3D orc - __start_orc_unwind; + } + + /* Initialize the ending block: */ + orc =3D __orc_find(__start_orc_unwind_ip, __start_orc_unwind, num_entries, + LOOKUP_STOP_IP); + if (!orc) { + orc_warn("WARNING: Corrupt .orc_unwind table. Disabling unwinder.\n"); + return; + } + orc_lookup[lookup_num_blocks-1] =3D orc - __start_orc_unwind; + + orc_init =3D true; +} + +__weak struct orc_entry *arch_orc_find(unsigned long ip) +{ + return NULL; +} --=20 2.25.1 From nobody Tue Apr 23 06:20:23 2024 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D3ABAC433EF for ; Tue, 24 May 2022 00:17:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232155AbiEXARb (ORCPT ); Mon, 23 May 2022 20:17:31 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58692 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231737AbiEXAQ5 (ORCPT ); Mon, 23 May 2022 20:16:57 -0400 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 7221A6D4CB; Mon, 23 May 2022 17:16:55 -0700 (PDT) Received: from x64host.home (unknown [47.189.24.195]) by linux.microsoft.com (Postfix) with ESMTPSA id 7F2F220B895B; Mon, 23 May 2022 17:16:54 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 7F2F220B895B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1653351415; bh=NA16KWlQPMN0HiA+DBPspnlFwB3chkl/e0Ulkr5UDdA=; h=From:To:Subject:Date:In-Reply-To:References:From; b=P/8Udr7JPl0jloM1OqtLgmnqIxrhl6BjF9tfhWnx5/slYQnE74waDWn2D96EQPP/X TyLxBMTcgWc6ZPLr/Nci9GakGN/DruUa59Y3DQKaD/ep3oR4502o1EjyLDUM6i9FSO Mlq1iVAkglieO/HQ9jXw5EUaz3fyKb4tr1kIau3Y= From: madvenka@linux.microsoft.com To: jpoimboe@redhat.com, peterz@infradead.org, chenzhongjin@huawei.com, mark.rutland@arm.com, broonie@kernel.org, nobuta.keiya@fujitsu.com, sjitindarsingh@gmail.com, catalin.marinas@arm.com, will@kernel.org, jamorris@linux.microsoft.com, linux-arm-kernel@lists.infradead.org, live-patching@vger.kernel.org, linux-kernel@vger.kernel.org, madvenka@linux.microsoft.com Subject: [RFC PATCH v2 08/20] objtool: arm64: Implement decoder for FP validation Date: Mon, 23 May 2022 19:16:25 -0500 Message-Id: <20220524001637.1707472-9-madvenka@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220524001637.1707472-1-madvenka@linux.microsoft.com> References: <20220524001637.1707472-1-madvenka@linux.microsoft.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: "Madhavan T. Venkataraman" Implement arch_decode_instruction() for ARM64. For dynamic FP validation, we need to walk each function's code and determine the stack and frame offsets at each instruction. So, the following instructions are completely decoded: Instructions that affect the SP and FP: - Load-Store instructions - Add/Sub/Mov instructions Instructions that affect control flow: - Branch instructions - Call instructions - Return instructions The rest of the instructions are either dont-care from an unwind perspective or unexpected from the compiler. Add checks for the unexpected ones to catch them if the compiler ever generates them. Define CFI registers used by ARM64 in arch-specific cfi_regs.h. This is a small subset of the ones used in x86. Signed-off-by: Madhavan T. Venkataraman --- tools/objtool/arch/arm64/Build | 1 + tools/objtool/arch/arm64/decode.c | 342 ++++++++++++++++++ .../arch/arm64/include/arch/cfi_regs.h | 12 + tools/objtool/include/objtool/arch.h | 1 + 4 files changed, 356 insertions(+) create mode 100644 tools/objtool/arch/arm64/Build create mode 100644 tools/objtool/arch/arm64/decode.c create mode 100644 tools/objtool/arch/arm64/include/arch/cfi_regs.h diff --git a/tools/objtool/arch/arm64/Build b/tools/objtool/arch/arm64/Build new file mode 100644 index 000000000000..3ff1f00c6a47 --- /dev/null +++ b/tools/objtool/arch/arm64/Build @@ -0,0 +1 @@ +objtool-y +=3D decode.o diff --git a/tools/objtool/arch/arm64/decode.c b/tools/objtool/arch/arm64/d= ecode.c new file mode 100644 index 000000000000..8a9ff030085d --- /dev/null +++ b/tools/objtool/arch/arm64/decode.c @@ -0,0 +1,342 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * decode.c - ARM64 instruction decoder for dynamic FP validation. Only a + * small subset of the instructions need to be decoded. + * + * Author: Madhavan T. Venkataraman (madvenka@linux.microsoft.com) + * + * Copyright (C) 2022 Microsoft Corporation + */ +#include +#include +#include + +#include +#include +#include +#include + +/* ARM64 instructions are all 4 bytes wide. */ +#define INSN_SIZE 4 + +/* --------------------- instruction decode struct -----------------------= -- */ + +struct decode { + unsigned long opmask; + unsigned long op; + unsigned int shift; + unsigned int bits; + unsigned int size; + unsigned int sign_extend; + void (*func)(struct decode *decode, + u32 insn, enum insn_type *type, + s64 *imm, struct list_head *stack_ops); +}; + +/* --------------------- miscellaneous functions -------------------------= -- */ + +static void reg_check(unsigned int sp_check, unsigned int fp_check, + u32 insn, enum insn_type *type) +{ + unsigned int rd =3D insn & 0x1F; + + if ((sp_check && rd =3D=3D CFI_SP) || (fp_check && rd =3D=3D CFI_FP)) + *type =3D INSN_UNRELIABLE; +} + +static void add_stack_op(unsigned char src, unsigned char dest, s64 offset, + struct list_head *stack_ops) +{ + struct stack_op *op; + + op =3D calloc(1, sizeof(*op)); + if (!op) { + WARN("calloc failed"); + return; + } + + op->src.reg =3D src; + op->src.type =3D OP_SRC_ADD; + op->src.offset =3D offset; + op->dest.reg =3D dest; + op->dest.type =3D OP_DEST_REG; + + list_add_tail(&op->list, stack_ops); +} + +/* ------------------------ decode functions -----------------------------= -- */ + +#define STP_SOFF 0x29000000 /* STP signed offset */ +#define STR_SOFF 0xB9000000 /* STR signed offset */ +#define LDP_SOFF 0x29400000 /* LDP signed offset */ +#define LDR_SOFF 0xB9400000 /* LDR signed offset */ + +/* Load-Store instructions. */ +static void ld_st(struct decode *decode, + u32 insn, enum insn_type *type, + s64 *imm, struct list_head *stack_ops) +{ + unsigned int rn =3D (insn >> 5) & 0x1F; + + if (decode->op =3D=3D LDP_SOFF || decode->op =3D=3D LDR_SOFF || + decode->op =3D=3D STP_SOFF || decode->op =3D=3D STR_SOFF) + return; + if (rn =3D=3D CFI_SP) + add_stack_op(CFI_SP, CFI_SP, *imm, stack_ops); + else if (rn =3D=3D CFI_FP) + add_stack_op(CFI_FP, CFI_FP, *imm, stack_ops); +} + +/* Load-Store instructions. */ +static void ld_st_chk(struct decode *decode, + u32 insn, enum insn_type *type, + s64 *imm, struct list_head *stack_ops) +{ + ld_st(decode, insn, type, imm, stack_ops); + reg_check(0, 1, insn, type); +} + +#define CMN_OP 0x31000000 /* Alias of ADDS imm */ +#define CMP_OP 0x71000000 /* Alias of SUBS imm */ + +/* Add instructions. */ +static void add(struct decode *decode, + u32 insn, enum insn_type *type, + s64 *imm, struct list_head *stack_ops) +{ + unsigned int rd =3D insn & 0x1F; + unsigned int rn =3D (insn >> 5) & 0x1F; + unsigned int shift =3D (insn >> 22) & 1; + + if (shift) + *imm <<=3D 12; + + if (rd =3D=3D CFI_SP) { + if (rn =3D=3D CFI_SP) + add_stack_op(CFI_SP, CFI_SP, *imm, stack_ops); + else if (rn =3D=3D CFI_FP) + add_stack_op(CFI_FP, CFI_SP, *imm, stack_ops); + else if (decode->op !=3D CMN_OP && decode->op !=3D CMP_OP) + *type =3D INSN_UNRELIABLE; + } else if (rd =3D=3D CFI_FP) { + if (rn =3D=3D CFI_SP) + add_stack_op(CFI_SP, CFI_FP, *imm, stack_ops); + else if (rn =3D=3D CFI_FP) + add_stack_op(CFI_FP, CFI_FP, *imm, stack_ops); + else + *type =3D INSN_UNRELIABLE; + } +} + +/* Subtract instructions. */ +static void sub(struct decode *decode, + u32 insn, enum insn_type *type, + s64 *imm, struct list_head *stack_ops) +{ + *imm =3D -(*imm); + return add(decode, insn, type, imm, stack_ops); +} + +#define BR_UNCONDITIONAL 0x14000000 + +/* Branch and Return instructions. */ +static void branch(struct decode *decode, + u32 insn, enum insn_type *type, + s64 *imm, struct list_head *stack_ops) +{ + if (*imm) { + if (decode->op =3D=3D BR_UNCONDITIONAL) + *type =3D INSN_JUMP_UNCONDITIONAL; + else + *type =3D INSN_JUMP_CONDITIONAL; + } else { + *type =3D INSN_JUMP_DYNAMIC; + } +} + +static void call(struct decode *decode, + u32 insn, enum insn_type *type, + s64 *imm, struct list_head *stack_ops) +{ + *type =3D *imm ? INSN_CALL : INSN_CALL_DYNAMIC; +} + +static void ret(struct decode *decode, + u32 insn, enum insn_type *type, + s64 *imm, struct list_head *stack_ops) +{ + *type =3D INSN_RETURN; +} + +static void bug(struct decode *decode, + u32 insn, enum insn_type *type, + s64 *imm, struct list_head *stack_ops) +{ + *type =3D INSN_BUG; +} + +/* + * Other instructions are not decoded. They don't generate any stack_ops. + * Only checks are done to make sure that the compiler does not generate + * any instructions to clobber the SP and FP registers in unexpected ways. + */ +static void sp_check(struct decode *decode, + u32 insn, enum insn_type *type, + s64 *imm, struct list_head *stack_ops) +{ + reg_check(1, 1, insn, type); +} + +static void fp_check(struct decode *decode, + u32 insn, enum insn_type *type, + s64 *imm, struct list_head *stack_ops) +{ + reg_check(0, 1, insn, type); +} + +static void ignore(struct decode *decode, + u32 insn, enum insn_type *type, + s64 *imm, struct list_head *stack_ops) +{ +} + +/* ------------------------ Instruction decode ---------------------------= -- */ + +struct decode decode_array[] =3D { +/* =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D INSTRUCTIONS =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ +/* operation mask opcode shift bits size sign func = */ +/* =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D*/ +/* LDP pre */ { 0x7FC00000, 0x29C00000, 15, 7, 8, 1, ld_st = }, +/* LDP post */ { 0x7FC00000, 0x28C00000, 15, 7, 8, 1, ld_st = }, +/* LDP off */ { 0x7FC00000, 0x29400000, 15, 7, 8, 1, ld_st = }, +/* LDPSW pre */ { 0xFFC00000, 0x69C00000, 15, 7, 4, 1, ld_st_= chk }, +/* LDPSW post */ { 0xFFC00000, 0x68C00000, 15, 7, 4, 1, ld_st_= chk }, +/* LDR imm pre */ { 0xBFE00C00, 0xB8400C00, 12, 9, 1, 1, ld_st = }, +/* LDR imm post */ { 0xBFE00C00, 0xB8400400, 12, 9, 1, 1, ld_st = }, +/* LDR off */ { 0xBFC00000, 0xB9400000, 12, 9, 1, 1, ld_st = }, +/* LDRB imm pre */ { 0xFFE00C00, 0x38400C00, 12, 9, 1, 1, ld_st_= chk }, +/* LDRB imm post */ { 0xFFE00C00, 0x38400400, 12, 9, 1, 1, ld_st_= chk }, +/* LDRH imm pre */ { 0xFFE00C00, 0x78400C00, 12, 9, 1, 1, ld_st_= chk }, +/* LDRH imm post */ { 0xFFE00C00, 0x78400400, 12, 9, 1, 1, ld_st_= chk }, +/* LDRSB imm pre */ { 0xFF800C00, 0x38800C00, 12, 9, 1, 1, ld_st_= chk }, +/* LDRSB imm post */ { 0xFF800C00, 0x38800400, 12, 9, 1, 1, ld_st_= chk }, +/* LDRSH imm pre */ { 0xFF800C00, 0x78800C00, 12, 9, 1, 1, ld_st_= chk }, +/* LDRSH imm post */ { 0xFF800C00, 0x78800400, 12, 9, 1, 1, ld_st_= chk }, +/* LDRSW imm pre */ { 0xFFE00C00, 0xB8800C00, 12, 9, 1, 1, ld_st_= chk }, +/* LDRSW imm post */ { 0xFFE00C00, 0xB8800400, 12, 9, 1, 1, ld_st_= chk }, +/* STP pre */ { 0x7FC00000, 0x29800000, 15, 7, 8, 1, ld_st = }, +/* STP post */ { 0x7FC00000, 0x28800000, 15, 7, 8, 1, ld_st = }, +/* STP off */ { 0x7FC00000, 0x29000000, 15, 7, 8, 1, ld_st = }, +/* STGP imm pre */ { 0xFFC00000, 0x69800000, 15, 7, 16, 1, ld_st = }, +/* STGP imm post */ { 0xFFC00000, 0x68800000, 15, 7, 16, 1, ld_st = }, +/* STR imm pre */ { 0xBFC00C00, 0xB8000C00, 12, 9, 1, 1, ld_st = }, +/* STR imm post */ { 0xBFC00C00, 0xB8000400, 12, 9, 1, 1, ld_st = }, +/* STR off */ { 0xBFC00000, 0xB9000000, 10, 12, 1, 1, ld_st = }, +/* STG imm pre */ { 0xFFC00C00, 0xD9000C00, 12, 9, 16, 1, ld_st = }, +/* STG imm post */ { 0xFFC00C00, 0xD9000400, 12, 9, 16, 1, ld_st = }, +/* ST2G imm pre */ { 0xFFE00C00, 0xD9A00C00, 12, 9, 16, 1, ld_st = }, +/* ST2G imm post */ { 0xFFE00C00, 0xD9A00400, 12, 9, 16, 1, ld_st = }, +/* ADD imm */ { 0x7F800000, 0x11000000, 10, 12, 1, 0, add }, +/* ADDS imm */ { 0x7F800000, 0x31000000, 10, 12, 1, 0, add }, +/* ADD ext reg */ { 0x7FE00000, 0x0B200000, 0, 0, 1, 0, sp_che= ck }, +/* SUB imm */ { 0x7F800000, 0x51000000, 10, 12, 1, 0, sub }, +/* SUBS imm */ { 0x7F800000, 0x71000000, 10, 12, 1, 0, sub }, +/* SUB ext reg */ { 0x7FE00000, 0x4B200000, 0, 0, 1, 0, sp_che= ck }, +/* ORR imm */ { 0x7F800000, 0x32000000, 0, 0, 1, 0, sp_che= ck }, +/* B */ { 0xFC000000, 0x14000000, 0, 26, 4, 1, branch= }, +/* B.cond */ { 0xFF000010, 0x54000000, 5, 19, 4, 1, branch= }, +/* BC.cond */ { 0xFF000010, 0x54000010, 5, 19, 4, 1, branch= }, +/* BR */ { 0xFFFFFC00, 0xD61F0000, 0, 0, 4, 0, branch= }, +/* BRA */ { 0xFEFFF800, 0xD61F0800, 0, 0, 4, 0, branch= }, +/* CBZ */ { 0x7F000000, 0x34000000, 5, 19, 4, 1, branch= }, +/* CBNZ */ { 0x7F000000, 0x35000000, 5, 19, 4, 1, branch= }, +/* TBZ */ { 0x7F000000, 0x36000000, 5, 14, 4, 1, branch= }, +/* TBNZ */ { 0x7F000000, 0x37000000, 5, 14, 4, 1, branch= }, +/* BL */ { 0xFC000000, 0x94000000, 0, 26, 4, 1, call }, +/* BLR */ { 0xFFFFFC00, 0xD63F0000, 0, 0, 4, 1, call }, +/* BLRA */ { 0xFEFFF800, 0xD63F0800, 0, 0, 4, 1, call }, +/* RET */ { 0xFFFFFC1F, 0xD65F0000, 0, 0, 1, 0, ret }, +/* RETA */ { 0xFFFFFBFF, 0xD65F0BFF, 0, 0, 1, 0, ret }, +/* ERET */ { 0xFFFFFFFF, 0xD69F03E0, 0, 0, 1, 0, ret }, +/* ERETA */ { 0xFFFFFBFF, 0xD69F0BFF, 0, 0, 1, 0, ret }, +/* BRK */ { 0xFFE00000, 0xD4200000, 0, 0, 1, 0, bug }, + +/* =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D INSTRUCTION CLASSES =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D*/ +/* operation mask opcode shift bits size sign func = */ +/* =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D*/ +/* RSVD_00 */ { 0x1E000000, 0x00000000, 0, 0, 1, 0, ignore= }, +/* UNALLOC_01 */ { 0x1E000000, 0x02000000, 0, 0, 1, 0, ignore= }, +/* SVE_02 */ { 0x1E000000, 0x04000000, 0, 0, 1, 0, ignore= }, +/* UNALLOC_03 */ { 0x1E000000, 0x06000000, 0, 0, 1, 0, ignore= }, +/* LOAD_STORE_04 */ { 0x1E000000, 0x08000000, 0, 0, 1, 0, fp_che= ck }, +/* DP_REGISTER_05 */ { 0x1E000000, 0x0A000000, 0, 0, 1, 0, fp_che= ck }, +/* LOAD_STORE_06 */ { 0x1E000000, 0x0C000000, 0, 0, 1, 0, ignore= }, +/* SIMD_FP_07 */ { 0x1E000000, 0x0E000000, 0, 0, 1, 0, ignore= }, +/* DP_IMMEDIATE_08 */{ 0x1E000000, 0x10000000, 0, 0, 1, 0, fp_che= ck }, +/* DP_IMMEDIATE_09 */{ 0x1E000000, 0x12000000, 0, 0, 1, 0, fp_che= ck }, +/* BR_SYS_10 */ { 0x1E000000, 0x14000000, 0, 0, 1, 0, fp_che= ck }, +/* BR_SYS_11 */ { 0x1E000000, 0x16000000, 0, 0, 1, 0, fp_che= ck }, +/* LOAD_STORE_12 */ { 0x1E000000, 0x18000000, 0, 0, 1, 0, fp_che= ck }, +/* DP_REGISTER_13 */ { 0x1E000000, 0x1A000000, 0, 0, 1, 0, ignore= }, +/* LOAD_STORE_14 */ { 0x1E000000, 0x1C000000, 0, 0, 1, 0, fp_che= ck }, +/* SIMD_FP_15 */ { 0x1E000000, 0x1E000000, 0, 0, 1, 0, ignore= }, +}; +unsigned int ndecode =3D ARRAY_SIZE(decode_array); + +static inline s64 sign_extend(s64 imm, unsigned int bits) +{ + return (imm << (64 - bits)) >> (64 - bits); +} + +/* + * This decoder is only for generating stack ops for instructions that + * affect the SP and FP. The instructions that involve only immediate + * operands can be evaluated in this decoder. But instructions that + * involve other registers cannot be evaluated because the contents of + * those registers are known only at runtime. There are checks to catch + * it if the compiler generates these for the FP and SP. Such instructions + * are marked as unreliable. + */ +int arch_decode_instruction(struct objtool_file *file, + const struct section *sec, + unsigned long offset, unsigned int maxlen, + unsigned int *len, enum insn_type *type, + unsigned long *immediate, + struct list_head *stack_ops) +{ + struct decode *decode; + s64 imm; + u32 insn; + unsigned int mask, i; + + if (maxlen < INSN_SIZE) + return -1; + + insn =3D *(u32 *)(sec->data->d_buf + offset); + *type =3D INSN_OTHER; + *len =3D INSN_SIZE; + + /* + * Find the decode structure for the specific instruction, + * if listed. + */ + for (i =3D 0; i < ndecode; i++) { + decode =3D &decode_array[i]; + if ((insn & decode->opmask) =3D=3D decode->op) { + /* + * Decode the instruction. + */ + mask =3D (1 << decode->bits) - 1; + imm =3D (insn >> decode->shift) & mask; + if (decode->sign_extend) + imm =3D sign_extend(imm, decode->bits); + imm *=3D decode->size; + + decode->func(decode, insn, type, &imm, stack_ops); + *immediate =3D imm; + return 0; + } + } + /* Cannot happen. */ + return -1; +} diff --git a/tools/objtool/arch/arm64/include/arch/cfi_regs.h b/tools/objto= ol/arch/arm64/include/arch/cfi_regs.h new file mode 100644 index 000000000000..a3df37fe5290 --- /dev/null +++ b/tools/objtool/arch/arm64/include/arch/cfi_regs.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef _OBJTOOL_CFI_REGS_H +#define _OBJTOOL_CFI_REGS_H + +#define CFI_FP 29 +#define CFI_RA 30 +#define CFI_SP 31 + +#define CFI_NUM_REGS 32 + +#endif /* _OBJTOOL_CFI_REGS_H */ diff --git a/tools/objtool/include/objtool/arch.h b/tools/objtool/include/o= bjtool/arch.h index 9b19cc304195..e23d5746daf0 100644 --- a/tools/objtool/include/objtool/arch.h +++ b/tools/objtool/include/objtool/arch.h @@ -29,6 +29,7 @@ enum insn_type { INSN_TRAP, INSN_ENDBR, INSN_OTHER, + INSN_UNRELIABLE, }; =20 enum op_dest_type { --=20 2.25.1 From nobody Tue Apr 23 06:20:23 2024 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 20D9BC433F5 for ; Tue, 24 May 2022 00:17:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231950AbiEXARu (ORCPT ); Mon, 23 May 2022 20:17:50 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58778 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231740AbiEXAQ5 (ORCPT ); Mon, 23 May 2022 20:16:57 -0400 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 741016D1BA; Mon, 23 May 2022 17:16:56 -0700 (PDT) Received: from x64host.home (unknown [47.189.24.195]) by linux.microsoft.com (Postfix) with ESMTPSA id 7E3B320B895E; Mon, 23 May 2022 17:16:55 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 7E3B320B895E DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1653351416; bh=YG6KQOAJyGOL922olQKuoXPzwcII9DtE7DpLrKl5nFA=; h=From:To:Subject:Date:In-Reply-To:References:From; b=rB6vq+eaexXeXKlEiEyPMzkVQcdNXoz1Ho/8mJ0EDHSarAy9/cFPKftW0GVjp4dQb qKlHQoWRsBJMW6rv/QaiguC/s+1qauw4KDmQGAKaoWEtDKq47wIVN4MLIQ2SkJGtc/ OI7+yk41BA3C46ueOP9X3cP6w7uxttnYDLIhnOlw= From: madvenka@linux.microsoft.com To: jpoimboe@redhat.com, peterz@infradead.org, chenzhongjin@huawei.com, mark.rutland@arm.com, broonie@kernel.org, nobuta.keiya@fujitsu.com, sjitindarsingh@gmail.com, catalin.marinas@arm.com, will@kernel.org, jamorris@linux.microsoft.com, linux-arm-kernel@lists.infradead.org, live-patching@vger.kernel.org, linux-kernel@vger.kernel.org, madvenka@linux.microsoft.com Subject: [RFC PATCH v2 09/20] objtool: arm64: Implement command to invoke the decoder Date: Mon, 23 May 2022 19:16:26 -0500 Message-Id: <20220524001637.1707472-10-madvenka@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220524001637.1707472-1-madvenka@linux.microsoft.com> References: <20220524001637.1707472-1-madvenka@linux.microsoft.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: "Madhavan T. Venkataraman" Implement a built-in command called cmd_fpv() that can be invoked as follows: objtool fpv generate file.o The built-in command invokes decode_instructions() to walk each function and decode the instructions of the function. Signed-off-by: Madhavan T. Venkataraman --- tools/objtool/Build | 5 ++ tools/objtool/Makefile | 6 ++- tools/objtool/builtin-fpv.c | 71 +++++++++++++++++++++++++ tools/objtool/fpv.c | 19 +++++++ tools/objtool/include/objtool/builtin.h | 1 + tools/objtool/include/objtool/objtool.h | 1 + tools/objtool/objtool.c | 12 ++++- tools/objtool/weak.c | 5 ++ 8 files changed, 117 insertions(+), 3 deletions(-) create mode 100644 tools/objtool/builtin-fpv.c create mode 100644 tools/objtool/fpv.c diff --git a/tools/objtool/Build b/tools/objtool/Build index 9c2a332f61f3..a491f51c40b4 100644 --- a/tools/objtool/Build +++ b/tools/objtool/Build @@ -15,9 +15,14 @@ objtool-$(SUBCMD_ORC) +=3D decode.o objtool-$(SUBCMD_ORC) +=3D unwind_hints.o objtool-$(SUBCMD_ORC) +=3D orc_gen.o objtool-$(SUBCMD_ORC) +=3D orc_dump.o +objtool-$(SUBCMD_FPV) +=3D fpv.o +objtool-$(SUBCMD_FPV) +=3D cfi.o +objtool-$(SUBCMD_FPV) +=3D insn.o +objtool-$(SUBCMD_FPV) +=3D decode.o =20 objtool-y +=3D builtin-check.o objtool-y +=3D builtin-orc.o +objtool-y +=3D builtin-fpv.o objtool-y +=3D elf.o objtool-y +=3D objtool.o =20 diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile index 0dbd397f319d..2511053245bc 100644 --- a/tools/objtool/Makefile +++ b/tools/objtool/Makefile @@ -47,7 +47,11 @@ ifeq ($(SRCARCH),x86) SUBCMD_ORC :=3D y endif =20 -export SUBCMD_CHECK SUBCMD_ORC +ifeq ($(SRCARCH),arm64) + SUBCMD_FPV :=3D y +endif + +export SUBCMD_CHECK SUBCMD_ORC SUBCMD_FPV export srctree OUTPUT CFLAGS SRCARCH AWK include $(srctree)/tools/build/Makefile.include =20 diff --git a/tools/objtool/builtin-fpv.c b/tools/objtool/builtin-fpv.c new file mode 100644 index 000000000000..ff57dde39587 --- /dev/null +++ b/tools/objtool/builtin-fpv.c @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Author: Madhavan T. Venkataraman (madvenka@linux.microsoft.com) + * + * Copyright (C) 2022 Microsoft Corporation + */ + +/* + * objtool fp validation: + * + * This command analyzes a .o file and adds .orc_unwind and .orc_unwind_ip + * sections to it. The sections are used by the frame pointer-based in-ker= nel + * unwinder to validate the frame pointer. + */ + +#include +#include +#include + +static const char * const fpv_usage[] =3D { + "objtool fpv generate file.o", + NULL, +}; + +const struct option fpv_options[] =3D { + OPT_END(), +}; + +int cmd_fpv(int argc, const char **argv) +{ + const char *objname; + struct objtool_file *file; + int ret; + + argc--; argv++; + if (argc <=3D 0) + usage_with_options(fpv_usage, fpv_options); + + objname =3D argv[1]; + + file =3D objtool_open_read(objname); + if (!file) + return 1; + + /* Supported architectures. */ + switch (file->elf->ehdr.e_machine) { + case EM_AARCH64: + break; + + default: + return 1; + } + + if (!strncmp(argv[0], "gen", 3)) { + ret =3D fpv_decode(file); + if (ret) + return ret; + + if (list_empty(&file->insn_list)) + return 0; + + if (!file->elf->changed) + return 0; + + return elf_write(file->elf); + } + + usage_with_options(fpv_usage, fpv_options); + + return 0; +} diff --git a/tools/objtool/fpv.c b/tools/objtool/fpv.c new file mode 100644 index 000000000000..76f0f2e611a8 --- /dev/null +++ b/tools/objtool/fpv.c @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Author: Madhavan T. Venkataraman (madvenka@linux.microsoft.com) + * + * Copyright (C) 2022 Microsoft Corporation + */ + +#include +#include +#include + +#include +#include +#include + +int fpv_decode(struct objtool_file *file) +{ + return decode_instructions(file); +} diff --git a/tools/objtool/include/objtool/builtin.h b/tools/objtool/includ= e/objtool/builtin.h index c39dbfaef6dc..bfd99e08c33b 100644 --- a/tools/objtool/include/objtool/builtin.h +++ b/tools/objtool/include/objtool/builtin.h @@ -16,5 +16,6 @@ extern int cmd_parse_options(int argc, const char **argv,= const char * const usa =20 extern int cmd_check(int argc, const char **argv); extern int cmd_orc(int argc, const char **argv); +extern int cmd_fpv(int argc, const char **argv); =20 #endif /* _BUILTIN_H */ diff --git a/tools/objtool/include/objtool/objtool.h b/tools/objtool/includ= e/objtool/objtool.h index 7a5c13a78f87..e00c8dcc6885 100644 --- a/tools/objtool/include/objtool/objtool.h +++ b/tools/objtool/include/objtool/objtool.h @@ -45,5 +45,6 @@ void objtool_pv_add(struct objtool_file *file, int idx, s= truct symbol *func); int check(struct objtool_file *file); int orc_dump(const char *objname); int orc_create(struct objtool_file *file); +int fpv_decode(struct objtool_file *file); =20 #endif /* _OBJTOOL_H */ diff --git a/tools/objtool/objtool.c b/tools/objtool/objtool.c index b09946f4e1d6..974a9bc384e8 100644 --- a/tools/objtool/objtool.c +++ b/tools/objtool/objtool.c @@ -35,9 +35,17 @@ struct cmd_struct { static const char objtool_usage_string[] =3D "objtool COMMAND [ARGS]"; =20 +static const char check_help[] =3D + "Perform stack metadata validation on an object file"; +static const char orc_help[] =3D + "Generate in-place ORC unwind tables for an object file"; +static const char fpv_help[] =3D + "Generate in-place FP validation tables for an object file"; + static struct cmd_struct objtool_cmds[] =3D { - {"check", cmd_check, "Perform stack metadata validation on an object file= " }, - {"orc", cmd_orc, "Generate in-place ORC unwind tables for an object file= " }, + {"check", cmd_check, check_help }, + {"orc", cmd_orc, orc_help }, + {"fpv", cmd_fpv, fpv_help }, }; =20 bool help; diff --git a/tools/objtool/weak.c b/tools/objtool/weak.c index 8314e824db4a..5e56ad5fe0fe 100644 --- a/tools/objtool/weak.c +++ b/tools/objtool/weak.c @@ -29,3 +29,8 @@ int __weak orc_create(struct objtool_file *file) { UNSUPPORTED("orc"); } + +int __weak fpv_decode(struct objtool_file *file) +{ + UNSUPPORTED("fpv"); +} --=20 2.25.1 From nobody Tue Apr 23 06:20:23 2024 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6F779C433FE for ; Tue, 24 May 2022 00:17:47 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232009AbiEXARo (ORCPT ); Mon, 23 May 2022 20:17:44 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59720 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231866AbiEXARG (ORCPT ); Mon, 23 May 2022 20:17:06 -0400 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 7BA0F7356E; Mon, 23 May 2022 17:16:57 -0700 (PDT) Received: from x64host.home (unknown [47.189.24.195]) by linux.microsoft.com (Postfix) with ESMTPSA id 840BF20B8961; Mon, 23 May 2022 17:16:56 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 840BF20B8961 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1653351417; bh=R+hlXlIgmzD2z81ekWg5REk7Zg6/92uCUr3rLRNg/rg=; h=From:To:Subject:Date:In-Reply-To:References:From; b=QAAfP8w12GLVb9uPNNedsIVKNCQj6aLqSkeHejW1GXkuc4iLXRtACFewvA5oBKo+/ d/uWxOfrtdguU0ytD3rjVxdOpumo2FbWjhfnqCwQLdqUaBe1mPIBbH42pQ5uVK0CGL rmuUO+gvuvU2BmRtg5gtEOMec8dRs6SzyF7EwiuM= From: madvenka@linux.microsoft.com To: jpoimboe@redhat.com, peterz@infradead.org, chenzhongjin@huawei.com, mark.rutland@arm.com, broonie@kernel.org, nobuta.keiya@fujitsu.com, sjitindarsingh@gmail.com, catalin.marinas@arm.com, will@kernel.org, jamorris@linux.microsoft.com, linux-arm-kernel@lists.infradead.org, live-patching@vger.kernel.org, linux-kernel@vger.kernel.org, madvenka@linux.microsoft.com Subject: [RFC PATCH v2 10/20] objtool: arm64: Compute destinations for call and jump instructions Date: Mon, 23 May 2022 19:16:27 -0500 Message-Id: <20220524001637.1707472-11-madvenka@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220524001637.1707472-1-madvenka@linux.microsoft.com> References: <20220524001637.1707472-1-madvenka@linux.microsoft.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: "Madhavan T. Venkataraman" Compute the destination address of each call and jump instruction after decoding all the instructions. Signed-off-by: Madhavan T. Venkataraman --- tools/objtool/arch/arm64/decode.c | 12 ++++++++ tools/objtool/fpv.c | 47 ++++++++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/tools/objtool/arch/arm64/decode.c b/tools/objtool/arch/arm64/d= ecode.c index 8a9ff030085d..f9df8b321659 100644 --- a/tools/objtool/arch/arm64/decode.c +++ b/tools/objtool/arch/arm64/decode.c @@ -33,6 +33,18 @@ struct decode { s64 *imm, struct list_head *stack_ops); }; =20 +/* --------------------- arch support functions ------------------------- = */ + +unsigned long arch_dest_reloc_offset(int addend) +{ + return addend; +} + +unsigned long arch_jump_destination(struct instruction *insn) +{ + return insn->offset + insn->immediate; +} + /* --------------------- miscellaneous functions -------------------------= -- */ =20 static void reg_check(unsigned int sp_check, unsigned int fp_check, diff --git a/tools/objtool/fpv.c b/tools/objtool/fpv.c index 76f0f2e611a8..92ad0d0aac8e 100644 --- a/tools/objtool/fpv.c +++ b/tools/objtool/fpv.c @@ -13,7 +13,52 @@ #include #include =20 +/* + * Find the destination instructions for all jumps. + */ +static void add_jump_destinations(struct objtool_file *file) +{ + struct instruction *insn; + struct reloc *reloc; + struct section *dest_sec; + unsigned long dest_off; + + for_each_insn(file, insn) { + if (insn->type !=3D INSN_CALL && + insn->type !=3D INSN_JUMP_CONDITIONAL && + insn->type !=3D INSN_JUMP_UNCONDITIONAL) { + continue; + } + + reloc =3D insn_reloc(file, insn); + if (!reloc) { + dest_sec =3D insn->sec; + dest_off =3D arch_jump_destination(insn); + } else if (reloc->sym->type =3D=3D STT_SECTION) { + dest_sec =3D reloc->sym->sec; + dest_off =3D arch_dest_reloc_offset(reloc->addend); + } else if (reloc->sym->sec->idx) { + dest_sec =3D reloc->sym->sec; + dest_off =3D reloc->sym->sym.st_value + + arch_dest_reloc_offset(reloc->addend); + } else { + /* non-func asm code jumping to another file */ + continue; + } + + insn->jump_dest =3D find_insn(file, dest_sec, dest_off); + } +} + int fpv_decode(struct objtool_file *file) { - return decode_instructions(file); + int ret; + + ret =3D decode_instructions(file); + if (ret) + return ret; + + add_jump_destinations(file); + + return 0; } --=20 2.25.1 From nobody Tue Apr 23 06:20:23 2024 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B022AC433EF for ; Tue, 24 May 2022 00:17:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231969AbiEXARy (ORCPT ); Mon, 23 May 2022 20:17:54 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59740 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231886AbiEXARH (ORCPT ); Mon, 23 May 2022 20:17:07 -0400 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 77A0C74DE7; Mon, 23 May 2022 17:16:58 -0700 (PDT) Received: from x64host.home (unknown [47.189.24.195]) by linux.microsoft.com (Postfix) with ESMTPSA id 831E120B8964; Mon, 23 May 2022 17:16:57 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 831E120B8964 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1653351418; bh=3KNu2SqTulpI6MsZJqxj2nDgr1mSyJJSrp9yO31aXUY=; h=From:To:Subject:Date:In-Reply-To:References:From; b=IFXCPTA6/D2mLlhEwmbRiLgn3+2MF4BeYPolu/uQdlODAqJxuvl0WObdOZw9ComZ3 b4RyDxpiQJpjqKMjoWCHrbAULt15XQZhwhhYV6Hh2YCYQ1343HOerzGwwR+Ii5Ubm3 P9HmqW1QNCv5g6KDbqfvxHUurSknmww/CIAyirHg= From: madvenka@linux.microsoft.com To: jpoimboe@redhat.com, peterz@infradead.org, chenzhongjin@huawei.com, mark.rutland@arm.com, broonie@kernel.org, nobuta.keiya@fujitsu.com, sjitindarsingh@gmail.com, catalin.marinas@arm.com, will@kernel.org, jamorris@linux.microsoft.com, linux-arm-kernel@lists.infradead.org, live-patching@vger.kernel.org, linux-kernel@vger.kernel.org, madvenka@linux.microsoft.com Subject: [RFC PATCH v2 11/20] objtool: arm64: Walk instructions and compute CFI for each instruction Date: Mon, 23 May 2022 19:16:28 -0500 Message-Id: <20220524001637.1707472-12-madvenka@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220524001637.1707472-1-madvenka@linux.microsoft.com> References: <20220524001637.1707472-1-madvenka@linux.microsoft.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: "Madhavan T. Venkataraman" Implement arch_initial_func_cfi_state() to initialize the CFI for a function. Add code to fpv_decode() to walk the instructions in every function and compute the CFI information for each instruction. Implement special handling for cases like jump tables. Signed-off-by: Madhavan T. Venkataraman --- tools/objtool/arch/arm64/decode.c | 15 +++ tools/objtool/fpv.c | 204 ++++++++++++++++++++++++++++++ 2 files changed, 219 insertions(+) diff --git a/tools/objtool/arch/arm64/decode.c b/tools/objtool/arch/arm64/d= ecode.c index f9df8b321659..93ef7c0811f1 100644 --- a/tools/objtool/arch/arm64/decode.c +++ b/tools/objtool/arch/arm64/decode.c @@ -35,6 +35,21 @@ struct decode { =20 /* --------------------- arch support functions ------------------------- = */ =20 +void arch_initial_func_cfi_state(struct cfi_init_state *state) +{ + int i; + + for (i =3D 0; i < CFI_NUM_REGS; i++) { + state->regs[i].base =3D CFI_UNDEFINED; + state->regs[i].offset =3D 0; + } + state->regs[CFI_FP].base =3D CFI_CFA; + + /* initial CFA (call frame address) */ + state->cfa.base =3D CFI_SP; + state->cfa.offset =3D 0; +} + unsigned long arch_dest_reloc_offset(int addend) { return addend; diff --git a/tools/objtool/fpv.c b/tools/objtool/fpv.c index 92ad0d0aac8e..52f613ae998f 100644 --- a/tools/objtool/fpv.c +++ b/tools/objtool/fpv.c @@ -13,6 +13,8 @@ #include #include =20 +static bool fill; + /* * Find the destination instructions for all jumps. */ @@ -50,15 +52,217 @@ static void add_jump_destinations(struct objtool_file = *file) } } =20 +static void update_cfi_state(struct cfi_state *cfi, struct stack_op *op) +{ + struct cfi_reg *cfa =3D &cfi->cfa; + struct cfi_reg *regs =3D cfi->regs; + + if (op->src.reg =3D=3D CFI_SP) { + if (op->dest.reg =3D=3D CFI_SP) + cfa->offset -=3D op->src.offset; + else + regs[CFI_FP].offset =3D -cfa->offset + op->src.offset; + } else { + if (op->dest.reg =3D=3D CFI_SP) + cfa->offset =3D -(regs[CFI_FP].offset + op->src.offset); + else + regs[CFI_FP].offset +=3D op->src.offset; + } + + if (cfa->offset < -regs[CFI_FP].offset) + regs[CFI_FP].offset =3D 0; +} + +static void do_stack_ops(struct instruction *insn, struct insn_state *stat= e) +{ + struct stack_op *op; + + list_for_each_entry(op, &insn->stack_ops, list) { + update_cfi_state(&state->cfi, op); + } +} + +static void walk_code(struct objtool_file *file, struct section *sec, + struct symbol *func, + struct instruction *insn, struct insn_state *state) +{ + struct symbol *insn_func =3D insn->func; + struct instruction *dest; + struct cfi_state save_cfi; + unsigned long start, end; + + for (; insn; insn =3D next_insn_same_sec(file, insn)) { + + if (insn->func !=3D insn_func) + return; + + if (insn->cfi) { + if (fill) { + /* CFI is present. Nothing to fill. */ + return; + } + if (insn->cfi->regs[CFI_FP].offset || + !state->cfi.regs[CFI_FP].offset) { + return; + } + /* + * The new CFI contains a valid frame and the existing + * CFI doesn't. Replace the existing CFI with the new + * one. + */ + } + insn->cfi =3D cfi_hash_find_or_add(&state->cfi); + dest =3D insn->jump_dest; + + do_stack_ops(insn, state); + + switch (insn->type) { + case INSN_BUG: + case INSN_RETURN: + case INSN_UNRELIABLE: + return; + + case INSN_CALL: + case INSN_CALL_DYNAMIC: + start =3D func->offset; + end =3D start + func->len; + /* + * Treat intra-function calls as jumps and fall + * through. + */ + if (!dest || dest->sec !=3D sec || + dest->offset <=3D start || dest->offset >=3D end) { + break; + } + /* fallthrough */ + + case INSN_JUMP_UNCONDITIONAL: + case INSN_JUMP_CONDITIONAL: + case INSN_JUMP_DYNAMIC: + if (dest) { + save_cfi =3D state->cfi; + walk_code(file, sec, func, dest, state); + state->cfi =3D save_cfi; + } + if (insn->type =3D=3D INSN_JUMP_UNCONDITIONAL || + insn->type =3D=3D INSN_JUMP_DYNAMIC) { + return; + } + break; + + default: + break; + } + } +} + +static void walk_function(struct objtool_file *file, struct section *sec, + struct symbol *func) +{ + struct instruction *insn =3D find_insn(file, sec, func->offset); + struct insn_state state; + + init_insn_state(&state, sec); + set_func_state(&state.cfi); + + walk_code(file, sec, func, insn, &state); +} + +/* + * This function addresses cases like jump tables where there is an array + * of unconditional branches. The normal walk would not have visited these + * instructions and established CFIs for them. Find those instructions. For + * each such instruction, copy the CFI from the branch instruction and + * propagate it down. + */ +static void fill_function(struct objtool_file *file, struct section *sec, + struct symbol *func) +{ + struct instruction *insn, *prev; + struct insn_state state; + + func_for_each_insn(file, func, insn) { + + if (insn->cfi) { + /* Instruction already has a CFI. */ + continue; + } + + prev =3D list_prev_entry(insn, list); + if (!prev || !prev->cfi) { + /* + * Previous instruction does not have a CFI that can + * be used for this instruction. + */ + continue; + } + + if (prev->type !=3D INSN_JUMP_UNCONDITIONAL && + prev->type !=3D INSN_JUMP_DYNAMIC) { + /* Only copy CFI from unconditional branches. */ + continue; + } + + /* + * Propagate the CFI to all the instructions that can be + * visited from the current instruction that don't already + * have a CFI. + */ + state.cfi =3D *prev->cfi; + walk_code(file, insn->sec, insn->func, insn, &state); + } +} + +static void walk_section(struct objtool_file *file, struct section *sec) +{ + struct symbol *func; + + list_for_each_entry(func, &sec->symbol_list, list) { + + if (func->type !=3D STT_FUNC || !func->len || + func->pfunc !=3D func || func->alias !=3D func) { + /* No CFI generated for this function. */ + continue; + } + + if (!fill) + walk_function(file, sec, func); + else + fill_function(file, sec, func); + } +} + +static void walk_sections(struct objtool_file *file) +{ + struct section *sec; + + for_each_sec(file, sec) { + if (sec->sh.sh_flags & SHF_EXECINSTR) + walk_section(file, sec); + } +} + int fpv_decode(struct objtool_file *file) { int ret; =20 + arch_initial_func_cfi_state(&initial_func_cfi); + + if (!cfi_hash_alloc(1UL << (file->elf->symbol_bits - 3))) + return -1; + ret =3D decode_instructions(file); if (ret) return ret; =20 add_jump_destinations(file); =20 + if (!list_empty(&file->insn_list)) { + fill =3D false; + walk_sections(file); + fill =3D true; + walk_sections(file); + } + return 0; } --=20 2.25.1 From nobody Tue Apr 23 06:20:23 2024 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id AF222C433EF for ; Tue, 24 May 2022 00:18:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232039AbiEXASA (ORCPT ); Mon, 23 May 2022 20:18:00 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59746 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231891AbiEXARH (ORCPT ); Mon, 23 May 2022 20:17:07 -0400 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 9835A71D85; Mon, 23 May 2022 17:16:59 -0700 (PDT) Received: from x64host.home (unknown [47.189.24.195]) by linux.microsoft.com (Postfix) with ESMTPSA id 842B720B894E; Mon, 23 May 2022 17:16:58 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 842B720B894E DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1653351419; bh=BEl4S6V4psJ66iKSePCr3T5CVSyK8EsXFe/iBjZM0v4=; h=From:To:Subject:Date:In-Reply-To:References:From; b=k2zG0DYZvlsYpgRdexocd7OeDGDCNKI+d036LGCk7yKAzCNYvqROeDaXKJ5BXpKtT B8KAuKBX+OJZXyU9cCqe799CTiHdOMz5rgxzuGu0uhal/n07siJJdTaPsojSDS9BBE enRPtc86MihszD3Lgnu9+cEmpUt93pEGdSJqpRaI= From: madvenka@linux.microsoft.com To: jpoimboe@redhat.com, peterz@infradead.org, chenzhongjin@huawei.com, mark.rutland@arm.com, broonie@kernel.org, nobuta.keiya@fujitsu.com, sjitindarsingh@gmail.com, catalin.marinas@arm.com, will@kernel.org, jamorris@linux.microsoft.com, linux-arm-kernel@lists.infradead.org, live-patching@vger.kernel.org, linux-kernel@vger.kernel.org, madvenka@linux.microsoft.com Subject: [RFC PATCH v2 12/20] objtool: arm64: Generate ORC data from CFI for object files Date: Mon, 23 May 2022 19:16:29 -0500 Message-Id: <20220524001637.1707472-13-madvenka@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220524001637.1707472-1-madvenka@linux.microsoft.com> References: <20220524001637.1707472-1-madvenka@linux.microsoft.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: "Madhavan T. Venkataraman" Call orc_create() from cmd_fpv() to generate the ORC sections in object files for dynamic frame pointer validation. Signed-off-by: Madhavan T. Venkataraman --- arch/arm64/include/asm/orc_types.h | 35 ++++++++ tools/arch/arm64/include/asm/orc_types.h | 35 ++++++++ tools/objtool/Build | 1 + tools/objtool/arch/arm64/Build | 1 + tools/objtool/arch/arm64/include/arch/elf.h | 9 ++ .../arch/arm64/include/arch/endianness.h | 9 ++ tools/objtool/arch/arm64/orc.c | 86 +++++++++++++++++++ tools/objtool/builtin-fpv.c | 4 + tools/objtool/include/objtool/insn.h | 2 + tools/objtool/include/objtool/objtool.h | 1 + tools/objtool/insn.c | 20 +++++ tools/objtool/orc_gen.c | 12 ++- tools/objtool/sync-check.sh | 7 ++ 13 files changed, 220 insertions(+), 2 deletions(-) create mode 100644 arch/arm64/include/asm/orc_types.h create mode 100644 tools/arch/arm64/include/asm/orc_types.h create mode 100644 tools/objtool/arch/arm64/include/arch/elf.h create mode 100644 tools/objtool/arch/arm64/include/arch/endianness.h create mode 100644 tools/objtool/arch/arm64/orc.c diff --git a/arch/arm64/include/asm/orc_types.h b/arch/arm64/include/asm/or= c_types.h new file mode 100644 index 000000000000..c7bb690ca7d9 --- /dev/null +++ b/arch/arm64/include/asm/orc_types.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Author: Madhavan T. Venkataraman (madvenka@linux.microsoft.com) + * + * Copyright (C) 2022 Microsoft Corporation + */ + +#ifndef _ORC_TYPES_H +#define _ORC_TYPES_H + +#include +#include +#include + +/* + * The ORC_REG_* registers are base registers which are used to find other + * registers on the stack. + * + * ORC_REG_PREV_SP, also known as DWARF Call Frame Address (CFA), is the + * address of the previous frame: the caller's SP before it called the cur= rent + * function. + * + * ORC_REG_UNDEFINED means the corresponding register's value didn't chang= e in + * the current frame. + * + * We only use base registers SP and FP -- which the previous SP is based = on -- + * and PREV_SP and UNDEFINED -- which the previous FP is based on. + */ +#define ORC_REG_UNDEFINED 0 +#define ORC_REG_PREV_SP 1 +#define ORC_REG_SP 2 +#define ORC_REG_FP 3 +#define ORC_REG_MAX 4 + +#endif /* _ORC_TYPES_H */ diff --git a/tools/arch/arm64/include/asm/orc_types.h b/tools/arch/arm64/in= clude/asm/orc_types.h new file mode 100644 index 000000000000..c7bb690ca7d9 --- /dev/null +++ b/tools/arch/arm64/include/asm/orc_types.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Author: Madhavan T. Venkataraman (madvenka@linux.microsoft.com) + * + * Copyright (C) 2022 Microsoft Corporation + */ + +#ifndef _ORC_TYPES_H +#define _ORC_TYPES_H + +#include +#include +#include + +/* + * The ORC_REG_* registers are base registers which are used to find other + * registers on the stack. + * + * ORC_REG_PREV_SP, also known as DWARF Call Frame Address (CFA), is the + * address of the previous frame: the caller's SP before it called the cur= rent + * function. + * + * ORC_REG_UNDEFINED means the corresponding register's value didn't chang= e in + * the current frame. + * + * We only use base registers SP and FP -- which the previous SP is based = on -- + * and PREV_SP and UNDEFINED -- which the previous FP is based on. + */ +#define ORC_REG_UNDEFINED 0 +#define ORC_REG_PREV_SP 1 +#define ORC_REG_SP 2 +#define ORC_REG_FP 3 +#define ORC_REG_MAX 4 + +#endif /* _ORC_TYPES_H */ diff --git a/tools/objtool/Build b/tools/objtool/Build index a491f51c40b4..5de79c76f3f0 100644 --- a/tools/objtool/Build +++ b/tools/objtool/Build @@ -19,6 +19,7 @@ objtool-$(SUBCMD_FPV) +=3D fpv.o objtool-$(SUBCMD_FPV) +=3D cfi.o objtool-$(SUBCMD_FPV) +=3D insn.o objtool-$(SUBCMD_FPV) +=3D decode.o +objtool-$(SUBCMD_FPV) +=3D orc_gen.o =20 objtool-y +=3D builtin-check.o objtool-y +=3D builtin-orc.o diff --git a/tools/objtool/arch/arm64/Build b/tools/objtool/arch/arm64/Build index 3ff1f00c6a47..c026f5ddbd03 100644 --- a/tools/objtool/arch/arm64/Build +++ b/tools/objtool/arch/arm64/Build @@ -1 +1,2 @@ objtool-y +=3D decode.o +objtool-$(SUBCMD_FPV) +=3D orc.o diff --git a/tools/objtool/arch/arm64/include/arch/elf.h b/tools/objtool/ar= ch/arm64/include/arch/elf.h new file mode 100644 index 000000000000..4ae6df2bd90c --- /dev/null +++ b/tools/objtool/arch/arm64/include/arch/elf.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */ + +#ifndef _OBJTOOL_ARCH_ELF +#define _OBJTOOL_ARCH_ELF + +#define R_NONE R_AARCH64_NONE +#define R_PCREL R_AARCH64_PREL32 + +#endif /* _OBJTOOL_ARCH_ELF */ diff --git a/tools/objtool/arch/arm64/include/arch/endianness.h b/tools/obj= tool/arch/arm64/include/arch/endianness.h new file mode 100644 index 000000000000..7c362527da20 --- /dev/null +++ b/tools/objtool/arch/arm64/include/arch/endianness.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef _ARCH_ENDIANNESS_H +#define _ARCH_ENDIANNESS_H + +#include + +#define __TARGET_BYTE_ORDER __LITTLE_ENDIAN + +#endif /* _ARCH_ENDIANNESS_H */ diff --git a/tools/objtool/arch/arm64/orc.c b/tools/objtool/arch/arm64/orc.c new file mode 100644 index 000000000000..cef14114e1ec --- /dev/null +++ b/tools/objtool/arch/arm64/orc.c @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Author: Madhavan T. Venkataraman (madvenka@linux.microsoft.com) + * + * Copyright (C) 2022 Microsoft Corporation + */ +#include + +#include + +#include +#include + +int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, + struct instruction *insn) +{ + struct cfi_reg *fp =3D &cfi->regs[CFI_FP]; + + memset(orc, 0, sizeof(*orc)); + + orc->sp_reg =3D ORC_REG_SP; + orc->fp_reg =3D ORC_REG_PREV_SP; + + if (!cfi || cfi->cfa.base =3D=3D CFI_UNDEFINED || + (cfi->type =3D=3D UNWIND_HINT_TYPE_CALL && !fp->offset)) { + /* + * The frame pointer has not been set up. This instruction is + * unreliable from an unwind perspective. + */ + return 0; + } + + orc->sp_offset =3D cfi->cfa.offset; + orc->fp_offset =3D fp->offset; + orc->type =3D cfi->type; + orc->end =3D cfi->end; + + return 0; +} + +static const char *reg_name(unsigned int reg) +{ + switch (reg) { + case ORC_REG_PREV_SP: + return "cfa"; + case ORC_REG_FP: + return "x29"; + case ORC_REG_SP: + return "sp"; + default: + return "?"; + } +} + +const char *orc_type_name(unsigned int type) +{ + switch (type) { + case UNWIND_HINT_TYPE_CALL: + return "call"; + default: + return "?"; + } +} + +void orc_print_reg(unsigned int reg, int offset) +{ + if (reg =3D=3D ORC_REG_UNDEFINED) + printf("(und)"); + else + printf("%s%+d", reg_name(reg), offset); +} + +void orc_print_sp(void) +{ + printf(" cfa:"); +} + +void orc_print_fp(void) +{ + printf(" x29:"); +} + +bool orc_ignore_section(struct section *sec) +{ + return !strcmp(sec->name, ".head.text"); +} diff --git a/tools/objtool/builtin-fpv.c b/tools/objtool/builtin-fpv.c index ff57dde39587..bc8f88f204b5 100644 --- a/tools/objtool/builtin-fpv.c +++ b/tools/objtool/builtin-fpv.c @@ -59,6 +59,10 @@ int cmd_fpv(int argc, const char **argv) if (list_empty(&file->insn_list)) return 0; =20 + ret =3D orc_create(file); + if (ret) + return ret; + if (!file->elf->changed) return 0; =20 diff --git a/tools/objtool/include/objtool/insn.h b/tools/objtool/include/o= bjtool/insn.h index 0b5596f8b12f..c555fcd88b43 100644 --- a/tools/objtool/include/objtool/insn.h +++ b/tools/objtool/include/objtool/insn.h @@ -80,12 +80,14 @@ struct instruction *next_insn_same_sec(struct objtool_f= ile *file, struct instruction *next_insn_same_func(struct objtool_file *file, struct instruction *insn); struct reloc *insn_reloc(struct objtool_file *file, struct instruction *in= sn); +bool insn_can_reloc(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 instruction *insn); int decode_instructions(struct objtool_file *file); int read_unwind_hints(struct objtool_file *file); =20 + #define for_each_insn(file, insn) \ list_for_each_entry(insn, &file->insn_list, list) =20 diff --git a/tools/objtool/include/objtool/objtool.h b/tools/objtool/includ= e/objtool/objtool.h index e00c8dcc6885..6375566bb78b 100644 --- a/tools/objtool/include/objtool/objtool.h +++ b/tools/objtool/include/objtool/objtool.h @@ -46,5 +46,6 @@ int check(struct objtool_file *file); int orc_dump(const char *objname); int orc_create(struct objtool_file *file); int fpv_decode(struct objtool_file *file); +bool orc_ignore_section(struct section *sec); =20 #endif /* _OBJTOOL_H */ diff --git a/tools/objtool/insn.c b/tools/objtool/insn.c index 669fca9b8e0d..f2a386bbd4b8 100644 --- a/tools/objtool/insn.c +++ b/tools/objtool/insn.c @@ -175,3 +175,23 @@ struct reloc *insn_reloc(struct objtool_file *file, st= ruct instruction *insn) =20 return insn->reloc; } + +/* + * This is a hack for Clang. Clang is aggressive about removing section + * symbols and then some. If we cannot find something to relocate an + * instruction against, we must not generate CFI for it or the ORC + * generation will fail later. + */ +bool insn_can_reloc(struct instruction *insn) +{ + struct section *insn_sec =3D insn->sec; + unsigned long insn_off =3D insn->offset; + + if (insn_sec->sym || + find_symbol_containing(insn_sec, insn_off) || + find_symbol_containing(insn_sec, insn_off - 1)) { + /* See elf_add_reloc_to_insn(). */ + return true; + } + return false; +} diff --git a/tools/objtool/orc_gen.c b/tools/objtool/orc_gen.c index ea2e361ff7bc..bddf5889466f 100644 --- a/tools/objtool/orc_gen.c +++ b/tools/objtool/orc_gen.c @@ -14,6 +14,11 @@ #include #include =20 +bool __weak orc_ignore_section(struct section *sec) +{ + return false; +} + static int write_orc_entry(struct elf *elf, struct section *orc_sec, struct section *ip_sec, unsigned int idx, struct section *insn_sec, unsigned long insn_off, @@ -87,13 +92,16 @@ int orc_create(struct objtool_file *file) struct instruction *insn; bool empty =3D true; =20 - if (!sec->text) + if (!sec->text || orc_ignore_section(sec)) continue; =20 sec_for_each_insn(file, sec, insn) { struct alt_group *alt_group =3D insn->alt_group; int i; =20 + if (!insn_can_reloc(insn)) + continue; + if (!alt_group) { if (init_orc_entry(&orc, insn->cfi, insn)) return -1; @@ -137,7 +145,7 @@ int orc_create(struct objtool_file *file) } =20 /* Add a section terminator */ - if (!empty) { + if (!empty && sec->sym) { orc_list_add(&orc_list, &null, sec, sec->sh.sh_size); nr++; } diff --git a/tools/objtool/sync-check.sh b/tools/objtool/sync-check.sh index ef1acb064605..0d0656f6ce4a 100755 --- a/tools/objtool/sync-check.sh +++ b/tools/objtool/sync-check.sh @@ -29,6 +29,13 @@ arch/x86/lib/insn.c ' fi =20 +if [ "$SRCARCH" =3D "arm64" ]; then +FILES=3D"$FILES +arch/arm64/include/asm/orc_types.h +include/linux/orc_entry.h +" +fi + check_2 () { file1=3D$1 file2=3D$2 --=20 2.25.1 From nobody Tue Apr 23 06:20:23 2024 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 910EEC433F5 for ; Tue, 24 May 2022 00:18:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231901AbiEXASG (ORCPT ); Mon, 23 May 2022 20:18:06 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59752 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231893AbiEXARH (ORCPT ); Mon, 23 May 2022 20:17:07 -0400 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 8FFA073574; Mon, 23 May 2022 17:17:00 -0700 (PDT) Received: from x64host.home (unknown [47.189.24.195]) by linux.microsoft.com (Postfix) with ESMTPSA id 840CD20B8968; Mon, 23 May 2022 17:16:59 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 840CD20B8968 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1653351420; bh=L/zVpQucNi7H5ecmmGZpBtWf3xyfz9caTMZwGZoyPb8=; h=From:To:Subject:Date:In-Reply-To:References:From; b=SCsal7wIoTOh0RTw4YSmNL6lsw6JYsOoXBp2B84WHf60eScEGnfiLPENyQW0TbnBF uCkG3E+ZnohnDGWGv/gmBU5Y0k/tr27GKAM/OyvN0h9KtFifJusnJzdZ0YzIVTjb40 CCx4NNCfGg71eK/I099mC1w6dWDf5zWqXgGjqKL4= From: madvenka@linux.microsoft.com To: jpoimboe@redhat.com, peterz@infradead.org, chenzhongjin@huawei.com, mark.rutland@arm.com, broonie@kernel.org, nobuta.keiya@fujitsu.com, sjitindarsingh@gmail.com, catalin.marinas@arm.com, will@kernel.org, jamorris@linux.microsoft.com, linux-arm-kernel@lists.infradead.org, live-patching@vger.kernel.org, linux-kernel@vger.kernel.org, madvenka@linux.microsoft.com Subject: [RFC PATCH v2 13/20] objtool: arm64: Dump ORC data present in object files Date: Mon, 23 May 2022 19:16:30 -0500 Message-Id: <20220524001637.1707472-14-madvenka@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220524001637.1707472-1-madvenka@linux.microsoft.com> References: <20220524001637.1707472-1-madvenka@linux.microsoft.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: "Madhavan T. Venkataraman" Call orc_dump() from cmd_fpv() to dump the ORC sections in an object file. This is for debug purposes. Signed-off-by: Madhavan T. Venkataraman --- tools/objtool/Build | 1 + tools/objtool/builtin-fpv.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/tools/objtool/Build b/tools/objtool/Build index 5de79c76f3f0..d40ee95039cf 100644 --- a/tools/objtool/Build +++ b/tools/objtool/Build @@ -20,6 +20,7 @@ objtool-$(SUBCMD_FPV) +=3D cfi.o objtool-$(SUBCMD_FPV) +=3D insn.o objtool-$(SUBCMD_FPV) +=3D decode.o objtool-$(SUBCMD_FPV) +=3D orc_gen.o +objtool-$(SUBCMD_FPV) +=3D orc_dump.o =20 objtool-y +=3D builtin-check.o objtool-y +=3D builtin-orc.o diff --git a/tools/objtool/builtin-fpv.c b/tools/objtool/builtin-fpv.c index bc8f88f204b5..7934c569e60a 100644 --- a/tools/objtool/builtin-fpv.c +++ b/tools/objtool/builtin-fpv.c @@ -19,6 +19,7 @@ =20 static const char * const fpv_usage[] =3D { "objtool fpv generate file.o", + "objtool fpv dump file.o", NULL, }; =20 @@ -69,6 +70,9 @@ int cmd_fpv(int argc, const char **argv) return elf_write(file->elf); } =20 + if (!strcmp(argv[0], "dump")) + return orc_dump(objname); + usage_with_options(fpv_usage, fpv_options); =20 return 0; --=20 2.25.1 From nobody Tue Apr 23 06:20:23 2024 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E20C2C433EF for ; Tue, 24 May 2022 00:18:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232156AbiEXASP (ORCPT ); Mon, 23 May 2022 20:18:15 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59744 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231922AbiEXARH (ORCPT ); Mon, 23 May 2022 20:17:07 -0400 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id B0DD0880DF; Mon, 23 May 2022 17:17:01 -0700 (PDT) Received: from x64host.home (unknown [47.189.24.195]) by linux.microsoft.com (Postfix) with ESMTPSA id 8477D20B71D5; Mon, 23 May 2022 17:17:00 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 8477D20B71D5 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1653351421; bh=h2BRZVfqw9e4ZLjkYIMOXm6ORlgnxhf1dKgvX5B6Qfk=; h=From:To:Subject:Date:In-Reply-To:References:From; b=eWWAIR0crFm1ImkNRj3/EvKHk/8ZsWs1Wl26TlJ6GKSxhomuoBentuNI2GAVBasJK WgLvyRwsVOBSOkdZeTVyNSo4uDGKvbgV9xuc1TAynForPTj/5/l98+vvxgJ9+QNNur 68deLiw4HismEjRk1sihGH5ciaG7ucfamQOKgb0Y= From: madvenka@linux.microsoft.com To: jpoimboe@redhat.com, peterz@infradead.org, chenzhongjin@huawei.com, mark.rutland@arm.com, broonie@kernel.org, nobuta.keiya@fujitsu.com, sjitindarsingh@gmail.com, catalin.marinas@arm.com, will@kernel.org, jamorris@linux.microsoft.com, linux-arm-kernel@lists.infradead.org, live-patching@vger.kernel.org, linux-kernel@vger.kernel.org, madvenka@linux.microsoft.com Subject: [RFC PATCH v2 14/20] objtool: arm64: Add unwind hint support Date: Mon, 23 May 2022 19:16:31 -0500 Message-Id: <20220524001637.1707472-15-madvenka@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220524001637.1707472-1-madvenka@linux.microsoft.com> References: <20220524001637.1707472-1-madvenka@linux.microsoft.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: "Madhavan T. Venkataraman" Implement the unwind hint macros for ARM64. Define the unwind hint types as well. Process the unwind hints section for dynamic FP validation for ARM64. Signed-off-by: Madhavan T. Venkataraman --- arch/arm64/include/asm/unwind_hints.h | 104 ++++++++++++++++++++ include/linux/objtool.h | 6 ++ tools/arch/arm64/include/asm/unwind_hints.h | 104 ++++++++++++++++++++ tools/include/linux/objtool.h | 6 ++ tools/objtool/Build | 1 + tools/objtool/arch/arm64/decode.c | 20 ++++ tools/objtool/arch/arm64/orc.c | 6 ++ tools/objtool/fpv.c | 4 + tools/objtool/include/objtool/endianness.h | 1 + tools/objtool/sync-check.sh | 1 + tools/objtool/unwind_hints.c | 16 +-- 11 files changed, 263 insertions(+), 6 deletions(-) create mode 100644 arch/arm64/include/asm/unwind_hints.h create mode 100644 tools/arch/arm64/include/asm/unwind_hints.h diff --git a/arch/arm64/include/asm/unwind_hints.h b/arch/arm64/include/asm= /unwind_hints.h new file mode 100644 index 000000000000..fb1b924d85bc --- /dev/null +++ b/arch/arm64/include/asm/unwind_hints.h @@ -0,0 +1,104 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef _ASM_ARM64_UNWIND_HINTS_H +#define _ASM_ARM64_UNWIND_HINTS_H + +#ifndef __ASSEMBLY__ + +#include + +/* + * This struct is used by asm and inline asm code to manually annotate the + * CFI for an instruction. We have to use s16 instead of s8 for some of th= ese + * fields as 8-bit fields are not relocated by some assemblers. + */ +struct unwind_hint { + u32 ip; + s16 sp_offset; + s16 sp_reg; + s16 type; + s16 end; +}; + +#endif + +#include + +#include "orc_types.h" + +#ifdef CONFIG_STACK_VALIDATION + +#ifndef __ASSEMBLY__ + +#define UNWIND_HINT(sp_reg, sp_offset, type, end) \ + "987: \n\t" \ + ".pushsection .discard.unwind_hints\n\t" \ + /* struct unwind_hint */ \ + ".long 987b - .\n\t" \ + ".short " __stringify(sp_offset) "\n\t" \ + ".short " __stringify(sp_reg) "\n\t" \ + ".short " __stringify(type) "\n\t" \ + ".short " __stringify(end) "\n\t" \ + ".popsection\n\t" + +#else /* __ASSEMBLY__ */ + +/* + * There are points in ASM code where it is useful to unwind through even + * though the ASM code itself may be unreliable from an unwind perspective. + * E.g., interrupt and exception handlers. + * + * These macros provide hints to objtool to compute the CFI information at + * such instructions. + */ +.macro UNWIND_HINT sp_reg:req sp_offset=3D0 type:req end=3D0 +.Lunwind_hint_pc_\@: + .pushsection .discard.unwind_hints + /* struct unwind_hint */ + .long .Lunwind_hint_pc_\@ - . + .short \sp_offset + .short \sp_reg + .short \type + .short \end + .popsection +.endm + +#endif /* __ASSEMBLY__ */ + +#else /* !CONFIG_STACK_VALIDATION */ + +#ifndef __ASSEMBLY__ + +#define UNWIND_HINT(sp_reg, sp_offset, type, end) \ + "\n\t" +#else +.macro UNWIND_HINT sp_reg:req sp_offset=3D0 type:req end=3D0 +.endm +#endif + +#endif /* CONFIG_STACK_VALIDATION */ +#ifdef __ASSEMBLY__ + +.macro UNWIND_HINT_FTRACE, offset + .set sp_reg, ORC_REG_SP + .set sp_offset, \offset + .set type, UNWIND_HINT_TYPE_FTRACE + UNWIND_HINT sp_reg=3Dsp_reg sp_offset=3Dsp_offset type=3Dtype +.endm + +.macro UNWIND_HINT_REGS, offset + .set sp_reg, ORC_REG_SP + .set sp_offset, \offset + .set type, UNWIND_HINT_TYPE_REGS + UNWIND_HINT sp_reg=3Dsp_reg sp_offset=3Dsp_offset type=3Dtype +.endm + +.macro UNWIND_HINT_IRQ, offset + .set sp_reg, ORC_REG_SP + .set sp_offset, \offset + .set type, UNWIND_HINT_TYPE_IRQ_STACK + UNWIND_HINT sp_reg=3Dsp_reg sp_offset=3Dsp_offset type=3Dtype +.endm + +#endif /* __ASSEMBLY__ */ + +#endif /* _ASM_ARM64_UNWIND_HINTS_H */ diff --git a/include/linux/objtool.h b/include/linux/objtool.h index 00bb449777d0..c28e3cff3b83 100644 --- a/include/linux/objtool.h +++ b/include/linux/objtool.h @@ -15,11 +15,17 @@ * * UNWIND_HINT_FUNC: Generate the unwind metadata of a callable function. * Useful for code which doesn't have an ELF function annotation. + * + * UNWIND_HINT_TYPE_FTRACE: Used to unwind through an ftrace callsite. + * + * UNWIND_HINT_TYPE_IRQ_STACK: Used to unwind through the IRQ stack. */ #define UNWIND_HINT_TYPE_CALL 0 #define UNWIND_HINT_TYPE_REGS 1 #define UNWIND_HINT_TYPE_REGS_PARTIAL 2 #define UNWIND_HINT_TYPE_FUNC 3 +#define UNWIND_HINT_TYPE_FTRACE 4 +#define UNWIND_HINT_TYPE_IRQ_STACK 5 =20 #ifdef CONFIG_STACK_VALIDATION =20 diff --git a/tools/arch/arm64/include/asm/unwind_hints.h b/tools/arch/arm64= /include/asm/unwind_hints.h new file mode 100644 index 000000000000..fb1b924d85bc --- /dev/null +++ b/tools/arch/arm64/include/asm/unwind_hints.h @@ -0,0 +1,104 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef _ASM_ARM64_UNWIND_HINTS_H +#define _ASM_ARM64_UNWIND_HINTS_H + +#ifndef __ASSEMBLY__ + +#include + +/* + * This struct is used by asm and inline asm code to manually annotate the + * CFI for an instruction. We have to use s16 instead of s8 for some of th= ese + * fields as 8-bit fields are not relocated by some assemblers. + */ +struct unwind_hint { + u32 ip; + s16 sp_offset; + s16 sp_reg; + s16 type; + s16 end; +}; + +#endif + +#include + +#include "orc_types.h" + +#ifdef CONFIG_STACK_VALIDATION + +#ifndef __ASSEMBLY__ + +#define UNWIND_HINT(sp_reg, sp_offset, type, end) \ + "987: \n\t" \ + ".pushsection .discard.unwind_hints\n\t" \ + /* struct unwind_hint */ \ + ".long 987b - .\n\t" \ + ".short " __stringify(sp_offset) "\n\t" \ + ".short " __stringify(sp_reg) "\n\t" \ + ".short " __stringify(type) "\n\t" \ + ".short " __stringify(end) "\n\t" \ + ".popsection\n\t" + +#else /* __ASSEMBLY__ */ + +/* + * There are points in ASM code where it is useful to unwind through even + * though the ASM code itself may be unreliable from an unwind perspective. + * E.g., interrupt and exception handlers. + * + * These macros provide hints to objtool to compute the CFI information at + * such instructions. + */ +.macro UNWIND_HINT sp_reg:req sp_offset=3D0 type:req end=3D0 +.Lunwind_hint_pc_\@: + .pushsection .discard.unwind_hints + /* struct unwind_hint */ + .long .Lunwind_hint_pc_\@ - . + .short \sp_offset + .short \sp_reg + .short \type + .short \end + .popsection +.endm + +#endif /* __ASSEMBLY__ */ + +#else /* !CONFIG_STACK_VALIDATION */ + +#ifndef __ASSEMBLY__ + +#define UNWIND_HINT(sp_reg, sp_offset, type, end) \ + "\n\t" +#else +.macro UNWIND_HINT sp_reg:req sp_offset=3D0 type:req end=3D0 +.endm +#endif + +#endif /* CONFIG_STACK_VALIDATION */ +#ifdef __ASSEMBLY__ + +.macro UNWIND_HINT_FTRACE, offset + .set sp_reg, ORC_REG_SP + .set sp_offset, \offset + .set type, UNWIND_HINT_TYPE_FTRACE + UNWIND_HINT sp_reg=3Dsp_reg sp_offset=3Dsp_offset type=3Dtype +.endm + +.macro UNWIND_HINT_REGS, offset + .set sp_reg, ORC_REG_SP + .set sp_offset, \offset + .set type, UNWIND_HINT_TYPE_REGS + UNWIND_HINT sp_reg=3Dsp_reg sp_offset=3Dsp_offset type=3Dtype +.endm + +.macro UNWIND_HINT_IRQ, offset + .set sp_reg, ORC_REG_SP + .set sp_offset, \offset + .set type, UNWIND_HINT_TYPE_IRQ_STACK + UNWIND_HINT sp_reg=3Dsp_reg sp_offset=3Dsp_offset type=3Dtype +.endm + +#endif /* __ASSEMBLY__ */ + +#endif /* _ASM_ARM64_UNWIND_HINTS_H */ diff --git a/tools/include/linux/objtool.h b/tools/include/linux/objtool.h index 00bb449777d0..c28e3cff3b83 100644 --- a/tools/include/linux/objtool.h +++ b/tools/include/linux/objtool.h @@ -15,11 +15,17 @@ * * UNWIND_HINT_FUNC: Generate the unwind metadata of a callable function. * Useful for code which doesn't have an ELF function annotation. + * + * UNWIND_HINT_TYPE_FTRACE: Used to unwind through an ftrace callsite. + * + * UNWIND_HINT_TYPE_IRQ_STACK: Used to unwind through the IRQ stack. */ #define UNWIND_HINT_TYPE_CALL 0 #define UNWIND_HINT_TYPE_REGS 1 #define UNWIND_HINT_TYPE_REGS_PARTIAL 2 #define UNWIND_HINT_TYPE_FUNC 3 +#define UNWIND_HINT_TYPE_FTRACE 4 +#define UNWIND_HINT_TYPE_IRQ_STACK 5 =20 #ifdef CONFIG_STACK_VALIDATION =20 diff --git a/tools/objtool/Build b/tools/objtool/Build index d40ee95039cf..4a57d7c7d31e 100644 --- a/tools/objtool/Build +++ b/tools/objtool/Build @@ -19,6 +19,7 @@ objtool-$(SUBCMD_FPV) +=3D fpv.o objtool-$(SUBCMD_FPV) +=3D cfi.o objtool-$(SUBCMD_FPV) +=3D insn.o objtool-$(SUBCMD_FPV) +=3D decode.o +objtool-$(SUBCMD_FPV) +=3D unwind_hints.o objtool-$(SUBCMD_FPV) +=3D orc_gen.o objtool-$(SUBCMD_FPV) +=3D orc_dump.o =20 diff --git a/tools/objtool/arch/arm64/decode.c b/tools/objtool/arch/arm64/d= ecode.c index 93ef7c0811f1..d3c650ca044e 100644 --- a/tools/objtool/arch/arm64/decode.c +++ b/tools/objtool/arch/arm64/decode.c @@ -15,6 +15,7 @@ #include #include #include +#include =20 /* ARM64 instructions are all 4 bytes wide. */ #define INSN_SIZE 4 @@ -60,6 +61,25 @@ unsigned long arch_jump_destination(struct instruction *= insn) return insn->offset + insn->immediate; } =20 +int arch_decode_hint_reg(u8 sp_reg, int *base) +{ + switch (sp_reg) { + case ORC_REG_UNDEFINED: + *base =3D CFI_UNDEFINED; + break; + case ORC_REG_SP: + *base =3D CFI_SP; + break; + case ORC_REG_FP: + *base =3D CFI_FP; + break; + default: + return -1; + } + + return 0; +} + /* --------------------- miscellaneous functions -------------------------= -- */ =20 static void reg_check(unsigned int sp_check, unsigned int fp_check, diff --git a/tools/objtool/arch/arm64/orc.c b/tools/objtool/arch/arm64/orc.c index cef14114e1ec..fecbed12b3f1 100644 --- a/tools/objtool/arch/arm64/orc.c +++ b/tools/objtool/arch/arm64/orc.c @@ -57,6 +57,12 @@ const char *orc_type_name(unsigned int type) switch (type) { case UNWIND_HINT_TYPE_CALL: return "call"; + case UNWIND_HINT_TYPE_REGS: + return "regs"; + case UNWIND_HINT_TYPE_FTRACE: + return "ftrace"; + case UNWIND_HINT_TYPE_IRQ_STACK: + return "irqstack"; default: return "?"; } diff --git a/tools/objtool/fpv.c b/tools/objtool/fpv.c index 52f613ae998f..346e0de787f3 100644 --- a/tools/objtool/fpv.c +++ b/tools/objtool/fpv.c @@ -257,6 +257,10 @@ int fpv_decode(struct objtool_file *file) =20 add_jump_destinations(file); =20 + ret =3D read_unwind_hints(file); + if (ret) + return ret; + if (!list_empty(&file->insn_list)) { fill =3D false; walk_sections(file); diff --git a/tools/objtool/include/objtool/endianness.h b/tools/objtool/inc= lude/objtool/endianness.h index 10241341eff3..9a53ab421a19 100644 --- a/tools/objtool/include/objtool/endianness.h +++ b/tools/objtool/include/objtool/endianness.h @@ -29,6 +29,7 @@ case 8: __ret =3D __NEED_BSWAP ? bswap_64(val) : (val); break; \ case 4: __ret =3D __NEED_BSWAP ? bswap_32(val) : (val); break; \ case 2: __ret =3D __NEED_BSWAP ? bswap_16(val) : (val); break; \ + case 1: __ret =3D (val); break; \ default: \ BUILD_BUG(); break; \ } \ diff --git a/tools/objtool/sync-check.sh b/tools/objtool/sync-check.sh index 0d0656f6ce4a..3742d1e2585c 100755 --- a/tools/objtool/sync-check.sh +++ b/tools/objtool/sync-check.sh @@ -31,6 +31,7 @@ fi =20 if [ "$SRCARCH" =3D "arm64" ]; then FILES=3D"$FILES +arch/arm64/include/asm/unwind_hints.h arch/arm64/include/asm/orc_types.h include/linux/orc_entry.h " diff --git a/tools/objtool/unwind_hints.c b/tools/objtool/unwind_hints.c index d4e41c67403b..91ceea3f7fd7 100644 --- a/tools/objtool/unwind_hints.c +++ b/tools/objtool/unwind_hints.c @@ -16,6 +16,7 @@ int read_unwind_hints(struct objtool_file *file) struct unwind_hint *hint; struct instruction *insn; struct reloc *reloc; + u8 sp_reg, type; int i; =20 sec =3D find_section_by_name(file->elf, ".discard.unwind_hints"); @@ -38,6 +39,9 @@ int read_unwind_hints(struct objtool_file *file) for (i =3D 0; i < sec->sh.sh_size / sizeof(struct unwind_hint); i++) { hint =3D (struct unwind_hint *)sec->data->d_buf + i; =20 + sp_reg =3D bswap_if_needed(hint->sp_reg); + type =3D bswap_if_needed(hint->type); + reloc =3D find_reloc_by_dest(file->elf, sec, i * sizeof(*hint)); if (!reloc) { WARN("can't find reloc for unwind_hints[%d]", i); @@ -52,7 +56,7 @@ int read_unwind_hints(struct objtool_file *file) =20 insn->hint =3D true; =20 - if (ibt && hint->type =3D=3D UNWIND_HINT_TYPE_REGS_PARTIAL) { + if (ibt && type =3D=3D UNWIND_HINT_TYPE_REGS_PARTIAL) { struct symbol *sym =3D find_symbol_by_offset(insn->sec, insn->offset); =20 if (sym && sym->bind =3D=3D STB_GLOBAL && @@ -62,7 +66,7 @@ int read_unwind_hints(struct objtool_file *file) } } =20 - if (hint->type =3D=3D UNWIND_HINT_TYPE_FUNC) { + if (type =3D=3D UNWIND_HINT_TYPE_FUNC) { insn->cfi =3D &func_cfi; continue; } @@ -70,15 +74,15 @@ int read_unwind_hints(struct objtool_file *file) if (insn->cfi) cfi =3D *(insn->cfi); =20 - if (arch_decode_hint_reg(hint->sp_reg, &cfi.cfa.base)) { + if (arch_decode_hint_reg(sp_reg, &cfi.cfa.base)) { WARN_FUNC("unsupported unwind_hint sp base reg %d", - insn->sec, insn->offset, hint->sp_reg); + insn->sec, insn->offset, sp_reg); return -1; } =20 cfi.cfa.offset =3D bswap_if_needed(hint->sp_offset); - cfi.type =3D hint->type; - cfi.end =3D hint->end; + cfi.type =3D type; + cfi.end =3D bswap_if_needed(hint->end); =20 insn->cfi =3D cfi_hash_find_or_add(&cfi); } --=20 2.25.1 From nobody Tue Apr 23 06:20:23 2024 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C7723C433F5 for ; Tue, 24 May 2022 00:18:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230153AbiEXAST (ORCPT ); Mon, 23 May 2022 20:18:19 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59748 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231992AbiEXARM (ORCPT ); Mon, 23 May 2022 20:17:12 -0400 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 15FA98AE41; Mon, 23 May 2022 17:17:02 -0700 (PDT) Received: from x64host.home (unknown [47.189.24.195]) by linux.microsoft.com (Postfix) with ESMTPSA id 8504120B6C7C; Mon, 23 May 2022 17:17:01 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 8504120B6C7C DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1653351422; bh=i38XBmt03Yj6P5EVI/Y5EXfzyY4okm3GZVL0Cbb4zHY=; h=From:To:Subject:Date:In-Reply-To:References:From; b=sfxAzXRMl11Qrr1SKOR9ea5oIJHGiWhdgsHqPPqFKf4ahKkqKBeISs0qQ+OmR29h8 AZvThfbgfBLg44ZxabgwLCB02mOch/EQ906C5w3Hx97du/aAmRSz0kLoAXT96QHk/Z EanZbUxltHcUVXXSzqnCJ7aQSRevWF4q56vT0qJ4= From: madvenka@linux.microsoft.com To: jpoimboe@redhat.com, peterz@infradead.org, chenzhongjin@huawei.com, mark.rutland@arm.com, broonie@kernel.org, nobuta.keiya@fujitsu.com, sjitindarsingh@gmail.com, catalin.marinas@arm.com, will@kernel.org, jamorris@linux.microsoft.com, linux-arm-kernel@lists.infradead.org, live-patching@vger.kernel.org, linux-kernel@vger.kernel.org, madvenka@linux.microsoft.com Subject: [RFC PATCH v2 15/20] arm64: Add unwind hints to specific points in code Date: Mon, 23 May 2022 19:16:32 -0500 Message-Id: <20220524001637.1707472-16-madvenka@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220524001637.1707472-1-madvenka@linux.microsoft.com> References: <20220524001637.1707472-1-madvenka@linux.microsoft.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: "Madhavan T. Venkataraman" Add unwind hints to the following: - Ftrace entry code - Interrupt and Exception handlers - Kretprobe trampoline Signed-off-by: Madhavan T. Venkataraman --- arch/arm64/kernel/entry-ftrace.S | 23 +++++++++++++++++++ arch/arm64/kernel/entry.S | 3 +++ arch/arm64/kernel/probes/kprobes_trampoline.S | 3 +++ 3 files changed, 29 insertions(+) diff --git a/arch/arm64/kernel/entry-ftrace.S b/arch/arm64/kernel/entry-ftr= ace.S index e535480a4069..6d68833e8cec 100644 --- a/arch/arm64/kernel/entry-ftrace.S +++ b/arch/arm64/kernel/entry-ftrace.S @@ -11,6 +11,7 @@ #include #include #include +#include =20 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS /* @@ -95,7 +96,14 @@ SYM_CODE_START(ftrace_common) mov x3, sp // regs =20 SYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL) + /* + * Tracer functions are patched at ftrace_stub. Stack traces + * taken from tracer functions will end up here. Place an + * unwind hint based on the stackframe setup in ftrace_regs_entry. + */ bl ftrace_stub +SYM_INNER_LABEL(ftrace_call_entry, SYM_L_GLOBAL) + UNWIND_HINT_REGS PT_REGS_SIZE =20 #ifdef CONFIG_FUNCTION_GRAPH_TRACER SYM_INNER_LABEL(ftrace_graph_call, SYM_L_GLOBAL) // ftrace_graph_caller(); @@ -134,10 +142,25 @@ SYM_CODE_START(ftrace_graph_caller) add x1, sp, #S_LR // parent_ip (callsite's LR) ldr x2, [sp, #PT_REGS_SIZE] // parent fp (callsite's FP) bl prepare_ftrace_return +SYM_INNER_LABEL(ftrace_graph_caller_entry, SYM_L_GLOBAL) + UNWIND_HINT_REGS PT_REGS_SIZE b ftrace_common_return SYM_CODE_END(ftrace_graph_caller) #endif =20 +/* + * ftrace_regs_entry() sets up two stackframes - one for the callsite and + * one for the ftrace entry code. Unwind hints have been placed for the + * ftrace entry code above. We need an unwind hint for the callsite. Calls= ites + * are numerous. But the unwind hint required for all the callsites is the + * same. Define a dummy function here with the callsite unwind hint for the + * benefit of the unwinder. + */ +SYM_CODE_START(ftrace_callsite) + UNWIND_HINT_FTRACE 16 // for the callsite + ret +SYM_CODE_END(ftrace_callsite) + #else /* CONFIG_DYNAMIC_FTRACE_WITH_REGS */ =20 /* diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index ede028dee81b..95d5f3c08aa1 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -28,6 +28,7 @@ #include #include #include +#include =20 .macro clear_gp_regs .irp n,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,2= 5,26,27,28,29 @@ -560,6 +561,7 @@ SYM_CODE_START_LOCAL(el\el\ht\()_\regsize\()_\label) .if \el =3D=3D 0 b ret_to_user .else + UNWIND_HINT_REGS PT_REGS_SIZE b ret_to_kernel .endif SYM_CODE_END(el\el\ht\()_\regsize\()_\label) @@ -894,6 +896,7 @@ SYM_FUNC_START(call_on_irq_stack) /* Move to the new stack and call the function there */ mov sp, x16 blr x1 + UNWIND_HINT_IRQ 16 =20 /* * Restore the SP from the FP, and restore the FP and LR from the frame diff --git a/arch/arm64/kernel/probes/kprobes_trampoline.S b/arch/arm64/ker= nel/probes/kprobes_trampoline.S index 9a6499bed58b..847cbb81ca33 100644 --- a/arch/arm64/kernel/probes/kprobes_trampoline.S +++ b/arch/arm64/kernel/probes/kprobes_trampoline.S @@ -6,6 +6,7 @@ #include #include #include +#include =20 .text =20 @@ -71,6 +72,8 @@ SYM_CODE_START(__kretprobe_trampoline) =20 mov x0, sp bl trampoline_probe_handler + UNWIND_HINT_REGS PT_REGS_SIZE + /* * Replace trampoline address in lr with actual orig_ret_addr return * address. --=20 2.25.1 From nobody Tue Apr 23 06:20:23 2024 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 099A1C433F5 for ; Tue, 24 May 2022 00:18:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231993AbiEXASY (ORCPT ); Mon, 23 May 2022 20:18:24 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60162 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231890AbiEXARM (ORCPT ); Mon, 23 May 2022 20:17:12 -0400 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id EC51E8FD62; Mon, 23 May 2022 17:17:03 -0700 (PDT) Received: from x64host.home (unknown [47.189.24.195]) by linux.microsoft.com (Postfix) with ESMTPSA id 860F520B87F3; Mon, 23 May 2022 17:17:02 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 860F520B87F3 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1653351423; bh=noSnCslKB9fq6Jf14ZT65t1WySif9JO6D3Dr/3SMpII=; h=From:To:Subject:Date:In-Reply-To:References:From; b=a6zAzEx/ijezFj5miAVlU0T+oHhC3mhtty4wPz5a2txcX8dCzGuYWO5BmypAhLcDz pfmjTlOHui8ZtBFm3whzL6Pu1pFdgPbEXj+TC8Ozg2rWLpR/549XSTj5MApKh2aTjK t1mDUmpa6P++0NrSzoCjr6EvQY9fBmCt/ir2FZEA= From: madvenka@linux.microsoft.com To: jpoimboe@redhat.com, peterz@infradead.org, chenzhongjin@huawei.com, mark.rutland@arm.com, broonie@kernel.org, nobuta.keiya@fujitsu.com, sjitindarsingh@gmail.com, catalin.marinas@arm.com, will@kernel.org, jamorris@linux.microsoft.com, linux-arm-kernel@lists.infradead.org, live-patching@vger.kernel.org, linux-kernel@vger.kernel.org, madvenka@linux.microsoft.com Subject: [RFC PATCH v2 16/20] arm64: Add kernel and module support for ORC Date: Mon, 23 May 2022 19:16:33 -0500 Message-Id: <20220524001637.1707472-17-madvenka@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220524001637.1707472-1-madvenka@linux.microsoft.com> References: <20220524001637.1707472-1-madvenka@linux.microsoft.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: "Madhavan T. Venkataraman" Call orc_lookup_init() from setup_arch() to perform ORC lookup initialization for vmlinux. Call orc_lookup_module_init() in module load to perform ORC lookup initialization for modules. Signed-off-by: Madhavan T. Venkataraman --- arch/arm64/kernel/module.c | 13 ++++++++++++- arch/arm64/kernel/setup.c | 2 ++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kernel/module.c b/arch/arm64/kernel/module.c index f2d4bb14bfab..d5ca2fa13156 100644 --- a/arch/arm64/kernel/module.c +++ b/arch/arm64/kernel/module.c @@ -19,6 +19,7 @@ #include #include #include +#include =20 void *module_alloc(unsigned long size) { @@ -524,10 +525,20 @@ int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, struct module *me) { - const Elf_Shdr *s; + const Elf_Shdr *s, *orc, *orc_ip; + s =3D find_section(hdr, sechdrs, ".altinstructions"); if (s) apply_alternatives_module((void *)s->sh_addr, s->sh_size); =20 + orc =3D find_section(hdr, sechdrs, ".orc_unwind"); + orc_ip =3D find_section(hdr, sechdrs, ".orc_unwind_ip"); + + if (orc && orc_ip) { + orc_lookup_module_init(me, + (void *)orc_ip->sh_addr, orc_ip->sh_size, + (void *)orc->sh_addr, orc->sh_size); + } + return module_init_ftrace_plt(hdr, sechdrs, me); } diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 3505789cf4bd..9094b941f6ed 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -51,6 +51,7 @@ #include #include #include +#include =20 static int num_standard_resources; static struct resource *standard_resources; @@ -389,6 +390,7 @@ void __init __no_sanitize_address setup_arch(char **cmd= line_p) "This indicates a broken bootloader or old kernel\n", boot_args[1], boot_args[2], boot_args[3]); } + orc_lookup_init(); } =20 static inline bool cpu_can_disable(unsigned int cpu) --=20 2.25.1 From nobody Tue Apr 23 06:20:23 2024 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id DBA25C433F5 for ; Tue, 24 May 2022 00:18:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232211AbiEXASv (ORCPT ); Mon, 23 May 2022 20:18:51 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60178 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232034AbiEXARM (ORCPT ); Mon, 23 May 2022 20:17:12 -0400 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 75BF87CB76; Mon, 23 May 2022 17:17:04 -0700 (PDT) Received: from x64host.home (unknown [47.189.24.195]) by linux.microsoft.com (Postfix) with ESMTPSA id 8601F20B87F6; Mon, 23 May 2022 17:17:03 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 8601F20B87F6 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1653351424; bh=TQ/XlAh2pJ/fVzbjSjvKssRRUWTo6FGCftijB4Zl7Mo=; h=From:To:Subject:Date:In-Reply-To:References:From; b=jJGo7xvKQqkBA7IhJFiWZkUNsWh4P/aCvBW0LfJ1s5E++6pqNlCQIinQQufRHbJ/R JFKvvdos2IVRf5OiQTK3IWfUkwGAPd5kdrLoRUXUyQ7+38ETsMFFE5YASUA7Lj66H4 z9tF0wuxsuTgupj5+HIRtvglb3vUj4imzq612COw= From: madvenka@linux.microsoft.com To: jpoimboe@redhat.com, peterz@infradead.org, chenzhongjin@huawei.com, mark.rutland@arm.com, broonie@kernel.org, nobuta.keiya@fujitsu.com, sjitindarsingh@gmail.com, catalin.marinas@arm.com, will@kernel.org, jamorris@linux.microsoft.com, linux-arm-kernel@lists.infradead.org, live-patching@vger.kernel.org, linux-kernel@vger.kernel.org, madvenka@linux.microsoft.com Subject: [RFC PATCH v2 17/20] arm64: Build the kernel with ORC information Date: Mon, 23 May 2022 19:16:34 -0500 Message-Id: <20220524001637.1707472-18-madvenka@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220524001637.1707472-1-madvenka@linux.microsoft.com> References: <20220524001637.1707472-1-madvenka@linux.microsoft.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: "Madhavan T. Venkataraman" Define CONFIG_UNWINDER_ORC - to include ORC lookup code in the kernel. Define CONFIG_FRAME_POINTER_VALIDATION - to enable ORC based FP validation. Select CONFIG_HAVE_STACK_VALIDATION if CONFIG_FRAME_POINTER_VALIDATION is present. Add code to scripts/Makefile.build to define objtool options to generate ORC data for frame pointer validation. When these configs are enabled, CONFIG_STACK_VALIDATION can be enabled. When that is done, invoke objtool on relocatable files during the kernel build with the following command: objtool fpv generate Objtool creates special sections in the object files: .orc_unwind_ip PC array. .orc_unwind ORC structure table. .orc_lookup ORC lookup table. Change arch/arm64/kernel/vmlinux.lds.S to include ORC_UNWIND_TABLE in the data section so that the special sections get included there. For modules, these sections will be added to the kernel during module load. In the future, the kernel can use these sections to find the ORC for a given instruction address. The unwinder can then compute the FP at an instruction address and validate the actual FP with that. NOTE: CONFIG_STACK_VALIDATION needs to be turned on here. Otherwise, objtool will not be invoked during the kernel build process. The actual stack validation code will be added separately. This is harmless. Signed-off-by: Madhavan T. Venkataraman --- arch/Kconfig | 4 +++- arch/arm64/Kconfig | 2 ++ arch/arm64/Kconfig.debug | 21 +++++++++++++++++++++ arch/arm64/include/asm/module.h | 10 +++++++++- arch/arm64/kernel/vmlinux.lds.S | 3 +++ scripts/Makefile | 4 +++- scripts/Makefile.build | 4 ++++ scripts/link-vmlinux.sh | 7 +++++++ 8 files changed, 52 insertions(+), 3 deletions(-) diff --git a/arch/Kconfig b/arch/Kconfig index 29b0167c088b..16eb5ad1f83e 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -1032,7 +1032,9 @@ config HAVE_STACK_VALIDATION bool help Architecture supports the 'objtool check' host tool command, which - performs compile-time stack metadata validation. + performs compile-time stack metadata validation. Or, on architectures + that use dynamic frame pointer validation, it supports the + 'objtool fpv generate' host tool command. =20 config HAVE_RELIABLE_STACKTRACE bool diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 57c4c995965f..e6a7bfc85ff9 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -223,6 +223,8 @@ config ARM64 select SWIOTLB select SYSCTL_EXCEPTION_TRACE select THREAD_INFO_IN_TASK + select HAVE_STACK_VALIDATION if FRAME_POINTER_VALIDATION + select STACK_VALIDATION if HAVE_STACK_VALIDATION select HAVE_ARCH_USERFAULTFD_MINOR if USERFAULTFD select TRACE_IRQFLAGS_SUPPORT help diff --git a/arch/arm64/Kconfig.debug b/arch/arm64/Kconfig.debug index 265c4461031f..37a7a90331d0 100644 --- a/arch/arm64/Kconfig.debug +++ b/arch/arm64/Kconfig.debug @@ -20,4 +20,25 @@ config ARM64_RELOC_TEST depends on m tristate "Relocation testing module" =20 +config UNWINDER_ORC + bool "ORC unwinder" + depends on FRAME_POINTER_VALIDATION + select HAVE_MOD_ARCH_SPECIFIC + help + This option enables ORC (Oops Rewind Capability) for ARM64. This + allows the unwinder to look up ORC data for an instruction address + and compute the frame pointer at that address. The computed frame + pointer is used to validate the actual frame pointer. + +config FRAME_POINTER_VALIDATION + bool "Dynamic Frame pointer validation" + depends on FRAME_POINTER + select UNWINDER_ORC + help + This invokes objtool on every object file causing it to + generate ORC data for the object file. ORC data is in a custom + data format which is a simplified version of the DWARF + Call Frame Information standard. See UNWINDER_ORC for more + details. + source "drivers/hwtracing/coresight/Kconfig" diff --git a/arch/arm64/include/asm/module.h b/arch/arm64/include/asm/modul= e.h index 4e7fa2623896..a15cddf11224 100644 --- a/arch/arm64/include/asm/module.h +++ b/arch/arm64/include/asm/module.h @@ -6,6 +6,7 @@ #define __ASM_MODULE_H =20 #include +#include =20 #ifdef CONFIG_ARM64_MODULE_PLTS struct mod_plt_sec { @@ -13,15 +14,22 @@ struct mod_plt_sec { int plt_num_entries; int plt_max_entries; }; +#endif =20 struct mod_arch_specific { +#ifdef CONFIG_ARM64_MODULE_PLTS struct mod_plt_sec core; struct mod_plt_sec init; =20 /* for CONFIG_DYNAMIC_FTRACE */ struct plt_entry *ftrace_trampolines; -}; #endif +#ifdef CONFIG_UNWINDER_ORC + unsigned int num_orcs; + int *orc_unwind_ip; + struct orc_entry *orc_unwind; +#endif +}; =20 u64 module_emit_plt_entry(struct module *mod, Elf64_Shdr *sechdrs, void *loc, const Elf64_Rela *rela, diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.ld= s.S index edaf0faf766f..7a4fa5404541 100644 --- a/arch/arm64/kernel/vmlinux.lds.S +++ b/arch/arm64/kernel/vmlinux.lds.S @@ -61,6 +61,7 @@ #define RUNTIME_DISCARD_EXIT =20 #include +#include #include #include #include @@ -291,6 +292,8 @@ SECTIONS __mmuoff_data_end =3D .; } =20 + ORC_UNWIND_TABLE + PECOFF_EDATA_PADDING __pecoff_data_rawsize =3D ABSOLUTE(. - __initdata_begin); _edata =3D .; diff --git a/scripts/Makefile b/scripts/Makefile index ce5aa9030b74..abcda21c1bb9 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -20,8 +20,10 @@ HOSTLDLIBS_sign-file =3D $(shell pkg-config --libs libcr= ypto 2> /dev/null || echo ifdef CONFIG_UNWINDER_ORC ifeq ($(ARCH),x86_64) ARCH :=3D x86 -endif HOSTCFLAGS_sorttable.o +=3D -I$(srctree)/tools/arch/x86/include +else +HOSTCFLAGS_sorttable.o +=3D -I$(srctree)/tools/arch/$(ARCH)/include +endif HOSTCFLAGS_sorttable.o +=3D -DUNWINDER_ORC_ENABLED endif =20 diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 9717e6f6fb31..7d370b498a6b 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -226,6 +226,9 @@ ifdef CONFIG_STACK_VALIDATION =20 objtool :=3D $(objtree)/tools/objtool/objtool =20 +ifdef CONFIG_FRAME_POINTER_VALIDATION +objtool_args =3D fpv generate +else objtool_args =3D \ $(if $(CONFIG_UNWINDER_ORC),orc generate,check) \ $(if $(part-of-module), --module) \ @@ -236,6 +239,7 @@ objtool_args =3D \ $(if $(CONFIG_X86_SMAP), --uaccess) \ $(if $(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL), --mcount) \ $(if $(CONFIG_SLS), --sls) +endif =20 cmd_objtool =3D $(if $(objtool-enabled), ; $(objtool) $(objtool_args) $@) cmd_gen_objtooldep =3D $(if $(objtool-enabled), { echo ; echo '$@: $$(wild= card $(objtool))' ; } >> $(dot-target).cmd) diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index 20f44504a644..ea0a85370e0f 100755 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh @@ -108,6 +108,13 @@ objtool_link() local objtoolcmd; local objtoolopt; =20 + if is_enabled CONFIG_STACK_VALIDATION && \ + is_enabled CONFIG_FRAME_POINTER_VALIDATION && \ + is_enabled CONFIG_LTO_CLANG; then + tools/objtool/objtool fpv generate ${1} + return + fi + if is_enabled CONFIG_STACK_VALIDATION && \ ( is_enabled CONFIG_LTO_CLANG || is_enabled CONFIG_X86_KERNEL_IBT ); t= hen =20 --=20 2.25.1 From nobody Tue Apr 23 06:20:23 2024 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 270FDC433F5 for ; Tue, 24 May 2022 00:18:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232085AbiEXAS1 (ORCPT ); Mon, 23 May 2022 20:18:27 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33504 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232076AbiEXAR2 (ORCPT ); Mon, 23 May 2022 20:17:28 -0400 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id B4CA792D12; Mon, 23 May 2022 17:17:05 -0700 (PDT) Received: from x64host.home (unknown [47.189.24.195]) by linux.microsoft.com (Postfix) with ESMTPSA id 8509520B5B4E; Mon, 23 May 2022 17:17:04 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 8509520B5B4E DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1653351425; bh=F+06QZixvxLg5mYB/7rdwOhFtinfWWMMUPEPRY4OtFI=; h=From:To:Subject:Date:In-Reply-To:References:From; b=fNUshMRvBVgso8WBJO4GkUQQK0Q8bi4QV+zVHOgHgrHmj0j+0jo9zP6py6SVb8xip fjz8QwDwctqwlJYT+ENWJT3lZZrgUpArvBvHx2po1pDhGjUVvmrLR3bfnkF2xE097s cq2Ds76QQ4c4IGWT4Sqi2kkTj0xKg50unsT0I/0Q= From: madvenka@linux.microsoft.com To: jpoimboe@redhat.com, peterz@infradead.org, chenzhongjin@huawei.com, mark.rutland@arm.com, broonie@kernel.org, nobuta.keiya@fujitsu.com, sjitindarsingh@gmail.com, catalin.marinas@arm.com, will@kernel.org, jamorris@linux.microsoft.com, linux-arm-kernel@lists.infradead.org, live-patching@vger.kernel.org, linux-kernel@vger.kernel.org, madvenka@linux.microsoft.com Subject: [RFC PATCH v2 18/20] arm64: unwinder: Add a reliability check in the unwinder based on ORC Date: Mon, 23 May 2022 19:16:35 -0500 Message-Id: <20220524001637.1707472-19-madvenka@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220524001637.1707472-1-madvenka@linux.microsoft.com> References: <20220524001637.1707472-1-madvenka@linux.microsoft.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: "Madhavan T. Venkataraman" Introduce a reliability flag in struct stackframe. This will be set to false if the PC does not have a valid ORC or if the frame pointer computed from the ORC does not match the actual frame pointer. Now that the unwinder can validate the frame pointer, introduce arch_stack_walk_reliable(). Signed-off-by: Madhavan T. Venkataraman --- arch/arm64/include/asm/stacktrace.h | 9 ++ arch/arm64/kernel/ftrace.c | 16 +++ arch/arm64/kernel/stacktrace.c | 153 ++++++++++++++++++++++++++++ include/linux/ftrace.h | 4 + 4 files changed, 182 insertions(+) diff --git a/arch/arm64/include/asm/stacktrace.h b/arch/arm64/include/asm/s= tacktrace.h index e77cdef9ca29..f5d9bbed53e6 100644 --- a/arch/arm64/include/asm/stacktrace.h +++ b/arch/arm64/include/asm/stacktrace.h @@ -44,6 +44,7 @@ struct stack_info { * @prev_fp: The fp that pointed to this frame record, or a synthetic = value * of 0. This is used to ensure that within a stack, each * subsequent frame record is at an increasing address. + * @prev_pc: The pc in the previous frame. * @prev_type: The type of stack this frame record was on, or a synthetic * value of STACK_TYPE_UNKNOWN. This is used to detect a * transition from one stack to another. @@ -51,16 +52,24 @@ struct stack_info { * @kr_cur: When KRETPROBES is selected, holds the kretprobe instance * associated with the most recently encountered replacement= lr * value. + * + * @cfa: The sp value at the call site of the current function. + * @unwind_type The previous frame's unwind type. + * @reliable: Stack trace is reliable. */ struct stackframe { unsigned long fp; unsigned long pc; DECLARE_BITMAP(stacks_done, __NR_STACK_TYPES); unsigned long prev_fp; + unsigned long prev_pc; enum stack_type prev_type; #ifdef CONFIG_KRETPROBES struct llist_node *kr_cur; #endif + unsigned long cfa; + int unwind_type; + bool reliable; }; =20 extern void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk, diff --git a/arch/arm64/kernel/ftrace.c b/arch/arm64/kernel/ftrace.c index 4506c4a90ac1..ec9a00d714e5 100644 --- a/arch/arm64/kernel/ftrace.c +++ b/arch/arm64/kernel/ftrace.c @@ -299,3 +299,19 @@ int ftrace_disable_ftrace_graph_caller(void) } #endif /* CONFIG_DYNAMIC_FTRACE */ #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ + +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS + +bool is_ftrace_entry(unsigned long pc) +{ + if (pc =3D=3D (unsigned long)&ftrace_call_entry) + return true; + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + if (pc =3D=3D (unsigned long)&ftrace_graph_caller_entry) + return true; +#endif + return false; +} + +#endif diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index e4103e085681..31184d64edb6 100644 --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c @@ -5,6 +5,8 @@ * Copyright (C) 2012 ARM Ltd. */ #include +#include +#include #include #include #include @@ -18,6 +20,120 @@ #include #include =20 +#ifdef CONFIG_FRAME_POINTER_VALIDATION + +static void unwind_check_frame(struct stackframe *frame) +{ + unsigned long pc, fp; + struct orc_entry *orc; + bool adjust_pc =3D false; + + /* + * If a previous frame was unreliable, the CFA cannot be reliably + * computed anymore. + */ + if (!frame->reliable) + return; + + pc =3D frame->pc; +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS + if (is_ftrace_entry(frame->prev_pc)) + pc =3D (unsigned long)&ftrace_callsite; +#endif + + /* Don't let modules unload while we're reading their ORC data. */ + preempt_disable(); + + orc =3D orc_find(pc); + if (!orc || (!orc->fp_offset && orc->type =3D=3D UNWIND_HINT_TYPE_CALL)) { + /* + * If the final instruction in a function happens to be a call + * instruction, the return address would fall outside of the + * function. That could be the case here. This can happen, for + * instance, if the called function is a "noreturn" function. + * The compiler can optimize away the instructions after the + * call. So, adjust the PC so it falls inside the function and + * retry. + * + * We only do this if the current and the previous frames + * are call frames and not hint frames. + */ + if (frame->unwind_type =3D=3D UNWIND_HINT_TYPE_CALL) { + pc -=3D 4; + adjust_pc =3D true; + orc =3D orc_find(pc); + } + } + if (!orc) { + frame->reliable =3D false; + goto out; + } + frame->unwind_type =3D orc->type; + + if (!frame->cfa) { + /* Set up the initial CFA and return. */ + frame->cfa =3D frame->fp - orc->fp_offset; + goto out; + } + + /* Compute the next CFA and FP. */ + switch (orc->type) { + case UNWIND_HINT_TYPE_CALL: + /* Normal call */ + frame->cfa +=3D orc->sp_offset; + fp =3D frame->cfa + orc->fp_offset; + break; + + case UNWIND_HINT_TYPE_REGS: + /* + * pt_regs hint: The frame pointer points to either the + * synthetic frame within pt_regs or to the place where + * x29 and x30 are saved in the register save area in + * pt_regs. + */ + frame->cfa +=3D orc->sp_offset; + fp =3D frame->cfa + offsetof(struct pt_regs, stackframe) - + sizeof(struct pt_regs); + if (frame->fp !=3D fp) { + fp =3D frame->cfa + offsetof(struct pt_regs, regs[29]) - + sizeof(struct pt_regs); + } + break; + + case UNWIND_HINT_TYPE_FTRACE: + /* ftrace callsite hint */ + frame->cfa +=3D orc->sp_offset; + fp =3D frame->cfa - orc->sp_offset; + break; + + case UNWIND_HINT_TYPE_IRQ_STACK: + /* Hint to unwind from the IRQ stack to the task stack. */ + frame->cfa =3D frame->fp + orc->sp_offset; + fp =3D frame->fp; + break; + + default: + fp =3D 0; + break; + } + + /* Validate the actual FP with the computed one. */ + if (frame->fp !=3D fp) + frame->reliable =3D false; +out: + if (frame->reliable && adjust_pc) + frame->pc =3D pc; + preempt_enable(); +} + +#else /* !CONFIG_FRAME_POINTER_VALIDATION */ + +static void unwind_check_frame(struct stackframe *frame) +{ +} + +#endif /* CONFIG_FRAME_POINTER_VALIDATION */ + /* * AArch64 PCS assigns the frame pointer to x29. * @@ -53,7 +169,13 @@ static notrace void start_backtrace(struct stackframe *= frame, unsigned long fp, */ bitmap_zero(frame->stacks_done, __NR_STACK_TYPES); frame->prev_fp =3D 0; + frame->prev_pc =3D 0; frame->prev_type =3D STACK_TYPE_UNKNOWN; + + frame->reliable =3D true; + frame->cfa =3D 0; + frame->unwind_type =3D UNWIND_HINT_TYPE_CALL; + unwind_check_frame(frame); } NOKPROBE_SYMBOL(start_backtrace); =20 @@ -110,6 +232,7 @@ static int notrace unwind_frame(struct task_struct *tsk, * Record this frame record's values and location. The prev_fp and * prev_type are only meaningful to the next unwind_frame() invocation. */ + frame->prev_pc =3D frame->pc; frame->fp =3D READ_ONCE_NOCHECK(*(unsigned long *)(fp)); frame->pc =3D READ_ONCE_NOCHECK(*(unsigned long *)(fp + 8)); frame->prev_fp =3D fp; @@ -139,6 +262,10 @@ static int notrace unwind_frame(struct task_struct *ts= k, frame->pc =3D kretprobe_find_ret_addr(tsk, (void *)frame->fp, &frame->kr= _cur); #endif =20 + /* If it is the final frame, no need to check reliability. */ + if (frame->fp !=3D (unsigned long)task_pt_regs(tsk)->stackframe) + unwind_check_frame(frame); + return 0; } NOKPROBE_SYMBOL(unwind_frame); @@ -210,3 +337,29 @@ noinline notrace void arch_stack_walk(stack_trace_cons= ume_fn consume_entry, =20 walk_stackframe(task, &frame, consume_entry, cookie); } + +noinline int arch_stack_walk_reliable(stack_trace_consume_fn consume_entry, + void *cookie, struct task_struct *task) +{ + struct stackframe frame; + int ret =3D 0; + + if (task =3D=3D current) { + start_backtrace(&frame, + (unsigned long)__builtin_frame_address(1), + (unsigned long)__builtin_return_address(0)); + } else { + start_backtrace(&frame, thread_saved_fp(task), + thread_saved_pc(task)); + } + + while (!ret) { + if (!frame.reliable) + return -EINVAL; + if (!consume_entry(cookie, frame.pc)) + return -EINVAL; + ret =3D unwind_frame(task, &frame); + } + + return ret =3D=3D -ENOENT ? 0 : -EINVAL; +} diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index 4816b7e11047..2324f0b25674 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h @@ -616,6 +616,10 @@ extern int ftrace_update_ftrace_func(ftrace_func_t fun= c); extern void ftrace_caller(void); extern void ftrace_regs_caller(void); extern void ftrace_call(void); +extern void ftrace_call_entry(void); +extern void ftrace_graph_caller_entry(void); +extern void ftrace_callsite(void); +extern bool is_ftrace_entry(unsigned long pc); extern void ftrace_regs_call(void); extern void mcount_call(void); =20 --=20 2.25.1 From nobody Tue Apr 23 06:20:23 2024 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 39AC7C433EF for ; Tue, 24 May 2022 00:18:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232182AbiEXASl (ORCPT ); Mon, 23 May 2022 20:18:41 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59752 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232084AbiEXAR3 (ORCPT ); Mon, 23 May 2022 20:17:29 -0400 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 89A1E95DC0; Mon, 23 May 2022 17:17:06 -0700 (PDT) Received: from x64host.home (unknown [47.189.24.195]) by linux.microsoft.com (Postfix) with ESMTPSA id 861EF20B8952; Mon, 23 May 2022 17:17:05 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 861EF20B8952 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1653351426; bh=W+kmmdWYfiBwaaGDXXPjvGV5/gA5GGveaxkzrHm/ZVs=; h=From:To:Subject:Date:In-Reply-To:References:From; b=jRvS00IvG4gtA8YIpC6RWC8bSYDRRjmfL4vLqLYf2/ydDSDLS0PCBoYu0pfmvGR9L vEW0prNJHP8P2Nns+JNS7mMiuIMB7TUO3JXJvmdUlPdwnnft3eMYz1Pxt7r1h46vXh 7pGFMc1xoaAVrp5whBjOG+WSNAjmkKv6bwpyC0Mo= From: madvenka@linux.microsoft.com To: jpoimboe@redhat.com, peterz@infradead.org, chenzhongjin@huawei.com, mark.rutland@arm.com, broonie@kernel.org, nobuta.keiya@fujitsu.com, sjitindarsingh@gmail.com, catalin.marinas@arm.com, will@kernel.org, jamorris@linux.microsoft.com, linux-arm-kernel@lists.infradead.org, live-patching@vger.kernel.org, linux-kernel@vger.kernel.org, madvenka@linux.microsoft.com Subject: [RFC PATCH v2 19/20] arm64: Miscellaneous changes required for enabling livepatch Date: Mon, 23 May 2022 19:16:36 -0500 Message-Id: <20220524001637.1707472-20-madvenka@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220524001637.1707472-1-madvenka@linux.microsoft.com> References: <20220524001637.1707472-1-madvenka@linux.microsoft.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: "Madhavan T. Venkataraman" - Create arch/arm64/include/asm/livepatch.h and define klp_arch_set_pc() and klp_get_ftrace_location() which are required for livepatch. - Define TIF_PATCH_PENDING in arch/arm64/include/asm/thread_info.h for livepatch. - Check TIF_PATCH_PENDING in do_notify_resume() to patch the current task for livepatch. Signed-off-by: Suraj Jitindar Singh Signed-off-by: Madhavan T. Venkataraman --- arch/arm64/include/asm/livepatch.h | 42 ++++++++++++++++++++++++++++ arch/arm64/include/asm/thread_info.h | 4 ++- arch/arm64/kernel/signal.c | 4 +++ 3 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 arch/arm64/include/asm/livepatch.h diff --git a/arch/arm64/include/asm/livepatch.h b/arch/arm64/include/asm/li= vepatch.h new file mode 100644 index 000000000000..72d7cd86f158 --- /dev/null +++ b/arch/arm64/include/asm/livepatch.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * livepatch.h - arm64-specific Kernel Live Patching Core + */ +#ifndef _ASM_ARM64_LIVEPATCH_H +#define _ASM_ARM64_LIVEPATCH_H + +#include + +static inline void klp_arch_set_pc(struct ftrace_regs *fregs, unsigned lon= g ip) +{ + struct pt_regs *regs =3D ftrace_get_regs(fregs); + + regs->pc =3D ip; +} + +/* + * klp_get_ftrace_location is expected to return the address of the BL to = the + * relevant ftrace handler in the callsite. The location of this can vary = based + * on several compilation options. + * CONFIG_DYNAMIC_FTRACE_WITH_REGS + * - Inserts 2 nops on function entry the second of which is the BL + * referenced above. (See ftrace_init_nop() for the callsite sequence) + * (this is required by livepatch and must be selected) + * CONFIG_ARM64_BTI_KERNEL: + * - Inserts a hint #0x22 on function entry if the function is called + * indirectly (to satisfy BTI requirements), which is inserted before + * the two nops from above. + */ +#define klp_get_ftrace_location klp_get_ftrace_location +static inline unsigned long klp_get_ftrace_location(unsigned long faddr) +{ + unsigned long addr =3D faddr + AARCH64_INSN_SIZE; + +#if IS_ENABLED(CONFIG_ARM64_BTI_KERNEL) + addr =3D ftrace_location_range(addr, addr + AARCH64_INSN_SIZE); +#endif + + return addr; +} + +#endif /* _ASM_ARM64_LIVEPATCH_H */ diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/= thread_info.h index e1317b7c4525..a1d8999dbdcc 100644 --- a/arch/arm64/include/asm/thread_info.h +++ b/arch/arm64/include/asm/thread_info.h @@ -68,6 +68,7 @@ int arch_dup_task_struct(struct task_struct *dst, #define TIF_UPROBE 4 /* uprobe breakpoint or singlestep */ #define TIF_MTE_ASYNC_FAULT 5 /* MTE Asynchronous Tag Check Fault */ #define TIF_NOTIFY_SIGNAL 6 /* signal notifications exist */ +#define TIF_PATCH_PENDING 7 /* pending live patching update */ #define TIF_SYSCALL_TRACE 8 /* syscall trace active */ #define TIF_SYSCALL_AUDIT 9 /* syscall auditing */ #define TIF_SYSCALL_TRACEPOINT 10 /* syscall tracepoint for ftrace */ @@ -98,11 +99,12 @@ int arch_dup_task_struct(struct task_struct *dst, #define _TIF_SVE (1 << TIF_SVE) #define _TIF_MTE_ASYNC_FAULT (1 << TIF_MTE_ASYNC_FAULT) #define _TIF_NOTIFY_SIGNAL (1 << TIF_NOTIFY_SIGNAL) +#define _TIF_PATCH_PENDING (1 << TIF_PATCH_PENDING) =20 #define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \ _TIF_NOTIFY_RESUME | _TIF_FOREIGN_FPSTATE | \ _TIF_UPROBE | _TIF_MTE_ASYNC_FAULT | \ - _TIF_NOTIFY_SIGNAL) + _TIF_NOTIFY_SIGNAL | _TIF_PATCH_PENDING) =20 #define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \ _TIF_SYSCALL_TRACEPOINT | _TIF_SECCOMP | \ diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c index 4a4122ef6f39..cbec9597349f 100644 --- a/arch/arm64/kernel/signal.c +++ b/arch/arm64/kernel/signal.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include =20 @@ -938,6 +939,9 @@ void do_notify_resume(struct pt_regs *regs, unsigned lo= ng thread_flags) (void __user *)NULL, current); } =20 + if (thread_flags & _TIF_PATCH_PENDING) + klp_update_patch_state(current); + if (thread_flags & (_TIF_SIGPENDING | _TIF_NOTIFY_SIGNAL)) do_signal(regs); =20 --=20 2.25.1 From nobody Tue Apr 23 06:20:23 2024 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0F532C433EF for ; Tue, 24 May 2022 00:18:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232209AbiEXASb (ORCPT ); Mon, 23 May 2022 20:18:31 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33560 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232091AbiEXAR3 (ORCPT ); Mon, 23 May 2022 20:17:29 -0400 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id BB3AD72213; Mon, 23 May 2022 17:17:07 -0700 (PDT) Received: from x64host.home (unknown [47.189.24.195]) by linux.microsoft.com (Postfix) with ESMTPSA id 8703720B8955; Mon, 23 May 2022 17:17:06 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 8703720B8955 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1653351427; bh=syoprsdej4CwEqysPiBnxYsuZxIUL2IqummhyMfwuKs=; h=From:To:Subject:Date:In-Reply-To:References:From; b=jmzMPJue8W13JKIJxHrm31Z+IrCiGzTbyg4geN4LH1l3NdMC7q8JIfO9+84Gl6MgK fd+S9ZmjkwUlbmBMoYsyd5JG7OzCHPiklaCOMchzYaMxMJxcWMFGpffAeXhTp7FXp9 Gux9CKb7F8U5PAFtI2Xp6LA28/BW8ngSH98CFKuY= From: madvenka@linux.microsoft.com To: jpoimboe@redhat.com, peterz@infradead.org, chenzhongjin@huawei.com, mark.rutland@arm.com, broonie@kernel.org, nobuta.keiya@fujitsu.com, sjitindarsingh@gmail.com, catalin.marinas@arm.com, will@kernel.org, jamorris@linux.microsoft.com, linux-arm-kernel@lists.infradead.org, live-patching@vger.kernel.org, linux-kernel@vger.kernel.org, madvenka@linux.microsoft.com Subject: [RFC PATCH v2 20/20] arm64: Enable livepatch for ARM64 Date: Mon, 23 May 2022 19:16:37 -0500 Message-Id: <20220524001637.1707472-21-madvenka@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220524001637.1707472-1-madvenka@linux.microsoft.com> References: <20220524001637.1707472-1-madvenka@linux.microsoft.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: "Madhavan T. Venkataraman" Enable livepatch in arch/arm64/Kconfig. Signed-off-by: Madhavan T. Venkataraman --- arch/arm64/Kconfig | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index e6a7bfc85ff9..49e15402d8c1 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -225,6 +225,9 @@ config ARM64 select THREAD_INFO_IN_TASK select HAVE_STACK_VALIDATION if FRAME_POINTER_VALIDATION select STACK_VALIDATION if HAVE_STACK_VALIDATION + select HAVE_RELIABLE_STACKTRACE if STACK_VALIDATION + select HAVE_LIVEPATCH if HAVE_DYNAMIC_FTRACE_WITH_REGS && HAVE_RELIABLE_= STACKTRACE + select HAVE_ARCH_USERFAULTFD_MINOR if USERFAULTFD select TRACE_IRQFLAGS_SUPPORT help @@ -2160,3 +2163,5 @@ source "arch/arm64/kvm/Kconfig" if CRYPTO source "arch/arm64/crypto/Kconfig" endif + +source "kernel/livepatch/Kconfig" --=20 2.25.1