From patchwork Thu May 16 10:36:40 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Raphael Gault X-Patchwork-Id: 10946321 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 69B18912 for ; Thu, 16 May 2019 10:38:15 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 56DDA2851A for ; Thu, 16 May 2019 10:38:15 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 4AD162863E; Thu, 16 May 2019 10:38:15 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id D78A32851A for ; Thu, 16 May 2019 10:38:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=QPgclXx+85elDwArs7ZIGMsgTSBZqdkKgSkwmU+pp0o=; b=H9oJ79Z/WbnRkSf/C/31pXuStf HTdUoD9kGOQ347Hqvr++U58Rd/RRyNySiQUWFjd6K0FgkWzM87HfDPnRVzSG/ejoA7uVPcJJ6bMqR 7JXLLtVVeE824UxowugH4jLaXP16PET1jdhJwxUFZH8o+05i74TwZsp2Ih4Y2Duy+wU3LJXGmEzzE pHXN7CrBSR1kaly7FiiRp2dktsMHAcly9jLftVvpltDN7U5xbJzzAZBKpfUnMyyAeTZZcGaPEmS8l 9nseOdOQuSTelV/GKTxWglpH/xQPz5BslG4GyTYIqT9kziqKrZGx5l/1VS2N7dowAVl3ZugdrgcSE GV/oOwxQ==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1hRDm8-0005ha-Lz; Thu, 16 May 2019 10:38:12 +0000 Received: from foss.arm.com ([217.140.101.70]) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1hRDly-0005VZ-Ll for linux-arm-kernel@lists.infradead.org; Thu, 16 May 2019 10:38:04 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 3196019F6; Thu, 16 May 2019 03:38:02 -0700 (PDT) Received: from e121650-lin.cambridge.arm.com (e121650-lin.cambridge.arm.com [10.1.196.108]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id A9E883F703; Thu, 16 May 2019 03:38:00 -0700 (PDT) From: Raphael Gault To: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [RFC 01/16] objtool: Add abstraction for computation of symbols offsets Date: Thu, 16 May 2019 11:36:40 +0100 Message-Id: <20190516103655.5509-2-raphael.gault@arm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190516103655.5509-1-raphael.gault@arm.com> References: <20190516103655.5509-1-raphael.gault@arm.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20190516_033802_718454_13C15F2E X-CRM114-Status: GOOD ( 14.71 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: julien.thierry@arm.com, peterz@infradead.org, catalin.marinas@arm.com, will.deacon@arm.com, Raphael Gault , jpoimboe@redhat.com MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP The jump destination and relocation offset used previously are only reliable on x86_64 architecture. We abstract these computations by calling arch-dependent implementations. Signed-off-by: Raphael Gault --- tools/objtool/arch.h | 6 ++++++ tools/objtool/arch/x86/decode.c | 11 +++++++++++ tools/objtool/check.c | 15 ++++++++++----- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/tools/objtool/arch.h b/tools/objtool/arch.h index 7a111a77b7aa..9897f9f94b29 100644 --- a/tools/objtool/arch.h +++ b/tools/objtool/arch.h @@ -76,6 +76,8 @@ struct stack_op { struct op_src src; }; +struct instruction; + void arch_initial_func_cfi_state(struct cfi_state *state); int arch_decode_instruction(struct elf *elf, struct section *sec, @@ -85,4 +87,8 @@ int arch_decode_instruction(struct elf *elf, struct section *sec, bool arch_callee_saved_reg(unsigned char reg); +unsigned long arch_jump_destination(struct instruction *insn); + +unsigned long arch_dest_rela_offset(int addend); + #endif /* _ARCH_H */ diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c index 472e991f6512..c1b95ea447c0 100644 --- a/tools/objtool/arch/x86/decode.c +++ b/tools/objtool/arch/x86/decode.c @@ -23,6 +23,7 @@ #include "lib/inat.c" #include "lib/insn.c" +#include "../../check.h" #include "../../elf.h" #include "../../arch.h" #include "../../warn.h" @@ -78,6 +79,11 @@ bool arch_callee_saved_reg(unsigned char reg) } } +unsigned long arch_dest_rela_offset(int addend) +{ + return addend + 4; +} + int arch_decode_instruction(struct elf *elf, struct section *sec, unsigned long offset, unsigned int maxlen, unsigned int *len, unsigned char *type, @@ -509,3 +515,8 @@ void arch_initial_func_cfi_state(struct cfi_state *state) state->regs[16].base = CFI_CFA; state->regs[16].offset = -8; } + +unsigned long arch_jump_destination(struct instruction *insn) +{ + return insn->offset + insn->len + insn->immediate; +} diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 38b0517dc49e..2a803ab4d5b7 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -574,7 +574,7 @@ static int add_jump_destinations(struct objtool_file *file) insn->len); if (!rela) { dest_sec = insn->sec; - dest_off = insn->offset + insn->len + insn->immediate; + dest_off = arch_jump_destination(insn); } else if (rela->sym->type == STT_SECTION) { dest_sec = rela->sym->sec; dest_off = rela->addend + 4; @@ -668,7 +668,7 @@ static int add_call_destinations(struct objtool_file *file) rela = find_rela_by_dest_range(insn->sec, insn->offset, insn->len); if (!rela) { - dest_off = insn->offset + insn->len + insn->immediate; + dest_off = arch_jump_destination(insn); insn->call_dest = find_symbol_by_offset(insn->sec, dest_off); @@ -681,14 +681,19 @@ static int add_call_destinations(struct objtool_file *file) } } else if (rela->sym->type == STT_SECTION) { + /* + * the original x86_64 code adds 4 to the rela->addend + * which is not needed on arm64 architecture. + */ + dest_off = arch_dest_rela_offset(rela->addend); insn->call_dest = find_symbol_by_offset(rela->sym->sec, - rela->addend+4); + dest_off); if (!insn->call_dest || insn->call_dest->type != STT_FUNC) { - WARN_FUNC("can't find call dest symbol at %s+0x%x", + WARN_FUNC("can't find call dest symbol at %s+0x%lx", insn->sec, insn->offset, rela->sym->sec->name, - rela->addend + 4); + dest_off); return -1; } } else From patchwork Thu May 16 10:36:41 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Raphael Gault X-Patchwork-Id: 10946323 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 623C4912 for ; Thu, 16 May 2019 10:38:29 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4BE9E2851A for ; Thu, 16 May 2019 10:38:29 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 3ECB52863E; Thu, 16 May 2019 10:38:29 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 883CA2851A for ; Thu, 16 May 2019 10:38:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=MVv1qZI/rWRSecFBbtORjBj5fKZx5iVVrqWPkXSrjkI=; b=sFsFF/K2D12EkL6BEmwy8oO3BV 34nubxuB/oVq13zc/9Ue9Apl04Dc6bnk5CBXjkA8wOe2h3vt7ZcXIy7CFJLdANCsD1IG/Gd9xiaHw f280o6GnW9hjlu+nXSThKYiPMemneUCOj+cBsOEfv0j6U0mBguyCL6EYTr/lnvdnvNBnPArqK2Dpb jP1k/ht6lp/mnFSrDyBnn0hx0ZphhzEgMwRlr8ealJXE9Dgl3tM4BE016cjXMfokWWGifKMOVDFb3 lXKJptwZPoLTyK5nn65mT7buZTowrNvq7UojhRDsBa5/gL57xQ8nqDEHR56nEBOkPfaXr0bwDU9SH 8gqr5cPQ==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1hRDmI-0005x2-UZ; Thu, 16 May 2019 10:38:22 +0000 Received: from usa-sjc-mx-foss1.foss.arm.com ([217.140.101.70] helo=foss.arm.com) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1hRDm0-0005X3-Ch for linux-arm-kernel@lists.infradead.org; Thu, 16 May 2019 10:38:07 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 1A2AE19BF; Thu, 16 May 2019 03:38:04 -0700 (PDT) Received: from e121650-lin.cambridge.arm.com (e121650-lin.cambridge.arm.com [10.1.196.108]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 700253F703; Thu, 16 May 2019 03:38:02 -0700 (PDT) From: Raphael Gault To: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [RFC 02/16] objtool: orc: Refactor ORC API for other architectures to implement. Date: Thu, 16 May 2019 11:36:41 +0100 Message-Id: <20190516103655.5509-3-raphael.gault@arm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190516103655.5509-1-raphael.gault@arm.com> References: <20190516103655.5509-1-raphael.gault@arm.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20190516_033804_598350_BA791043 X-CRM114-Status: GOOD ( 17.65 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: julien.thierry@arm.com, peterz@infradead.org, catalin.marinas@arm.com, will.deacon@arm.com, Raphael Gault , jpoimboe@redhat.com MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP The ORC unwinder is only supported on x86 at the moment and should thus be in the x86 architecture code. In order not to break the whole structure in case another architecture decides to support the ORC unwinder via objtool we choose to let the implementation be done in the architecture dependent code. Signed-off-by: Raphael Gault --- tools/objtool/Build | 2 - tools/objtool/arch.h | 3 + tools/objtool/arch/x86/Build | 2 + tools/objtool/{ => arch/x86}/orc_dump.c | 4 +- tools/objtool/{ => arch/x86}/orc_gen.c | 104 ++++++++++++++++++++++-- tools/objtool/check.c | 99 +--------------------- tools/objtool/orc.h | 4 +- 7 files changed, 111 insertions(+), 107 deletions(-) rename tools/objtool/{ => arch/x86}/orc_dump.c (98%) rename tools/objtool/{ => arch/x86}/orc_gen.c (69%) diff --git a/tools/objtool/Build b/tools/objtool/Build index 749becdf5b90..2ed83344e0a5 100644 --- a/tools/objtool/Build +++ b/tools/objtool/Build @@ -2,8 +2,6 @@ objtool-y += arch/$(SRCARCH)/ objtool-y += builtin-check.o objtool-y += builtin-orc.o objtool-y += check.o -objtool-y += orc_gen.o -objtool-y += orc_dump.o objtool-y += elf.o objtool-y += special.o objtool-y += objtool.o diff --git a/tools/objtool/arch.h b/tools/objtool/arch.h index 9897f9f94b29..653812457966 100644 --- a/tools/objtool/arch.h +++ b/tools/objtool/arch.h @@ -22,6 +22,7 @@ #include #include "elf.h" #include "cfi.h" +#include "orc.h" #define INSN_JUMP_CONDITIONAL 1 #define INSN_JUMP_UNCONDITIONAL 2 @@ -87,6 +88,8 @@ int arch_decode_instruction(struct elf *elf, struct section *sec, bool arch_callee_saved_reg(unsigned char reg); +int arch_orc_read_unwind_hints(struct objtool_file *file); + unsigned long arch_jump_destination(struct instruction *insn); unsigned long arch_dest_rela_offset(int addend); diff --git a/tools/objtool/arch/x86/Build b/tools/objtool/arch/x86/Build index b998412c017d..1f11b45999d0 100644 --- a/tools/objtool/arch/x86/Build +++ b/tools/objtool/arch/x86/Build @@ -1,4 +1,6 @@ objtool-y += decode.o +objtool-y += orc_dump.o +objtool-y += orc_gen.o inat_tables_script = arch/x86/tools/gen-insn-attr-x86.awk inat_tables_maps = arch/x86/lib/x86-opcode-map.txt diff --git a/tools/objtool/orc_dump.c b/tools/objtool/arch/x86/orc_dump.c similarity index 98% rename from tools/objtool/orc_dump.c rename to tools/objtool/arch/x86/orc_dump.c index faa444270ee3..8ad0e5764118 100644 --- a/tools/objtool/orc_dump.c +++ b/tools/objtool/arch/x86/orc_dump.c @@ -16,8 +16,8 @@ */ #include -#include "orc.h" -#include "warn.h" +#include "../../orc.h" +#include "../../warn.h" static const char *reg_name(unsigned int reg) { diff --git a/tools/objtool/orc_gen.c b/tools/objtool/arch/x86/orc_gen.c similarity index 69% rename from tools/objtool/orc_gen.c rename to tools/objtool/arch/x86/orc_gen.c index 3f98dcfbc177..a1ee3b12c937 100644 --- a/tools/objtool/orc_gen.c +++ b/tools/objtool/arch/x86/orc_gen.c @@ -18,11 +18,11 @@ #include #include -#include "orc.h" -#include "check.h" -#include "warn.h" +#include "../../orc.h" +#include "../../check.h" +#include "../../warn.h" -int create_orc(struct objtool_file *file) +int arch_create_orc(struct objtool_file *file) { struct instruction *insn; @@ -128,7 +128,7 @@ static int create_orc_entry(struct section *u_sec, struct section *ip_relasec, return 0; } -int create_orc_sections(struct objtool_file *file) +int arch_create_orc_sections(struct objtool_file *file) { struct instruction *insn, *prev_insn; struct section *sec, *u_sec, *ip_relasec; @@ -221,3 +221,97 @@ int create_orc_sections(struct objtool_file *file) return 0; } + +int arch_orc_read_unwind_hints(struct objtool_file *file) +{ + struct section *sec, *relasec; + struct rela *rela; + struct unwind_hint *hint; + struct instruction *insn; + struct cfi_reg *cfa; + int i; + + sec = find_section_by_name(file->elf, ".discard.unwind_hints"); + if (!sec) + return 0; + + relasec = sec->rela; + if (!relasec) { + WARN("missing .rela.discard.unwind_hints section"); + return -1; + } + + if (sec->len % sizeof(struct unwind_hint)) { + WARN("struct unwind_hint size mismatch"); + return -1; + } + + file->hints = true; + + for (i = 0; i < sec->len / sizeof(struct unwind_hint); i++) { + hint = (struct unwind_hint *)sec->data->d_buf + i; + + rela = find_rela_by_dest(sec, i * sizeof(*hint)); + if (!rela) { + WARN("can't find rela for unwind_hints[%d]", i); + return -1; + } + + insn = find_insn(file, rela->sym->sec, rela->addend); + if (!insn) { + WARN("can't find insn for unwind_hints[%d]", i); + return -1; + } + + cfa = &insn->state.cfa; + + if (hint->type == UNWIND_HINT_TYPE_SAVE) { + insn->save = true; + continue; + + } else if (hint->type == UNWIND_HINT_TYPE_RESTORE) { + insn->restore = true; + insn->hint = true; + continue; + } + + insn->hint = true; + + switch (hint->sp_reg) { + case ORC_REG_UNDEFINED: + cfa->base = CFI_UNDEFINED; + break; + case ORC_REG_SP: + cfa->base = CFI_SP; + break; + case ORC_REG_BP: + cfa->base = CFI_BP; + break; + case ORC_REG_SP_INDIRECT: + cfa->base = CFI_SP_INDIRECT; + break; + case ORC_REG_R10: + cfa->base = CFI_R10; + break; + case ORC_REG_R13: + cfa->base = CFI_R13; + break; + case ORC_REG_DI: + cfa->base = CFI_DI; + break; + case ORC_REG_DX: + cfa->base = CFI_DX; + break; + default: + WARN_FUNC("unsupported unwind_hint sp base reg %d", + insn->sec, insn->offset, hint->sp_reg); + return -1; + } + + cfa->offset = hint->sp_offset; + insn->state.type = hint->type; + insn->state.end = hint->end; + } + + return 0; +} diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 2a803ab4d5b7..cd9cd26206d1 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -1156,99 +1156,6 @@ static int add_switch_table_alts(struct objtool_file *file) return 0; } -static int read_unwind_hints(struct objtool_file *file) -{ - struct section *sec, *relasec; - struct rela *rela; - struct unwind_hint *hint; - struct instruction *insn; - struct cfi_reg *cfa; - int i; - - sec = find_section_by_name(file->elf, ".discard.unwind_hints"); - if (!sec) - return 0; - - relasec = sec->rela; - if (!relasec) { - WARN("missing .rela.discard.unwind_hints section"); - return -1; - } - - if (sec->len % sizeof(struct unwind_hint)) { - WARN("struct unwind_hint size mismatch"); - return -1; - } - - file->hints = true; - - for (i = 0; i < sec->len / sizeof(struct unwind_hint); i++) { - hint = (struct unwind_hint *)sec->data->d_buf + i; - - rela = find_rela_by_dest(sec, i * sizeof(*hint)); - if (!rela) { - WARN("can't find rela for unwind_hints[%d]", i); - return -1; - } - - insn = find_insn(file, rela->sym->sec, rela->addend); - if (!insn) { - WARN("can't find insn for unwind_hints[%d]", i); - return -1; - } - - cfa = &insn->state.cfa; - - if (hint->type == UNWIND_HINT_TYPE_SAVE) { - insn->save = true; - continue; - - } else if (hint->type == UNWIND_HINT_TYPE_RESTORE) { - insn->restore = true; - insn->hint = true; - continue; - } - - insn->hint = true; - - switch (hint->sp_reg) { - case ORC_REG_UNDEFINED: - cfa->base = CFI_UNDEFINED; - break; - case ORC_REG_SP: - cfa->base = CFI_SP; - break; - case ORC_REG_BP: - cfa->base = CFI_BP; - break; - case ORC_REG_SP_INDIRECT: - cfa->base = CFI_SP_INDIRECT; - break; - case ORC_REG_R10: - cfa->base = CFI_R10; - break; - case ORC_REG_R13: - cfa->base = CFI_R13; - break; - case ORC_REG_DI: - cfa->base = CFI_DI; - break; - case ORC_REG_DX: - cfa->base = CFI_DX; - break; - default: - WARN_FUNC("unsupported unwind_hint sp base reg %d", - insn->sec, insn->offset, hint->sp_reg); - return -1; - } - - cfa->offset = hint->sp_offset; - insn->state.type = hint->type; - insn->state.end = hint->end; - } - - return 0; -} static int read_retpoline_hints(struct objtool_file *file) { @@ -1343,7 +1250,7 @@ static int decode_sections(struct objtool_file *file) if (ret) return ret; - ret = read_unwind_hints(file); + ret = arch_orc_read_unwind_hints(file); if (ret) return ret; @@ -2465,11 +2372,11 @@ int check(const char *_objname, bool orc) } if (orc) { - ret = create_orc(&file); + ret = arch_create_orc(&file); if (ret < 0) goto out; - ret = create_orc_sections(&file); + ret = arch_create_orc_sections(&file); if (ret < 0) goto out; diff --git a/tools/objtool/orc.h b/tools/objtool/orc.h index b0e92a6d0903..1aa02dce3bca 100644 --- a/tools/objtool/orc.h +++ b/tools/objtool/orc.h @@ -22,8 +22,8 @@ struct objtool_file; -int create_orc(struct objtool_file *file); -int create_orc_sections(struct objtool_file *file); +int arch_create_orc(struct objtool_file *file); +int arch_create_orc_sections(struct objtool_file *file); int orc_dump(const char *objname); From patchwork Thu May 16 10:36:42 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Raphael Gault X-Patchwork-Id: 10946327 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id CA429924 for ; Thu, 16 May 2019 10:38:53 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B72E42854F for ; Thu, 16 May 2019 10:38:53 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id AA18E28842; Thu, 16 May 2019 10:38:53 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 260A12854F for ; Thu, 16 May 2019 10:38:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=TTJCvIT1vvyiIZgVwVZ1n1BEGhxvyDmLM5DGxO29kgs=; b=W1Qdax3AtJOeEdwITwynrrybFs O68LIpWUxpNjM01DNTslPoTLVsRuqvp+YL8mHSb5Nc2/GTBgEexOol1Z+89om1TkahrHBD+HtmqlC 76uAVy6dz8Bq/FgGbfQNzUytbhcbkNFdlVYLSI1UIej76lssu0+T2yMyVLaJ2W49ceKCGaniqpM1P BMdt/p64Kjdy9kq/7PlldxqsCHfrF6v0PWkKPkgwBf1ql7nLok9O2g+xOlZUr3T5lajRfo+x1WhTG DIPe1UVrA8FtXUz7mgudhW8g1dpjdQGi7fGUQlekY5R6GXVseovQyeGG6FQD/F0YsMM2EFQz0tK7l yVPlQ06Q==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1hRDmk-0006Re-9g; Thu, 16 May 2019 10:38:50 +0000 Received: from foss.arm.com ([217.140.101.70]) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1hRDm2-0005ZV-DQ for linux-arm-kernel@lists.infradead.org; Thu, 16 May 2019 10:38:11 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id D307719F6; Thu, 16 May 2019 03:38:05 -0700 (PDT) Received: from e121650-lin.cambridge.arm.com (e121650-lin.cambridge.arm.com [10.1.196.108]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 581EF3F703; Thu, 16 May 2019 03:38:04 -0700 (PDT) From: Raphael Gault To: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [RFC 03/16] objtool: Move registers and control flow to arch-dependent code Date: Thu, 16 May 2019 11:36:42 +0100 Message-Id: <20190516103655.5509-4-raphael.gault@arm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190516103655.5509-1-raphael.gault@arm.com> References: <20190516103655.5509-1-raphael.gault@arm.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20190516_033806_735888_04FCFC31 X-CRM114-Status: GOOD ( 15.22 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: julien.thierry@arm.com, peterz@infradead.org, catalin.marinas@arm.com, will.deacon@arm.com, Raphael Gault , jpoimboe@redhat.com MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP The control flow information and register macro definitions were based on the x86_64 architecture but should be abstract so that each architecture can define the correct values for the registers, especially the registers related to the stack frame (Frame Pointer, Stack Pointer and possibly Return Address). Signed-off-by: Raphael Gault --- tools/objtool/arch/x86/include/arch_special.h | 36 +++++++++++++++++++ tools/objtool/{ => arch/x86/include}/cfi.h | 0 tools/objtool/check.h | 1 + tools/objtool/special.c | 19 +--------- 4 files changed, 38 insertions(+), 18 deletions(-) create mode 100644 tools/objtool/arch/x86/include/arch_special.h rename tools/objtool/{ => arch/x86/include}/cfi.h (100%) diff --git a/tools/objtool/arch/x86/include/arch_special.h b/tools/objtool/arch/x86/include/arch_special.h new file mode 100644 index 000000000000..424ce47013e3 --- /dev/null +++ b/tools/objtool/arch/x86/include/arch_special.h @@ -0,0 +1,36 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ +#ifndef _X86_ARCH_SPECIAL_H +#define _X86_ARCH_SPECIAL_H + +#define EX_ENTRY_SIZE 12 +#define EX_ORIG_OFFSET 0 +#define EX_NEW_OFFSET 4 + +#define JUMP_ENTRY_SIZE 16 +#define JUMP_ORIG_OFFSET 0 +#define JUMP_NEW_OFFSET 4 + +#define ALT_ENTRY_SIZE 13 +#define ALT_ORIG_OFFSET 0 +#define ALT_NEW_OFFSET 4 +#define ALT_FEATURE_OFFSET 8 +#define ALT_ORIG_LEN_OFFSET 10 +#define ALT_NEW_LEN_OFFSET 11 + +#define X86_FEATURE_POPCNT (4 * 32 + 23) +#define X86_FEATURE_SMAP (9 * 32 + 20) + +#endif /* _X86_ARCH_SPECIAL_H */ diff --git a/tools/objtool/cfi.h b/tools/objtool/arch/x86/include/cfi.h similarity index 100% rename from tools/objtool/cfi.h rename to tools/objtool/arch/x86/include/cfi.h diff --git a/tools/objtool/check.h b/tools/objtool/check.h index 71e54f97dbcd..8d809de23029 100644 --- a/tools/objtool/check.h +++ b/tools/objtool/check.h @@ -23,6 +23,7 @@ #include "cfi.h" #include "arch.h" #include "orc.h" +#include "arch_special.h" #include struct insn_state { diff --git a/tools/objtool/special.c b/tools/objtool/special.c index 4e50563d87c6..fd7c928fa1d6 100644 --- a/tools/objtool/special.c +++ b/tools/objtool/special.c @@ -26,24 +26,7 @@ #include "builtin.h" #include "special.h" #include "warn.h" - -#define EX_ENTRY_SIZE 12 -#define EX_ORIG_OFFSET 0 -#define EX_NEW_OFFSET 4 - -#define JUMP_ENTRY_SIZE 16 -#define JUMP_ORIG_OFFSET 0 -#define JUMP_NEW_OFFSET 4 - -#define ALT_ENTRY_SIZE 13 -#define ALT_ORIG_OFFSET 0 -#define ALT_NEW_OFFSET 4 -#define ALT_FEATURE_OFFSET 8 -#define ALT_ORIG_LEN_OFFSET 10 -#define ALT_NEW_LEN_OFFSET 11 - -#define X86_FEATURE_POPCNT (4*32+23) -#define X86_FEATURE_SMAP (9*32+20) +#include "arch_special.h" struct special_entry { const char *sec; From patchwork Thu May 16 10:36:43 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Raphael Gault X-Patchwork-Id: 10946345 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id CCF84912 for ; Thu, 16 May 2019 10:40:42 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id AC12328A8E for ; Thu, 16 May 2019 10:40:42 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 9BD9A28A93; Thu, 16 May 2019 10:40:42 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 35A4628A8E for ; Thu, 16 May 2019 10:40:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=Z01l/0EGiQCh1J+8Prx5iHF6TTt+YTzCYkYUX8bASuU=; b=SYhmH8U7h6brwsKdQSEoFwmums qkcm51+t/JcT2Ai2NnmLcKWlt4Z+h+vwwE/HuF2/Gwngi0oHkGdtcaZ2qrWjXfqJ8l9hP+TIb605Z HTS6ntGCpWhyXXjZjhcVHMXyV7s6DNhVrSRS6lPx7jJnWP12lkrFetJpe5t4PmJuwSzoQJM8V+OZO +sf/Wr+S1g14ciPEbkiJnk47RDypy8axY72GGSDrfYUdoAid/bWmM4MagqkGngPm0caT1YtBMwSIv 2EFSynwni2JP+39H0aH45q+MQNn/HsuG/unWP0PAmAMDhu5714IGDrPTRAsCa8075brGRxy0jTaiX hYMc3ubA==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1hRDoN-0001NO-99; Thu, 16 May 2019 10:40:31 +0000 Received: from usa-sjc-mx-foss1.foss.arm.com ([217.140.101.70] helo=foss.arm.com) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1hRDm4-0005cK-Ay for linux-arm-kernel@lists.infradead.org; Thu, 16 May 2019 10:38:38 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id E693B19BF; Thu, 16 May 2019 03:38:07 -0700 (PDT) Received: from e121650-lin.cambridge.arm.com (e121650-lin.cambridge.arm.com [10.1.196.108]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 1DCD83F703; Thu, 16 May 2019 03:38:05 -0700 (PDT) From: Raphael Gault To: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [RFC 04/16] objtool: arm64: Add required implementation for supporting the aarch64 architecture in objtool. Date: Thu, 16 May 2019 11:36:43 +0100 Message-Id: <20190516103655.5509-5-raphael.gault@arm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190516103655.5509-1-raphael.gault@arm.com> References: <20190516103655.5509-1-raphael.gault@arm.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20190516_033809_051605_0B03BC7D X-CRM114-Status: GOOD ( 25.28 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: julien.thierry@arm.com, peterz@infradead.org, catalin.marinas@arm.com, will.deacon@arm.com, Raphael Gault , jpoimboe@redhat.com MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP Provide implementation for the arch-dependent functions that are called by the main check function of objtool. The ORC unwinder is not yet supported by the arm64 architecture so we only provide a dummy interface for now. The decoding of the instruction is split into classes and subclasses as described into the Instruction Encoding in the ArmV8.5 Architecture Reference Manual. In order to handle the load/store instructions for a pair of registers we add an extra field to the stack_op structure. Signed-off-by: Raphael Gault --- tools/objtool/arch.h | 7 + tools/objtool/arch/arm64/Build | 7 + tools/objtool/arch/arm64/bit_operations.c | 67 + tools/objtool/arch/arm64/decode.c | 2778 +++++++++++++++++ .../objtool/arch/arm64/include/arch_special.h | 36 + .../arch/arm64/include/asm/orc_types.h | 96 + .../arch/arm64/include/bit_operations.h | 24 + tools/objtool/arch/arm64/include/cfi.h | 74 + .../objtool/arch/arm64/include/insn_decode.h | 211 ++ tools/objtool/arch/arm64/orc_dump.c | 26 + tools/objtool/arch/arm64/orc_gen.c | 40 + 11 files changed, 3366 insertions(+) create mode 100644 tools/objtool/arch/arm64/Build create mode 100644 tools/objtool/arch/arm64/bit_operations.c create mode 100644 tools/objtool/arch/arm64/decode.c create mode 100644 tools/objtool/arch/arm64/include/arch_special.h create mode 100644 tools/objtool/arch/arm64/include/asm/orc_types.h create mode 100644 tools/objtool/arch/arm64/include/bit_operations.h create mode 100644 tools/objtool/arch/arm64/include/cfi.h create mode 100644 tools/objtool/arch/arm64/include/insn_decode.h create mode 100644 tools/objtool/arch/arm64/orc_dump.c create mode 100644 tools/objtool/arch/arm64/orc_gen.c diff --git a/tools/objtool/arch.h b/tools/objtool/arch.h index 653812457966..bb3494e431b7 100644 --- a/tools/objtool/arch.h +++ b/tools/objtool/arch.h @@ -72,9 +72,16 @@ struct op_src { int offset; }; +struct op_extra { + unsigned char used; + unsigned char reg; + int offset; +}; + struct stack_op { struct op_dest dest; struct op_src src; + struct op_extra extra; }; struct instruction; diff --git a/tools/objtool/arch/arm64/Build b/tools/objtool/arch/arm64/Build new file mode 100644 index 000000000000..bf7a32c2b9e9 --- /dev/null +++ b/tools/objtool/arch/arm64/Build @@ -0,0 +1,7 @@ +objtool-y += decode.o +objtool-y += orc_dump.o +objtool-y += orc_gen.o +objtool-y += bit_operations.o + + +CFLAGS_decode.o += -I$(OUTPUT)arch/arm64/lib diff --git a/tools/objtool/arch/arm64/bit_operations.c b/tools/objtool/arch/arm64/bit_operations.c new file mode 100644 index 000000000000..f457a14a7f5d --- /dev/null +++ b/tools/objtool/arch/arm64/bit_operations.c @@ -0,0 +1,67 @@ +#include +#include +#include "bit_operations.h" + +#include "../../warn.h" + +u64 replicate(u64 x, int size, int n) +{ + u64 ret = 0; + + while (n >= 0) { + ret = (ret | x) << size; + n--; + } + return ret | x; +} + +u64 ror(u64 x, int size, int shift) +{ + int m = shift % size; + + if (shift == 0) + return x; + return ZERO_EXTEND((x >> m) | (x << (size - m)), size); +} + +int highest_set_bit(u32 x) +{ + int i; + + for (i = 31; i >= 0; i--, x <<= 1) + if (x & 0x80000000) + return i; + return 0; +} + +/* imms and immr are both 6 bit long */ +__uint128_t decode_bit_masks(unsigned char N, unsigned char imms, + unsigned char immr, bool immediate) +{ + u64 tmask, wmask; + u32 diff, S, R, esize, welem, telem; + unsigned char levels = 0, len = 0; + + len = highest_set_bit((N << 6) | ((~imms) & ONES(6))); + levels = ZERO_EXTEND(ONES(len), 6); + + if (immediate && ((imms & levels) == levels)) { + WARN("unknown instruction"); + return -1; + } + + S = imms & levels; + R = immr & levels; + diff = ZERO_EXTEND(S - R, 6); + + esize = 1 << len; + diff = diff & ONES(len); + + welem = ZERO_EXTEND(ONES(S + 1), esize); + telem = ZERO_EXTEND(ONES(diff + 1), esize); + + wmask = replicate(ror(welem, esize, R), esize, 64 / esize); + tmask = replicate(telem, esize, 64 / esize); + + return ((__uint128_t)wmask << 64) | tmask; +} diff --git a/tools/objtool/arch/arm64/decode.c b/tools/objtool/arch/arm64/decode.c new file mode 100644 index 000000000000..721152342dd3 --- /dev/null +++ b/tools/objtool/arch/arm64/decode.c @@ -0,0 +1,2778 @@ +/* + * Copyright (C) 2019 Raphael Gault + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#include +#include + +#include "insn_decode.h" +#include "cfi.h" +#include "bit_operations.h" + +#include "../../check.h" +#include "../../arch.h" +#include "../../elf.h" +#include "../../warn.h" + +/* + * static int (*arm_decode_class)(u32 instr, + * unsigned int *len, + * unsigned char *type, + * unsigned long *immediate, + * struct stack_op *op); + */ +static arm_decode_class aarch64_insn_class_decode_table[] = { + [INSN_RESERVED] = arm_decode_reserved, + [INSN_UNKNOWN] = arm_decode_unknown, + [INSN_SVE_ENC] = arm_decode_sve_encoding, + [INSN_UNALLOC] = arm_decode_unknown, + [INSN_LD_ST_4] = arm_decode_ld_st, + [INSN_DP_REG_5] = arm_decode_dp_reg, + [INSN_LD_ST_6] = arm_decode_ld_st, + [INSN_DP_SIMD_7] = arm_decode_dp_simd, + [0b1000 ... INSN_DP_IMM] = arm_decode_dp_imm, + [0b1010 ... INSN_BRANCH] = arm_decode_br_sys, + [INSN_LD_ST_C] = arm_decode_ld_st, + [INSN_DP_REG_D] = arm_decode_dp_reg, + [INSN_LD_ST_E] = arm_decode_ld_st, + [INSN_DP_SIMD_F] = arm_decode_dp_simd, +}; + +static arm_decode_class aarch64_insn_dp_imm_decode_table[] = { + [0 ... INSN_PCREL] = arm_decode_pcrel, + [INSN_ADD_SUB] = arm_decode_add_sub, + [INSN_ADD_TAG] = arm_decode_add_sub_tags, + [INSN_LOGICAL] = arm_decode_logical, + [INSN_MOVE_WIDE] = arm_decode_move_wide, + [INSN_BITFIELD] = arm_decode_bitfield, + [INSN_EXTRACT] = arm_decode_extract, +}; + +bool arch_callee_saved_reg(unsigned char reg) +{ + switch (reg) { + case CFI_R19: + case CFI_R20: + case CFI_R21: + case CFI_R22: + case CFI_R23: + case CFI_R24: + case CFI_R25: + case CFI_R26: + case CFI_R27: + case CFI_R28: + case CFI_FP: + case CFI_R30: + return true; + default: + return false; + } +} + +void arch_initial_func_cfi_state(struct cfi_state *state) +{ + int i; + + for (i = 0; i < CFI_NUM_REGS; i++) { + state->regs[i].base = CFI_UNDEFINED; + state->regs[i].offset = 0; + } + + /* initial CFA (call frame address) */ + state->cfa.base = CFI_CFA; + state->cfa.offset = 0; + + /* initial RA (return address) */ + state->regs[CFI_LR].base = CFI_CFA; + state->regs[CFI_LR].offset = -8; +} + +unsigned long arch_dest_rela_offset(int addend) +{ + return addend; +} + +static int is_arm64(struct elf *elf) +{ + switch (elf->ehdr.e_machine) { + case EM_AARCH64: //0xB7 + return 1; + default: + WARN("unexpected ELF machine type %x", + elf->ehdr.e_machine); + return 0; + } +} + +/* + * Arm A64 Instruction set' decode groups (based on op0 bits[28:25]): + * Ob0000 - Reserved + * 0b0001/0b001x - Unallocated + * 0b100x - Data Processing -- Immediate + * 0b101x - Branch, Exception Gen., System Instructions. + * 0bx1x0 - Loads and Stores + * 0bx101 - Data Processing -- Registers + * 0bx111 - Data Processing -- Scalar Floating-Points, Advanced SIMD + */ + +int arch_decode_instruction(struct elf *elf, struct section *sec, + unsigned long offset, unsigned int maxlen, + unsigned int *len, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + int arm64 = 0; + u32 insn = 0; + + *len = 4; + *immediate = 0; + + op->dest.type = 0; + op->dest.reg = 0; + op->dest.offset = 0; + op->src.type = 0; + op->src.reg = 0; + op->src.offset = 0; + + //test architucture (make sure it is arm64) + arm64 = is_arm64(elf); + if (arm64 != 1) + return -1; + + //retrieve instruction (from sec->data->offset) + insn = *(u32 *)(sec->data->d_buf + offset); + + //dispatch according to encoding classes + return aarch64_insn_class_decode_table[(insn >> 25) & 0xf](insn, type, + immediate, op); +} + +int arm_decode_unknown(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + *type = 0; + return 0; +} + +int arm_decode_dp_simd(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + *type = INSN_OTHER; + return 0; +} + +int arm_decode_reserved(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + *immediate = instr & ONES(16); + *type = INSN_BUG; + return 0; +} + +int arm_decode_dp_imm(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + return aarch64_insn_dp_imm_decode_table[(instr >> 23) & 0x7](instr, + type, immediate, op); +} + +int arm_decode_pcrel(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + unsigned char rd = 0, page = 0; + u32 immhi = 0, immlo = 0; + + page = EXTRACT_BIT(instr, 31); + rd = instr & 0x1F; + immhi = (instr >> 5) & ONES(19); + immlo = (instr >> 29) & ONES(2); + + *immediate = SIGN_EXTEND((immhi << 2) | immlo, 21); + + if (page) + *immediate = SIGN_EXTEND(*immediate << 12, 33); + + *type = INSN_OTHER; + op->src.reg = ADR_SOURCE; + op->dest.reg = rd; + + return 0; +} + +int arm_decode_add_sub(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + unsigned long imm12 = 0, imm = 0; + unsigned char sf = 0, sh = 0, S = 0, op_bit = 0; + unsigned char rn = 0, rd = 0; + + S = EXTRACT_BIT(instr, 29); + op_bit = EXTRACT_BIT(instr, 30); + sf = EXTRACT_BIT(instr, 31); + sh = EXTRACT_BIT(instr, 22); + rd = instr & ONES(5); + rn = (instr >> 5) & ONES(5); + imm12 = (instr >> 10) & ONES(12); + imm = ZERO_EXTEND(imm12 << (sh * 12), (sf + 1) * 32); + + *type = INSN_OTHER; + + if ((!S && rd == CFI_SP) || rn == CFI_SP) { + *type = INSN_STACK; + op->dest.type = OP_DEST_REG; + op->dest.offset = 0; + op->dest.reg = rd; + op->src.type = imm12 ? OP_SRC_ADD : OP_SRC_REG; + op->src.offset = op_bit ? -1 * imm : imm; + op->src.reg = rn; + } + return 0; +} + +int arm_decode_add_sub_tags(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + unsigned char decode_field = 0, rn = 0, rd = 0, uimm6 = 0; + + decode_field = (instr >> 29) & ONES(3); + rd = instr & ONES(5); + rn = (instr >> 5) & ONES(5); + uimm6 = (instr >> 16) & ONES(6); + + *immediate = uimm6; + *type = INSN_OTHER; + +#define ADDG_DECODE 4 +#define SUBG_DECODE 5 + if (decode_field != ADDG_DECODE && decode_field != SUBG_DECODE) + return arm_decode_unknown(instr, type, immediate, op); + +#undef ADDG_DECODE +#undef SUBG_DECODE + op->dest.type = OP_DEST_REG; + op->dest.offset = 0; + op->dest.reg = rd; + op->src.type = OP_SRC_ADD; + op->src.offset = 0; + op->src.reg = rn; + + if (rd == CFI_SP) + *type = INSN_STACK; + + return 0; +} + +int arm_decode_logical(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + unsigned char sf = 0, opc = 0, N = 0; + unsigned char imms = 0, immr = 0, rn = 0, rd = 0; + + rd = instr & ONES(5); + rn = (instr >> 5) & ONES(5); + + imms = (instr >> 10) & ONES(6); + immr = (instr >> 16) & ONES(6); + + N = EXTRACT_BIT(instr, 22); + opc = (instr >> 29) & ONES(2); + sf = EXTRACT_BIT(instr, 31); + + if (N == 1 && sf == 0) + return arm_decode_unknown(instr, type, immediate, op); + + *type = INSN_OTHER; + *immediate = (decode_bit_masks(N, imms, immr, true) >> 64); +#define ANDS_DECODE 0b11 + if (opc == ANDS_DECODE) + return 0; +#undef ANDS_DECODE + if (rd == CFI_SP) { + *type = INSN_STACK; + op->dest.type = OP_DEST_REG; + op->dest.offset = 0; + op->dest.reg = CFI_SP; + + op->src.type = OP_SRC_AND; + op->src.offset = 0; + op->src.reg = rn; + } + + return 0; +} + +int arm_decode_move_wide(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + u32 imm16 = 0; + unsigned char hw = 0, opc = 0, sf = 0; + + sf = EXTRACT_BIT(instr, 31); + opc = (instr >> 29) & ONES(2); + hw = (instr >> 21) & ONES(2); + imm16 = (instr >> 5) & ONES(16); + + if ((sf == 0 && (hw & 0x2)) || opc == 0x1) + return arm_decode_unknown(instr, type, immediate, op); + + *type = INSN_OTHER; + *immediate = imm16; + + return 0; +} + +int arm_decode_bitfield(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + unsigned char sf = 0, opc = 0, N = 0; + + sf = EXTRACT_BIT(instr, 31); + opc = (instr >> 29) & ONES(2); + N = EXTRACT_BIT(instr, 22); + + if (opc == 0x3 || sf != N) + return arm_decode_unknown(instr, type, immediate, op); + + *type = INSN_OTHER; + + return 0; +} + +int arm_decode_extract(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + unsigned char sf = 0, op21 = 0, N = 0, o0 = 0; + unsigned char imms = 0; + unsigned char decode_field = 0; + + sf = EXTRACT_BIT(instr, 31); + op21 = (instr >> 29) & ONES(2); + N = EXTRACT_BIT(instr, 22); + o0 = EXTRACT_BIT(instr, 21); + imms = (instr >> 10) & ONES(6); + + decode_field = (sf << 4) | (op21 << 2) | (N << 1) | o0; + *type = INSN_OTHER; + *immediate = imms; + + if ((decode_field == 0 && !EXTRACT_BIT(imms, 5)) || + decode_field == 0b10010) + return 0; + + return arm_decode_unknown(instr, type, immediate, op); +} + +static struct aarch64_insn_decoder br_sys_decoder[] = { + { + .mask = 0b1111000000000000000000, + .value = 0b0100000000000000000000, + .decode_func = arm_decode_br_cond_imm, + }, + { + .mask = 0b1111100000000000000000, + .value = 0b1100000000000000000000, + .decode_func = arm_decode_except_gen, + }, + { + .mask = 0b1111111111111111111111, + .value = 0b1100100000011001011111, + .decode_func = arm_decode_hints, + }, + { + .mask = 0b1111111111111111100000, + .value = 0b1100100000011001100000, + .decode_func = arm_decode_barriers, + }, + { + .mask = 0b1111111111000111100000, + .value = 0b1100100000000010000000, + .decode_func = arm_decode_pstate, + }, + { + .mask = 0b1111111011000000000000, + .value = 0b1100100001000000000000, + .decode_func = arm_decode_system_insn, + }, + { + .mask = 0b1111111010000000000000, + .value = 0b1100100010000000000000, + .decode_func = arm_decode_system_regs, + }, + { + .mask = 0b1111000000000000000000, + .value = 0b1101000000000000000000, + .decode_func = arm_decode_br_uncond_reg, + }, + { + .mask = 0b0110000000000000000000, + .value = 0b0000000000000000000000, + .decode_func = arm_decode_br_uncond_imm, + }, + { + .mask = 0b0111000000000000000000, + .value = 0b0010000000000000000000, + .decode_func = arm_decode_br_comp_imm, + }, + { + .mask = 0b0111000000000000000000, + .value = 0b0011000000000000000000, + .decode_func = arm_decode_br_tst_imm, + }, + +}; + +int arm_decode_br_sys(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + u32 decode_field = 0, op1 = 0; + unsigned char op0 = 0, op2 = 0; + int i = 0; + + op0 = (instr >> 29) & ONES(3); + op1 = (instr >> 12) & ONES(14); + op2 = instr & ONES(5); + + decode_field = op0; + decode_field = (decode_field << 19) | (op1 << 5) | op2; + + for (i = 0; i < ARRAY_SIZE(br_sys_decoder); i++) { + if ((decode_field & br_sys_decoder[i].mask) == + br_sys_decoder[i].value) { + return br_sys_decoder[i].decode_func(instr, + type, + immediate, + op); + } + } + + return arm_decode_unknown(instr, type, immediate, op); +} + +int arm_decode_br_cond_imm(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + unsigned char o0 = 0, o1 = 0; + u32 imm19; + + o0 = EXTRACT_BIT(instr, 4); + o1 = EXTRACT_BIT(instr, 24); + imm19 = (instr >> 5) & ONES(19); + + *immediate = SIGN_EXTEND(imm19 << 2, 19); + + if ((o1 << 1) | o0) + return arm_decode_unknown(instr, type, immediate, op); + + *type = INSN_JUMP_CONDITIONAL; + + return 0; +} + +static struct aarch64_insn_decoder except_gen_decoder[] = { + { + .mask = 0b00000100, + .value = 0b00000100, + }, + { + .mask = 0b00001000, + .value = 0b00001000, + }, + { + .mask = 0b00010000, + .value = 0b00010000, + }, + { + .mask = 0b11111111, + .value = 0b00000000, + }, + { + .mask = 0b11111101, + .value = 0b00100001, + }, + { + .mask = 0b11111110, + .value = 0b00100010, + }, + { + .mask = 0b11111101, + .value = 0b01000001, + }, + { + .mask = 0b11111110, + .value = 0b01000010, + }, + { + .mask = 0b11111111, + .value = 0b01100001, + }, + { + .mask = 0b11111110, + .value = 0b01100010, + }, + { + .mask = 0b11111111, + .value = 0b10000000, + }, + { + .mask = 0b11111111, + .value = 0b10100000, + }, + { + .mask = 0b11111100, + .value = 0b11000000, + }, + { + .mask = 0b11111111, + .value = 0b11100001, + }, + { + .mask = 0b11111110, + .value = 0b11100010, + }, +}; + +int arm_decode_except_gen(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + u32 imm16 = 0; + unsigned char opc = 0, op2 = 0, LL = 0, decode_field = 0; + int i = 0; + + imm16 = (instr >> 5) & ONES(16); + opc = (instr >> 21) & ONES(3); + op2 = (instr >> 2) & ONES(3); + LL = instr & ONES(2); + decode_field = (opc << 5) | (op2 << 2) | LL; + + for (i = 0; i < ARRAY_SIZE(except_gen_decoder); i++) { + if ((decode_field & except_gen_decoder[i].mask) == + except_gen_decoder[i].value) { + return arm_decode_unknown(instr, type, immediate, op); + } + } + +#define INSN_SVC 0b00000001 +#define INSN_HVC 0b00000010 +#define INSN_SMC 0b00000011 +#define INSN_BRK 0b00100000 +#define INSN_HLT 0b01000000 +#define INSN_DCPS1 0b10100001 +#define INSN_DCPS2 0b10100010 +#define INSN_DCPS3 0b10100011 + + switch (decode_field) { + case INSN_SVC: + case INSN_HVC: + case INSN_SMC: + *immediate = imm16; + *type = INSN_CONTEXT_SWITCH; + return 0; + case INSN_BRK: + if (imm16 == 0x800) + *type = INSN_BUG; + else if (imm16 == 0x100 || imm16 >= 0x900) + *type = INSN_CONTEXT_SWITCH; + else + *type = INSN_OTHER; + return 0; + case INSN_HLT: + case INSN_DCPS1: + case INSN_DCPS2: + case INSN_DCPS3: + *immediate = imm16; + *type = INSN_OTHER; + return 0; + default: + return arm_decode_unknown(instr, type, immediate, op); + } + +#undef INSN_SVC +#undef INSN_HVC +#undef INSN_SMC +#undef INSN_BRK +#undef INSN_HLT +#undef INSN_DCPS1 +#undef INSN_DCPS2 +#undef INSN_DCPS3 +} + +int arm_decode_hints(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + *type = INSN_NOP; + return 0; +} + +int arm_decode_barriers(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + /* TODO:check unallocated */ + *type = INSN_OTHER; + return 0; +} + +int arm_decode_pstate(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + /* TODO:check unallocated */ + *type = INSN_OTHER; + return 0; +} + +int arm_decode_system_insn(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + /* TODO:check unallocated */ + *type = INSN_OTHER; + return 0; +} + +int arm_decode_system_regs(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + /* TODO:check unallocated */ + *type = INSN_OTHER; + return 0; +} + +static struct aarch64_insn_decoder ret_decoder[] = { + /* + * RET, RETAA, RETAB + */ + { + .mask = 0b1111111111111110000011111, + .value = 0b0010111110000000000000000, + .decode_func = NULL, + }, + { + .mask = 0b1111111111111111111111111, + .value = 0b0010111110000101111111111, + .decode_func = NULL, + }, + { + .mask = 0b1111111111111111111111111, + .value = 0b0010111110000111111111111, + .decode_func = NULL, + }, +}; + +static struct aarch64_insn_decoder br_decoder[] = { + /* + * BR, BRAA, BRAAZ, BRAB, BRABZ + */ + { + .mask = 0b1111111111111110000011111, + .value = 0b0000111110000000000000000, + .decode_func = NULL, + }, + { + .mask = 0b1111111111111110000011111, + .value = 0b0000111110000100000011111, + .decode_func = NULL, + }, + { + .mask = 0b1111111111111110000011111, + .value = 0b0000111110000110000011111, + .decode_func = NULL, + }, + { + .mask = 0b1111111111111110000000000, + .value = 0b1000111110000100000000000, + .decode_func = NULL, + }, + { + .mask = 0b1111111111111110000000000, + .value = 0b1000111110000110000000000, + .decode_func = NULL, + }, +}; + +#define INSN_DRPS_FIELD 0b0101111110000001111100000 +#define INSN_DRPS_MASK 0b1111111111111111111111111 + +static struct aarch64_insn_decoder ct_sw_decoder[] = { + /* + * ERET, ERETAA, ERETAB + */ + { + .mask = INSN_DRPS_MASK, + .value = 0b0100111110000001111100000, + .decode_func = NULL, + }, + { + .mask = INSN_DRPS_MASK, + .value = 0b0100111110000101111111111, + .decode_func = NULL, + }, + { + .mask = INSN_DRPS_MASK, + .value = 0b0100111110000111111111111, + .decode_func = NULL, + }, +}; + +static struct aarch64_insn_decoder call_decoder[] = { + /* + * BLR, BLRAA, BLRAAZ, BLRAB, BLRABZ + */ + { + .mask = 0b1111111111111110000011111, + .value = 0b0001111110000000000000000, + .decode_func = NULL, + }, + { + .mask = 0b1111111111111110000011111, + .value = 0b0001111110000100000011111, + .decode_func = NULL, + }, + { + 0b1111111111111110000011111, + 0b0001111110000110000011111, + .decode_func = NULL, + }, + { + .mask = 0b1111111111111110000000000, + .value = 0b1001111110000100000000000, + .decode_func = NULL, + }, + { + .mask = 0b1111111111111110000000000, + .value = 0b1001111110000110000000000, + .decode_func = NULL, + }, +}; + +int arm_decode_br_uncond_reg(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + u32 decode_field = 0; + int i = 0; + + decode_field = instr & ONES(25); + *type = 0; + for (i = 0; i < ARRAY_SIZE(br_decoder); i++) { + if ((decode_field & br_decoder[i].mask) == br_decoder[i].value) + *type = INSN_JUMP_DYNAMIC; + } + for (i = 0; i < ARRAY_SIZE(call_decoder); i++) { + if ((decode_field & call_decoder[i].value) == + call_decoder[i].value) + *type = INSN_CALL_DYNAMIC; + } + for (i = 0; i < ARRAY_SIZE(ret_decoder); i++) { + if ((decode_field & ret_decoder[i].mask) == + ret_decoder[i].value) + *type = INSN_RETURN; + } + for (i = 0; i < ARRAY_SIZE(ct_sw_decoder); i++) { + if ((decode_field & ct_sw_decoder[i].mask) == + ct_sw_decoder[i].value) + *type = INSN_CONTEXT_SWITCH; + } + if ((decode_field & INSN_DRPS_MASK) == INSN_DRPS_FIELD) + *type = INSN_OTHER; + if (*type == 0) + return arm_decode_unknown(instr, type, immediate, op); + return 0; +} + +#undef INSN_DRPS_FIELD +#undef INSN_DRPS_MASK + +int arm_decode_br_uncond_imm(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + unsigned char decode_field = 0; + u32 imm26 = 0; + + decode_field = EXTRACT_BIT(instr, 31); + imm26 = instr & ONES(26); + + *immediate = SIGN_EXTEND(imm26 << 2, 28); + if (decode_field == 0) + *type = INSN_JUMP_UNCONDITIONAL; + else + *type = INSN_CALL; + + return 0; +} + +int arm_decode_br_comp_imm(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + u32 imm19 = (instr >> 5) & ONES(19); + + *immediate = SIGN_EXTEND(imm19 << 2, 21); + *type = INSN_JUMP_CONDITIONAL; + return 0; +} + +int arm_decode_br_tst_imm(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + u32 imm14 = (instr >> 5) & ONES(14); + + *immediate = SIGN_EXTEND(imm14 << 2, 16); + *type = INSN_JUMP_CONDITIONAL; + return 0; +} + +static struct aarch64_insn_decoder ld_st_decoder[] = { + { + .mask = 0b101111111111100, + .value = 0b000010000000000, + .decode_func = arm_decode_adv_simd_mult, + }, + { + .mask = 0b101111110000000, + .value = 0b000010100000000, + .decode_func = arm_decode_adv_simd_mult_post, + }, + { + .mask = 0b101111101111100, + .value = 0b000011000000000, + .decode_func = arm_decode_adv_simd_single, + }, + { + .mask = 0b101111100000000, + .value = 0b000011100000000, + .decode_func = arm_decode_adv_simd_single_post, + }, + { + .mask = 0b111111010000000, + .value = 0b110101010000000, + .decode_func = arm_decode_ld_st_mem_tags, + }, + { + .mask = 0b001111000000000, + .value = 0b000000000000000, + .decode_func = arm_decode_ld_st_exclusive, + }, + { + .mask = 0b001111010000011, + .value = 0b000101000000000, + .decode_func = arm_decode_ldapr_stlr_unsc_imm, + }, + { + .mask = 0b001101000000000, + .value = 0b000100000000000, + .decode_func = arm_decode_ld_regs_literal, + }, + { + .mask = 0b001101100000000, + .value = 0b001000000000000, + .decode_func = arm_decode_ld_st_noalloc_pair_off, + }, + { + .mask = 0b001101100000000, + .value = 0b001000100000000, + .decode_func = arm_decode_ld_st_regs_pair_post, + }, + { + .mask = 0b001101100000000, + .value = 0b001001000000000, + .decode_func = arm_decode_ld_st_regs_pair_off, + }, + { + .mask = 0b001101100000000, + .value = 0b001001100000000, + .decode_func = arm_decode_ld_st_regs_pair_pre, + }, + { + .mask = 0b001101010000011, + .value = 0b001100000000000, + .decode_func = arm_decode_ld_st_regs_unsc_imm, + }, + { + .mask = 0b001101010000011, + .value = 0b001100000000001, + .decode_func = arm_decode_ld_st_imm_post, + }, + { + .mask = 0b001101010000011, + .value = 0b001100000000010, + .decode_func = arm_decode_ld_st_imm_unpriv, + }, + { + .mask = 0b001101010000011, + .value = 0b001100000000011, + .decode_func = arm_decode_ld_st_imm_pre, + }, + { + .mask = 0b001101010000011, + .value = 0b001100010000000, + .decode_func = arm_decode_atomic, + }, + { + .mask = 0b001101010000011, + .value = 0b001100010000010, + .decode_func = arm_decode_ld_st_regs_off, + }, + { + .mask = 0b001101010000001, + .value = 0b001100010000001, + .decode_func = arm_decode_ld_st_regs_pac, + }, + { + .mask = 0b001101000000000, + .value = 0b001101000000000, + .decode_func = arm_decode_ld_st_regs_unsigned, + }, +}; + +int arm_decode_ld_st(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + u32 decode_field = 0; + int i = 0; + unsigned char op0 = 0, op1 = 0, op2 = 0, op3 = 0, op4 = 0; + + op0 = (instr >> 28) & ONES(4); + op1 = EXTRACT_BIT(instr, 26); + op2 = (instr >> 23) & ONES(2); + op3 = (instr >> 16) & ONES(6); + op4 = (instr >> 10) & ONES(2); + decode_field = (op0 << 3) | (op1 << 2) | op2; + decode_field = (decode_field << 8) | (op3 << 2) | op4; + + for (i = 0; i < ARRAY_SIZE(ld_st_decoder); i++) { + if ((decode_field & ld_st_decoder[i].mask) == + ld_st_decoder[i].value) { + return ld_st_decoder[i].decode_func(instr, + type, + immediate, + op); + } + } + return arm_decode_unknown(instr, type, immediate, op); +} + +static int adv_simd_mult_fields[] = { + 0b00000, + 0b00010, + 0b00100, + 0b00110, + 0b00111, + 0b01000, + 0b01010, + 0b10000, + 0b10010, + 0b10100, + 0b10110, + 0b10111, + 0b11000, + 0b11010, +}; + +int arm_decode_adv_simd_mult(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + unsigned char L = 0, opcode = 0, rn = 0, rt = 0; + unsigned char decode_field = 0; + int i = 0; + + L = EXTRACT_BIT(instr, 22); + opcode = (instr >> 12) & ONES(4); + + decode_field = (L << 4) | opcode; + rn = (instr >> 5) & ONES(5); + rt = instr & ONES(5); + *type = INSN_OTHER; + + for (i = 0; i < ARRAY_SIZE(adv_simd_mult_fields); i++) { + if ((decode_field & 0b11111) == adv_simd_mult_fields[i]) { + if (rn != 31) + return 0; + *type = INSN_STACK; + } + } + if (*type != INSN_STACK) + return arm_decode_unknown(instr, type, immediate, op); + + if (!L) { + op->dest.type = OP_DEST_REG_INDIRECT; + op->dest.reg = CFI_SP; + op->dest.offset = 0; + op->src.type = OP_SRC_REG; + op->src.reg = rt; + op->src.offset = 0; + } else { + op->src.type = OP_SRC_REG_INDIRECT; + op->src.reg = CFI_SP; + op->src.offset = 0; + op->dest.type = OP_SRC_REG; + op->dest.reg = rt; + op->dest.offset = 0; + } + + return 0; +} + +int arm_decode_adv_simd_mult_post(u32 instr, unsigned char *type, + unsigned long *immediate, + struct stack_op *op) +{ + /* same opcode as for the no offset variant */ + unsigned char rm = 0; + int ret = 0; + + rm = (instr >> 16) & ONES(5); + + ret = arm_decode_adv_simd_mult(instr, type, immediate, op); + + /* + * This is actually irrelevant if the offset is given by a register + * however there is no way to know the offset value from the encoding + * in such a case. + */ + if (op->dest.type == OP_DEST_REG_INDIRECT) + op->dest.offset = rm; + if (op->src.type == OP_SRC_REG_INDIRECT) + op->src.offset = rm; + return ret; +} + +static struct aarch64_insn_decoder simd_single_decoder[] = { + { + .mask = 0b11111000, + .value = 0b00000000, + .decode_func = NULL, + }, + { + .mask = 0b11111000, + .value = 0b00001000, + .decode_func = NULL, + }, + { + .mask = 0b11111001, + .value = 0b00010000, + .decode_func = NULL, + }, + { + .mask = 0b11111001, + .value = 0b00011000, + .decode_func = NULL, + }, + { + .mask = 0b11111011, + .value = 0b00100000, + .decode_func = NULL, + }, + { + .mask = 0b11111111, + .value = 0b00100001, + .decode_func = NULL, + }, + { + .mask = 0b11111011, + .value = 0b00101000, + .decode_func = NULL, + }, + { + .mask = 0b11111111, + .value = 0b00101001, + .decode_func = NULL, + }, + { + .mask = 0b11111000, + .value = 0b01000000, + .decode_func = NULL, + }, + { + .mask = 0b11111000, + .value = 0b01001000, + .decode_func = NULL, + }, + { + .mask = 0b11111001, + .value = 0b01010000, + .decode_func = NULL, + }, + { + .mask = 0b11111001, + .value = 0b01011000, + .decode_func = NULL, + }, + { + .mask = 0b11111011, + .value = 0b01100000, + .decode_func = NULL, + }, + { + .mask = 0b11111111, + .value = 0b01100001, + .decode_func = NULL, + }, + { + .mask = 0b11111011, + .value = 0b01101000, + .decode_func = NULL, + }, + { + .mask = 0b11111111, + .value = 0b01101001, + .decode_func = NULL, + }, + { + .mask = 0b11111000, + .value = 0b10000000, + .decode_func = NULL, + }, + { + .mask = 0b11111000, + .value = 0b10001000, + .decode_func = NULL, + }, + { + .mask = 0b11111001, + .value = 0b10010000, + .decode_func = NULL, + }, + { + .mask = 0b11111001, + .value = 0b10011000, + .decode_func = NULL, + }, + { + .mask = 0b11111011, + .value = 0b10100000, + .decode_func = NULL, + }, + { + .mask = 0b11111111, + .value = 0b10100001, + .decode_func = NULL, + }, + { + .mask = 0b11111011, + .value = 0b10101000, + .decode_func = NULL, + }, + { + .mask = 0b11111111, + .value = 0b10101001, + .decode_func = NULL, + }, + { + .mask = 0b11111100, + .value = 0b10110000, + .decode_func = NULL, + }, + { + .mask = 0b11111100, + .value = 0b10111000, + .decode_func = NULL, + }, + { + .mask = 0b11000000, + .value = 0b11111000, + .decode_func = NULL, + }, + { + .mask = 0b11111000, + .value = 0b11001000, + .decode_func = NULL, + }, + { + .mask = 0b11111001, + .value = 0b11010000, + .decode_func = NULL, + }, + { + .mask = 0b11111001, + .value = 0b11011000, + .decode_func = NULL, + }, + { + .mask = 0b11111011, + .value = 0b11100000, + .decode_func = NULL, + }, + { + .mask = 0b11111111, + .value = 0b11100001, + .decode_func = NULL, + }, + { + .mask = 0b11111011, + .value = 0b11101000, + .decode_func = NULL, + }, + { + .mask = 0b11111111, + .value = 0b11101001, + .decode_func = NULL, + }, + { + .mask = 0b11111100, + .value = 0b11110000, + .decode_func = NULL, + }, + { + .mask = 0b11111100, + .value = 0b11111000, + .decode_func = NULL, + }, +}; + +int arm_decode_adv_simd_single(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + unsigned char L = 0, R = 0, S = 0, opcode = 0, size = 0; + unsigned char rn = 0, rt = 0, dfield = 0; + int i = 0; + + L = EXTRACT_BIT(instr, 22); + R = EXTRACT_BIT(instr, 21); + S = EXTRACT_BIT(instr, 12); + opcode = (instr >> 13) & ONES(3); + size = (instr >> 10) & ONES(2); + + dfield = (L << 7) | (R << 6) | (opcode << 3) | (S << 2) | size; + + *type = INSN_OTHER; + rn = (instr << 5) & ONES(5); + + for (i = 0; i < ARRAY_SIZE(simd_single_decoder); i++) { + if ((dfield & simd_single_decoder[i].mask) == + simd_single_decoder[i].value) { + if (rn != CFI_SP) + return 0; + *type = INSN_STACK; + } + } + + if (*type == INSN_OTHER) + return arm_decode_unknown(instr, type, immediate, op); + + rt = instr & ONES(5); + if (!L) { + op->dest.type = OP_DEST_REG_INDIRECT; + op->dest.reg = CFI_SP; + op->dest.offset = 0; + op->src.type = OP_SRC_REG; + op->src.reg = rt; + op->src.offset = 0; + } else { + op->src.type = OP_SRC_REG_INDIRECT; + op->src.reg = CFI_SP; + op->src.offset = 0; + op->dest.type = OP_DEST_REG; + op->dest.reg = rt; + op->dest.offset = 0; + } + return 0; +} + +int arm_decode_adv_simd_single_post(u32 instr, unsigned char *type, + unsigned long *immediate, + struct stack_op *op) +{ + /* same opcode as for the no offset variant */ + unsigned char rm = 0; + int ret = 0; + + rm = (instr >> 16) & ONES(5); + + ret = arm_decode_adv_simd_single(instr, type, immediate, op); + + /* + * This is actually irrelevant if the offset is given by a register + * however there is no way to know the offset value from the encoding + * in such a case. + */ + if (op->dest.type == OP_DEST_REG_INDIRECT) + op->dest.offset = rm; + if (op->src.type == OP_SRC_REG_INDIRECT) + op->src.offset = rm; + return ret; +} + +int arm_decode_ld_st_mem_tags(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + u32 imm9 = 0; + unsigned char opc = 0, op2 = 0, rn = 0, rt = 0, decode_field = 0; + + imm9 = (instr >> 12) & ONES(9); + opc = (instr >> 22) & ONES(2); + op2 = (instr >> 10) & ONES(2); + rn = (instr >> 5) & ONES(5); + rt = instr & ONES(6); + + decode_field = (opc << 2) | op2; + + if (decode_field == 0x0 || + (decode_field == 0x8 && imm9 != 0) || + (decode_field == 0xC && imm9 != 0)) { + return arm_decode_unknown(instr, type, immediate, op); + } + + if (rn != CFI_SP) { + *type = INSN_OTHER; + return 0; + } + *type = INSN_STACK; + *immediate = imm9; + + /* + * Offset should normally be shifted to the + * left of LOG2_TAG_GRANULE + */ + switch (decode_field) { + case 1: + case 5: + case 9: + case 13: + /* post index */ + case 3: + case 7: + case 8: + case 11: + case 15: + /* pre index */ + op->dest.reg = CFI_SP; + op->dest.type = OP_DEST_PUSH; + op->dest.offset = SIGN_EXTEND(imm9, 9); + op->src.reg = rt; + op->src.type = OP_SRC_REG; + op->src.offset = 0; + return 0; + case 2: + case 6: + case 10: + case 14: + /* store */ + op->dest.reg = CFI_SP; + op->dest.type = OP_DEST_REG_INDIRECT; + op->dest.offset = SIGN_EXTEND(imm9, 9); + op->src.reg = rt; + op->src.type = OP_SRC_REG; + op->src.offset = 0; + return 0; + case 4: + case 12: + /* load */ + op->src.reg = CFI_SP; + op->src.type = OP_SRC_REG_INDIRECT; + op->src.offset = SIGN_EXTEND(imm9, 9); + op->dest.reg = rt; + op->dest.type = OP_DEST_REG; + op->dest.offset = 0; + return 0; + } + + return -1; +} + +#define ST_EXCL_UNALLOC_1 0b001010 +#define ST_EXCL_UNALLOC_2 0b000010 + +#define LDXRB 0b000100 +#define LDAXRB 0b000101 +#define LDLARB 0b001100 +#define LDARB 0b001101 +#define LDXRH 0b010100 +#define LDAXRH 0b010101 +#define LDLARH 0b011100 +#define LDARH 0b011101 +#define LDXR 0b100100 +#define LDAXR 0b100101 +#define LDXP 0b100110 +#define LDAXP 0b100111 +#define LDLAR 0b101100 +#define LDAR 0b101101 +#define LDXR_64 0b110100 +#define LDAXR_64 0b110101 +#define LDXP_64 0b110110 +#define LDAXP_64 0b110111 +#define LDLAR_64 0b111100 +#define LDAR_64 0b111101 + +#define LD_EXCL_NUMBER 20 + +static int ld_excl_masks[] = { + LDXRB, + LDAXRB, + LDLARB, + LDARB, + LDXRH, + LDAXRH, + LDLARH, + LDARH, + LDXR, + LDAXR, + LDXP, + LDAXP, + LDLAR, + LDAR, + LDXR_64, + LDAXR_64, + LDXP_64, + LDAXP_64, + LDLAR_64, + LDAR_64, +}; + +int arm_decode_ld_st_exclusive(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + unsigned char size = 0, o2 = 0, L = 0, o1 = 0, o0 = 0; + unsigned char rt = 0, rt2 = 0, rn = 0; + unsigned char decode_field = 0; + int i = 0; + + size = (instr >> 30) & ONES(2); + o2 = EXTRACT_BIT(instr, 23); + L = EXTRACT_BIT(instr, 22); + o1 = EXTRACT_BIT(instr, 21); + o0 = EXTRACT_BIT(instr, 15); + + rt2 = (instr >> 10) & ONES(5); + rn = (instr >> 5) & ONES(5); + rt = instr & ONES(5); + + decode_field = (size << 4) | (o2 << 3) | (L << 2) | (o1 << 1) | o0; + + if ((decode_field & ST_EXCL_UNALLOC_1) == ST_EXCL_UNALLOC_1 || + (decode_field & 0b101010) == ST_EXCL_UNALLOC_2) { + if (rt2 != 31) + return arm_decode_unknown(instr, type, immediate, op); + } + + if (rn != 31) { + *type = INSN_OTHER; + return 0; + } + + *type = INSN_STACK; + for (i = 0; i < LD_EXCL_NUMBER; i++) { + if ((decode_field & 0b111111) == ld_excl_masks[i]) { + op->src.type = OP_SRC_REG_INDIRECT; + op->src.reg = CFI_SP; + op->src.offset = 0; + op->dest.type = OP_DEST_REG; + op->dest.reg = rt; + op->dest.offset = 0; + return 0; + } + } + + op->dest.type = OP_DEST_REG_INDIRECT; + op->dest.reg = CFI_SP; + op->dest.offset = 0; + op->src.type = OP_SRC_REG; + op->src.reg = rt; + op->src.offset = 0; + + return 0; +} + +#undef ST_EXCL_UNALLOC_1 +#undef ST_EXCL_UNALLOC_2 + +#undef LD_EXCL_NUMBER + +#undef LDXRB +#undef LDAXRB +#undef LDLARB +#undef LDARB +#undef LDXRH +#undef LDAXRH +#undef LDLARH +#undef LDARH +#undef LDXR +#undef LDAXR +#undef LDXP +#undef LDAXP +#undef LDLAR +#undef LDAR +#undef LDXR_64 +#undef LDAXR_64 +#undef LDXP_64 +#undef LDAXP_64 +#undef LDLAR_64 +#undef LDAR_64 + +int arm_decode_ldapr_stlr_unsc_imm(u32 instr, unsigned char *type, + unsigned long *immediate, + struct stack_op *op) +{ + u32 imm9 = 0; + unsigned char size = 0, opc = 0, rn = 0, rt = 0, decode_field = 0; + + imm9 = (instr >> 12) & ONES(9); + size = (instr >> 30) & ONES(2); + opc = (instr >> 22) & ONES(2); + rn = (instr >> 5) & ONES(5); + rt = instr & ONES(5); + + decode_field = (size << 2) | opc; + if (decode_field == 0xB || + decode_field == 0xE || + decode_field == 0xF) { + return arm_decode_unknown(instr, type, immediate, op); + } + + if (rn != 31) { + *type = INSN_OTHER; + return 0; + } + *type = INSN_STACK; + *immediate = imm9; + switch (decode_field) { + case 1: + case 2: + case 3: + case 5: + case 6: + case 7: + case 9: + case 10: + case 13: + /* load */ + op->src.type = OP_SRC_REG_INDIRECT; + op->src.reg = CFI_SP; + op->src.offset = SIGN_EXTEND(imm9, 9); + op->dest.type = OP_DEST_REG; + op->dest.reg = rt; + op->dest.offset = 0; + break; + default: + /* store */ + op->dest.type = OP_SRC_REG_INDIRECT; + op->dest.reg = CFI_SP; + op->dest.offset = SIGN_EXTEND(imm9, 9); + op->src.type = OP_SRC_REG; + op->src.reg = rt; + op->src.offset = 0; + break; + } + + return 0; +} + +int arm_decode_ld_regs_literal(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + unsigned char opc = 0, V = 0; + + opc = (instr >> 30) & ONES(2); + V = EXTRACT_BIT(instr, 26); + + if (((opc << 1) | V) == 0x7) + return arm_decode_unknown(instr, type, immediate, op); + + *type = INSN_OTHER; + return 0; +} + +int arm_decode_ld_st_noalloc_pair_off(u32 instr, unsigned char *type, + unsigned long *immediate, + struct stack_op *op) +{ + unsigned char opc = 0, V = 0, L = 0; + unsigned char decode_field = 0; + + opc = (instr >> 30) & ONES(2); + V = EXTRACT_BIT(instr, 26); + L = EXTRACT_BIT(instr, 22); + + decode_field = (opc << 2) | (V << 1) | L; + + if (decode_field == 0x4 || + decode_field == 0x5 || + decode_field >= 12) { + return arm_decode_unknown(instr, type, immediate, op); + } + return arm_decode_ld_st_regs_pair_off(instr, type, immediate, op); +} + +int arm_decode_ld_st_regs_pair_off(u32 instr, unsigned char *type, + unsigned long *immediate, + struct stack_op *op) +{ + unsigned char opc = 0, V = 0, L = 0, bit = 0; + unsigned char imm7 = 0, rt2 = 0, rt = 0, rn = 0; + unsigned char decode_field = 0; + int scale = 0; + + opc = (instr >> 30) & ONES(2); + V = EXTRACT_BIT(instr, 26); + L = EXTRACT_BIT(instr, 22); + imm7 = (instr >> 15) & ONES(7); + rt2 = (instr >> 10) & ONES(5); + rn = (instr >> 5) & ONES(5); + rt = instr & ONES(5); + bit = EXTRACT_BIT(opc, 1); + scale = 2 + bit; + + decode_field = (opc << 2) | (V << 1) | L; + + if (decode_field >= 0xC) + return arm_decode_unknown(instr, type, immediate, op); + + *immediate = (SIGN_EXTEND(imm7, 7)) << scale; + + if (rn != CFI_SP) { + *type = INSN_OTHER; + return 0; + } + + *type = INSN_STACK; + + switch (decode_field) { + case 1: + case 3: + case 5: + case 7: + case 9: + case 11: + /* load */ + op->src.type = OP_SRC_REG_INDIRECT; + op->src.reg = CFI_SP; + op->src.offset = 0; + op->dest.type = OP_DEST_REG; + op->dest.reg = rt; + op->dest.offset = 0; + op->extra.used = 1; + op->extra.reg = rt2; + op->extra.offset = 8; + break; + default: + op->dest.type = OP_DEST_REG_INDIRECT; + op->dest.reg = CFI_SP; + op->dest.offset = 8; + op->src.type = OP_SRC_REG; + op->src.reg = rt2; + op->src.offset = 0; + op->extra.used = 1; + op->extra.reg = rt; + op->extra.offset = 0; + /* store */ + } + return 0; +} + +int arm_decode_ld_st_regs_pair_post(u32 instr, unsigned char *type, + unsigned long *immediate, + struct stack_op *op) +{ + int ret = 0; + + ret = arm_decode_ld_st_regs_pair_off(instr, type, immediate, op); + if (ret < 0 || *type == INSN_OTHER) + return ret; + if (op->dest.type == OP_DEST_REG_INDIRECT) { + op->dest.type = OP_DEST_PUSH; + op->dest.reg = CFI_SP; + } + + if (op->src.type == OP_SRC_REG_INDIRECT) { + op->src.type = OP_SRC_POP; + op->src.reg = CFI_SP; + } + + return ret; +} + +int arm_decode_ld_st_regs_pair_pre(u32 instr, unsigned char *type, + unsigned long *immediate, + struct stack_op *op) +{ + return arm_decode_ld_st_regs_pair_post(instr, type, immediate, op); +} + +int arm_decode_ld_st_regs_unsc_imm(u32 instr, unsigned char *type, + unsigned long *immediate, + struct stack_op *op) +{ + u32 imm9 = 0; + unsigned char size = 0, V = 0, opc = 0, rn = 0, rt = 0; + unsigned char decode_field = 0; + + size = (instr >> 30) & ONES(2); + V = EXTRACT_BIT(instr, 26); + opc = (instr >> 22) & ONES(2); + + imm9 = (instr >> 12) & ONES(9); + rn = (instr >> 5) & ONES(5); + rt = instr & ONES(5); + + decode_field = (size << 2) | (V << 2) | opc; + + switch (decode_field) { + case 0b01110: + case 0b01111: + case 0b11110: + case 0b11111: + case 0b10011: + case 0b11011: + case 0b10110: + case 0b10111: + return arm_decode_unknown(instr, type, immediate, op); + case 26: + /* prefetch */ + *type = INSN_OTHER; + return 0; + case 1: + case 2: + case 3: + case 5: + case 7: + case 9: + case 10: + case 11: + case 13: + case 17: + case 18: + case 21: + case 25: + case 29: + /* load */ + if (rn != CFI_SP) { + *type = INSN_OTHER; + return 0; + } + op->src.type = OP_SRC_REG_INDIRECT; + op->src.reg = CFI_SP; + op->src.offset = SIGN_EXTEND(imm9, 9); + op->dest.type = OP_DEST_REG; + op->dest.reg = rt; + op->dest.offset = 0; + break; + default: + if (rn != CFI_SP) { + *type = INSN_OTHER; + return 0; + } + op->dest.type = OP_DEST_REG_INDIRECT; + op->dest.reg = CFI_SP; + op->dest.offset = SIGN_EXTEND(imm9, 9); + op->src.type = OP_DEST_REG; + op->src.reg = rt; + op->src.offset = 0; + break; + } + + *type = INSN_STACK; + return 0; +} + +static struct aarch64_insn_decoder ld_unsig_unalloc_decoder[] = { + { + .mask = 0b01110, + .value = 0b01110, + }, + { + .mask = 0b10111, + .value = 0b10011, + }, + { + .mask = 0b10110, + .value = 0b10110, + }, +}; + +int arm_decode_ld_st_regs_unsigned(u32 instr, unsigned char *type, + unsigned long *immediate, + struct stack_op *op) +{ + unsigned char size = 0, V = 0, opc = 0, rn = 0, rt = 0; + unsigned char decode_field = 0; + u32 imm12 = 0; + int i = 0; + + size = (instr >> 30) & ONES(2); + V = EXTRACT_BIT(instr, 26); + opc = (instr >> 22) & ONES(2); + + decode_field = (size << 3) | (V << 2) | opc; + for (i = 0; i < ARRAY_SIZE(ld_unsig_unalloc_decoder); i++) { + if ((decode_field & ld_unsig_unalloc_decoder[i].mask) == + ld_unsig_unalloc_decoder[i].value) { + return arm_decode_unknown(instr, type, + immediate, op); + } + } + + imm12 = (instr >> 10) & ONES(12); + rn = (instr >> 5) & ONES(5); + rt = instr & ONES(5); + + if (rn != CFI_SP || decode_field == 26) { + *type = INSN_OTHER; + return 0; + } + + *type = INSN_STACK; + + switch (decode_field) { + case 1: + case 2: + case 3: + case 5: + case 7: + case 9: + case 10: + case 11: + case 13: + case 17: + case 18: + case 21: + case 25: + /* load */ + op->src.type = OP_SRC_REG_INDIRECT; + op->src.reg = CFI_SP; + op->src.offset = imm12; + op->dest.type = OP_DEST_REG; + op->dest.reg = rt; + op->dest.offset = 0; + break; + default: /* store */ + op->dest.type = OP_DEST_REG_INDIRECT; + op->dest.reg = CFI_SP; + op->dest.offset = imm12; + op->src.type = OP_DEST_REG; + op->src.reg = rt; + op->src.offset = 0; + } + + return 0; +} + +int arm_decode_ld_st_imm_post(u32 instr, unsigned char *type, + unsigned long *immediate, + struct stack_op *op) +{ + unsigned char size = 0, V = 0, opc = 0; + unsigned char decode_field = 0; + u32 imm9 = 0; + int ret = 0; + + size = (instr >> 30) & ONES(2); + V = EXTRACT_BIT(instr, 26); + opc = (instr >> 22) & ONES(2); + + imm9 = (instr >> 12) & ONES(9); + + decode_field = (size << 2) | (V << 2) | opc; + + if (decode_field == 0b11010) + return arm_decode_unknown(instr, type, immediate, op); + + ret = arm_decode_ld_st_regs_unsigned(instr, type, immediate, op); + if (ret < 0 || *type == INSN_OTHER) + return ret; + + if (op->dest.type == OP_DEST_REG_INDIRECT) { + op->dest.type = OP_DEST_PUSH; + op->dest.reg = CFI_SP; + op->dest.offset = SIGN_EXTEND(imm9, 9); + } + + if (op->src.type == OP_SRC_REG_INDIRECT) { + op->src.type = OP_SRC_POP; + op->src.reg = CFI_SP; + op->src.offset = SIGN_EXTEND(imm9, 9); + } + + return 0; +} + +int arm_decode_ld_st_imm_pre(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + return arm_decode_ld_st_imm_post(instr, type, immediate, op); +} + +#define LD_UNPR_UNALLOC_1 0b10011 +#define LD_UNPR_UNALLOC_2 0b11010 +int arm_decode_ld_st_imm_unpriv(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + unsigned char size = 0, V = 0, opc = 0, rn = 0, rt = 0; + unsigned char decode_field = 0; + u32 imm9 = 0; + + size = (instr >> 30) & ONES(2); + V = EXTRACT_BIT(instr, 26); + opc = (instr >> 22) & ONES(2); + + imm9 = (instr >> 12) & ONES(9); + + decode_field = (size << 3) | (V << 2) | opc; + if (V == 1 || + (decode_field & 0b10111) == LD_UNPR_UNALLOC_1 || + (decode_field & 0b11111) == LD_UNPR_UNALLOC_2) { + return arm_decode_unknown(instr, type, immediate, op); + } +#undef LD_UNPR_UNALLOC_1 +#undef LD_UNPR_UNALLOC_2 + + if (rn != CFI_SP) { + *type = INSN_OTHER; + return 0; + } + *type = INSN_STACK; + + switch (decode_field) { + case 1: + case 2: + case 3: + case 9: + case 10: + case 11: + case 17: + case 18: + case 25: + /* load */ + op->src.type = OP_SRC_REG_INDIRECT; + op->src.reg = CFI_SP; + op->src.offset = SIGN_EXTEND(imm9, 9); + op->dest.type = OP_DEST_REG; + op->dest.reg = rt; + op->dest.offset = 0; + break; + default: + /* store */ + op->dest.type = OP_DEST_REG_INDIRECT; + op->dest.reg = CFI_SP; + op->dest.offset = SIGN_EXTEND(imm9, 9); + op->src.type = OP_DEST_REG; + op->src.reg = rt; + op->src.offset = 0; + break; + } + return 0; +} + +static struct aarch64_insn_decoder atom_unallocs_decoder[] = { + { + .mask = 0b1001111, + .value = 0b0001001, + }, + { + .mask = 0b1001110, + .value = 0b0001010, + }, + { + .mask = 0b1001111, + .value = 0b0001101, + }, + { + .mask = 0b1001110, + .value = 0b0001110, + }, + { + .mask = 0b1101111, + .value = 0b0001100, + }, + { + .mask = 0b1111111, + .value = 0b0111100, + }, + { + .mask = 0b1000000, + .value = 0b1000000, + }, +}; + +int arm_decode_atomic(u32 instr, unsigned char *type, + unsigned long *immediate, + struct stack_op *op) +{ + unsigned char V = 0, A = 0, R = 0, o3 = 0, opc = 0; + unsigned char rn = 0, rt = 0; + unsigned char decode_field = 0; + int i = 0; + + V = EXTRACT_BIT(instr, 26); + A = EXTRACT_BIT(instr, 23); + R = EXTRACT_BIT(instr, 22); + o3 = EXTRACT_BIT(instr, 15); + opc = (instr >> 12) & ONES(3); + + decode_field = (V << 6) | (A << 5) | (R << 4) | (o3 << 3) | opc; + + for (i = 0; i < ARRAY_SIZE(atom_unallocs_decoder); i++) { + if ((decode_field & atom_unallocs_decoder[i].mask) == + atom_unallocs_decoder[i].value) { + return arm_decode_unknown(instr, + type, + immediate, + op); + } + } + + rn = (instr >> 5) & ONES(5); + rt = instr & ONES(5); + + if (rn != CFI_SP) { + *type = INSN_OTHER; + return 0; + } + *type = INSN_STACK; + op->src.reg = CFI_SP; + op->src.type = OP_DEST_REG_INDIRECT; + op->src.offset = 0; + op->dest.type = OP_DEST_REG; + op->dest.reg = rt; + op->dest.offset = 0; + + return 0; +} + +int arm_decode_ld_st_regs_off(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + unsigned char size = 0, V = 0, opc = 0, option = 0; + unsigned char rm = 0, rn = 0, rt = 0; + unsigned char decode_field = 0; + + size = (instr >> 30) & ONES(2); + V = EXTRACT_BIT(instr, 26); + opc = (instr >> 22) & ONES(2); + option = (instr >> 13) & ONES(3); + +#define LD_ROFF_UNALLOC_1 0b01110 +#define LD_ROFF_UNALLOC_2 0b10110 +#define LD_ROFF_UNALLOC_3 0b10011 + decode_field = (size << 3) | (V << 2) | opc; + if (!EXTRACT_BIT(option, 1) || + (decode_field & LD_ROFF_UNALLOC_1) == LD_ROFF_UNALLOC_1 || + (decode_field & LD_ROFF_UNALLOC_2) == LD_ROFF_UNALLOC_2 || + (decode_field & 0b10111) == LD_ROFF_UNALLOC_3) { + return arm_decode_unknown(instr, type, immediate, op); + } +#undef LD_ROFF_UNALLOC_1 +#undef LD_ROFF_UNALLOC_2 +#undef LD_ROFF_UNALLOC_3 + + rn = (instr >> 5) & ONES(5); + +#define LD_ROFF_PRFM 0b11010 + if (rn != CFI_SP || decode_field == LD_ROFF_PRFM) { + *type = INSN_OTHER; + return 0; + } +#undef LD_ROFF_PRFM + + rt = instr & ONES(5); + rm = (instr >> 16) & ONES(5); + + switch (decode_field & ONES(3)) { + case 0b001: + case 0b010: + case 0b011: + case 0b101: + case 0b111: + /* load */ + op->src.type = OP_SRC_REG_INDIRECT; + op->src.reg = CFI_SP; + op->src.offset = rm; + op->dest.type = OP_DEST_REG; + op->dest.reg = rt; + op->dest.offset = 0; + break; + default: + /* store */ + op->dest.type = OP_DEST_REG_INDIRECT; + op->dest.reg = CFI_SP; + op->dest.offset = rm; + op->src.type = OP_DEST_REG; + op->src.reg = rt; + op->src.offset = 0; + break; + } + + return 0; +} + +int arm_decode_ld_st_regs_pac(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + unsigned char size = 0, V = 0, W = 0, S = 0; + unsigned char rn = 0, rt = 0; + u32 imm9 = 0, s10 = 0; + + size = (instr >> 30) & ONES(2); + V = EXTRACT_BIT(instr, 26); + W = EXTRACT_BIT(instr, 11); + + if (size != 3 || V == 1) + return arm_decode_unknown(instr, type, immediate, op); + + rn = (instr >> 5) & ONES(5); + + if (rn != CFI_SP) { + *type = INSN_OTHER; + return 0; + } + + S = EXTRACT_BIT(instr, 22); + s10 = (S << 9) | imm9; + + op->dest.reg = rt; + op->dest.type = OP_DEST_REG; + op->dest.offset = 0; + op->src.offset = (SIGN_EXTEND(s10, 9) << 3); + if (W) { /* pre-indexed/writeback */ + op->src.type = OP_SRC_POP; + op->src.reg = CFI_SP; + } else { + op->src.type = OP_SRC_REG_INDIRECT; + op->src.reg = CFI_SP; + } + + return 0; +} + +static struct aarch64_insn_decoder dp_reg_decoder[] = { + { + .mask = 0b111111000000, + .value = 0b010110000000, + .decode_func = arm_decode_dp_reg_2src, + }, + { + .mask = 0b111111000000, + .value = 0b110110000000, + .decode_func = arm_decode_dp_reg_1src, + }, + { + .mask = 0b011000000000, + .value = 0b000000000000, + .decode_func = arm_decode_dp_reg_logi, + }, + { + .mask = 0b011001000000, + .value = 0b001000000000, + .decode_func = arm_decode_dp_reg_adds, + }, + { + .mask = 0b011001000000, + .value = 0b001001000000, + .decode_func = arm_decode_dp_reg_adde, + }, + { + .mask = 0b011111111111, + .value = 0b010000000000, + .decode_func = arm_decode_dp_reg_addc, + }, + { + .mask = 0b011111011111, + .value = 0b010000000001, + .decode_func = arm_decode_dp_reg_rota, + }, + { + .mask = 0b011111001111, + .value = 0b010000000010, + .decode_func = arm_decode_dp_reg_eval, + }, + { + .mask = 0b011111000010, + .value = 0b010010000000, + .decode_func = arm_decode_dp_reg_cmpr, + }, + { + .mask = 0b011111000010, + .value = 0b010010000010, + .decode_func = arm_decode_dp_reg_cmpi, + }, + { + .mask = 0b011111000000, + .value = 0b010100000000, + .decode_func = arm_decode_dp_reg_csel, + }, + { + .mask = 0b011000000000, + .value = 0b011000000000, + .decode_func = arm_decode_dp_reg_3src, + }, +}; + +int arm_decode_dp_reg(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + unsigned char op0 = 0, op1 = 0, op2 = 0, op3 = 0; + u32 decode_field = 0; + int i = 0; + + op0 = EXTRACT_BIT(instr, 30); + op1 = EXTRACT_BIT(instr, 28); + op2 = (instr >> 21) & ONES(4); + op3 = (instr >> 10) & ONES(6); + decode_field = (op0 << 5) | (op1 << 4) | op2; + decode_field = (decode_field << 6) | op3; + + for (i = 0; i < ARRAY_SIZE(dp_reg_decoder); i++) { + if ((decode_field & dp_reg_decoder[i].mask) == + dp_reg_decoder[i].value) { + return dp_reg_decoder[i].decode_func(instr, type, + immediate, op); + } + } + return arm_decode_unknown(instr, type, immediate, op); +} + +static struct aarch64_insn_decoder dp_reg_2src_decoder[] = { + { + .mask = 0b00111111, + .value = 0b00000001, + }, + { + .mask = 0b00111000, + .value = 0b00011000, + }, + { + .mask = 0b00100000, + .value = 0b00100000, + }, + { + .mask = 0b01111111, + .value = 0b00000101, + }, + { + .mask = 0b01111100, + .value = 0b00001100, + }, + { + .mask = 0b01111110, + .value = 0b01000010, + }, + { + .mask = 0b01111100, + .value = 0b01000100, + }, + { + .mask = 0b01111000, + .value = 0b01001000, + }, + { + .mask = 0b01110000, + .value = 0b01010000, + }, + { + .mask = 0b10111111, + .value = 0b00000000, + }, + { + .mask = 0b11111111, + .value = 0b00000100, + }, + { + .mask = 0b11111110, + .value = 0b00000110, + }, + { + .mask = 0b11111011, + .value = 0b00010011, + }, + { + .mask = 0b11111001, + .value = 0b10010000, + }, + { + .mask = 0b11111010, + .value = 0b10010000, + }, +}; + +static int dp_reg_2src_stack_fields[] = { + 0b10000000, + 0b10000100, + 0b10000101, + 0b10001100, + 0b11000000, +}; + +int arm_decode_dp_reg_2src(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + unsigned char sf = 0, S = 0, opcode = 0, rn = 0, rd = 0; + unsigned char decode_field = 0; + int i = 0; + + sf = EXTRACT_BIT(instr, 31); + S = EXTRACT_BIT(instr, 29); + opcode = (instr >> 10) & ONES(6); + + decode_field = (sf << 7) | (S << 6) | opcode; + + for (i = 0; i < ARRAY_SIZE(dp_reg_2src_decoder); i++) { + if ((decode_field & dp_reg_2src_decoder[i].mask) == + dp_reg_2src_decoder[i].value) { + return arm_decode_unknown(instr, type, immediate, op); + } + } + + *type = 0; + for (i = 0; i < ARRAY_SIZE(dp_reg_2src_stack_fields); i++) { + if (opcode == dp_reg_2src_stack_fields[i]) { + *type = INSN_OTHER; + break; + } + } + if (*type == 0) { + *type = INSN_OTHER; + return 0; + } + + rn = (instr >> 5) & ONES(5); + rd = instr & ONES(5); + +#define IRG_OPCODE 0b10000100 + if ((rn != CFI_SP && opcode != IRG_OPCODE) || + (opcode == IRG_OPCODE && rd != CFI_SP && + rn != CFI_SP)) { + *type = INSN_OTHER; + return 0; + } +#undef IRG_OPCODE + + *type = INSN_STACK; + op->dest.reg = rd; + op->dest.type = OP_DEST_REG; + op->dest.offset = 0; + + op->src.reg = rn; + op->src.type = OP_DEST_REG; + op->src.offset = 0; + + return 0; +} + +static struct aarch64_insn_decoder dp_reg_1src_decoder[] = { + { + .mask = 0b0000000001000, + .value = 0b0000000001000, + }, + { + .mask = 0b0000000010000, + .value = 0b0000000010000, + }, + { + .mask = 0b0000000100000, + .value = 0b0000000100000, + }, + { + .mask = 0b0000001000000, + .value = 0b0000001000000, + }, + { + .mask = 0b0000010000000, + .value = 0b0000010000000, + }, + { + .mask = 0b0000100000000, + .value = 0b0000100000000, + }, + { + .mask = 0b0001000000000, + .value = 0b0001000000000, + }, + { + .mask = 0b0010000000000, + .value = 0b0010000000000, + }, + { + .mask = 0b0111111111110, + .value = 0b0000000000110, + }, + { + .mask = 0b0100000000000, + .value = 0b0100000000000, + }, +}; + +int arm_decode_dp_reg_1src(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + unsigned char sf = 0, S = 0, opcode2 = 0, opcode = 0; + u32 decode_field = 0; + int i = 0; + + sf = EXTRACT_BIT(instr, 31); + S = EXTRACT_BIT(instr, 29); + opcode2 = (instr >> 16) & ONES(5); + opcode = (instr >> 10) & ONES(6); + + decode_field = (sf << 6) | (S << 5) | opcode2; + decode_field = (decode_field << 6) | opcode; + + for (i = 0; i < ARRAY_SIZE(dp_reg_1src_decoder); i++) { + if ((decode_field & dp_reg_1src_decoder[i].mask) == + dp_reg_1src_decoder[i].value) { + return arm_decode_unknown(instr, type, immediate, op); + } + } + *type = INSN_OTHER; + return 0; +} + +int arm_decode_dp_reg_logi(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + unsigned char sf = 0, imm6 = 0; + + sf = EXTRACT_BIT(instr, 31); + imm6 = (instr >> 10) & ONES(6); + + if (imm6 >= 0b100000 && !sf) + return arm_decode_unknown(instr, type, immediate, op); + + *type = INSN_OTHER; + return 0; +} + +int arm_decode_dp_reg_adds(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + unsigned char sf = 0, shift = 0, imm6 = 0; + + sf = EXTRACT_BIT(instr, 31); + shift = (instr >> 22) & ONES(2); + imm6 = (instr >> 10) & ONES(6); + + if ((imm6 >= 0b100000 && !sf) || shift == 0b11) + return arm_decode_unknown(instr, type, immediate, op); + + *type = INSN_OTHER; + return 0; +} + +int arm_decode_dp_reg_adde(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + unsigned char S = 0, opt = 0, imm3 = 0, rn = 0, rd = 0; + + S = EXTRACT_BIT(instr, 29); + opt = (instr >> 22) & ONES(2); + imm3 = (instr >> 10) & ONES(3); + rn = (instr >> 5) & ONES(5); + rd = instr & ONES(5); + + if (opt != 0 || imm3 >= 0b101) + return arm_decode_unknown(instr, type, immediate, op); + + if (rd == CFI_SP && S == 0) { + *type = INSN_STACK; + op->dest.reg = CFI_SP; + op->dest.type = OP_DEST_REG; + op->src.type = OP_SRC_ADD; + op->src.reg = rn; + + return 0; + } + *type = INSN_OTHER; + return 0; +} + +int arm_decode_dp_reg_addc(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + *type = INSN_OTHER; + return 0; +} + +int arm_decode_dp_reg_rota(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + unsigned char sf = 0, S = 0, op_bit = 0, o2 = 0; + unsigned char decode_field = 0; + + sf = EXTRACT_BIT(instr, 31); + op_bit = EXTRACT_BIT(instr, 30); + S = EXTRACT_BIT(instr, 29); + o2 = EXTRACT_BIT(instr, 4); + + decode_field = (sf << 3) | (op_bit << 2) | (S << 1) | o2; + + if (decode_field != 0b1010) + return arm_decode_unknown(instr, type, immediate, op); + + *type = INSN_OTHER; + return 0; +} + +int arm_decode_dp_reg_eval(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + unsigned char sf = 0, S = 0, op_bit = 0, o3 = 0, sz = 0; + unsigned char opcode2 = 0, mask = 0; + u32 decode_field = 0; + + sf = EXTRACT_BIT(instr, 31); + op_bit = EXTRACT_BIT(instr, 30); + S = EXTRACT_BIT(instr, 29); + sz = EXTRACT_BIT(instr, 14); + o3 = EXTRACT_BIT(instr, 4); + + opcode2 = (instr >> 15) & ONES(6); + mask = instr & ONES(4); + + decode_field = (sf << 2) | (op_bit << 1) | S; + decode_field = (decode_field << 12) | (opcode2 << 6) | (sz << 5); + decode_field |= (o3 << 4) | mask; + +#define DP_EVAL_SETF_1 0b001000000001101 +#define DP_EVAL_SETF_2 0b001000000101101 + + if (decode_field != DP_EVAL_SETF_1 && + decode_field != DP_EVAL_SETF_2) { + return arm_decode_unknown(instr, type, immediate, op); + } + + *type = INSN_OTHER; + return 0; +#undef DP_EVAL_SETF_1 +#undef DP_EVAL_SETF_2 +} + +int arm_decode_dp_reg_cmpr(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + unsigned char S = 0, o2 = 0, o3 = 0; + + S = EXTRACT_BIT(instr, 29); + o2 = EXTRACT_BIT(instr, 10); + o3 = EXTRACT_BIT(instr, 4); + + if (!S || o2 || o3) + return arm_decode_unknown(instr, type, immediate, op); + + *type = INSN_OTHER; + return 0; +} + +int arm_decode_dp_reg_csel(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + unsigned char S = 0, op2 = 0; + + S = EXTRACT_BIT(instr, 29); + op2 = (instr >> 10) & ONES(2); + + if (S || op2 >= 0b10) + return arm_decode_unknown(instr, type, immediate, op); + + *type = INSN_OTHER; + return 0; +} + +int arm_decode_dp_reg_cmpi(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + return arm_decode_dp_reg_cmpr(instr, type, immediate, op); +} + +static int dp_reg_3src_fields[] = { +}; + +static struct aarch64_insn_decoder dp_reg_3src_decoder[] = { + { + .mask = 0b0111111, + .value = 0b0000101, + }, + { + .mask = 0b0111110, + .value = 0b0000110, + }, + { + .mask = 0b0111110, + .value = 0b0001000, + }, + { + .mask = 0b0111111, + .value = 0b0001101, + }, + { + .mask = 0b0111110, + .value = 0b0001110, + }, + { + .mask = 0b0110000, + .value = 0b0010000, + }, + { + .mask = 0b0100000, + .value = 0b0100000, + }, + { + .mask = 0b1111111, + .value = 0b0000010, + }, + { + .mask = 0b1111111, + .value = 0b0000011, + }, + { + .mask = 0b1111111, + .value = 0b0000100, + }, + { + .mask = 0b1111111, + .value = 0b0001010, + }, + { + .mask = 0b1111111, + .value = 0b0001011, + }, + { + .mask = 0b1111111, + .value = 0b0001100, + }, +}; + +int arm_decode_dp_reg_3src(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + unsigned char sf = 0, op54 = 0, op31 = 0, o0 = 0; + unsigned char decode_field = 0; + int i = 0; + + sf = EXTRACT_BIT(instr, 31); + op54 = (instr >> 29) & ONES(2); + op31 = (instr >> 21) & ONES(3); + o0 = EXTRACT_BIT(instr, 15); + + decode_field = (sf << 6) | (op54 << 4) | (op31 << 1) | o0; + + for (i = 0; i < ARRAY_SIZE(dp_reg_3src_fields); i++) { + if ((decode_field & dp_reg_3src_decoder[i].mask) == + dp_reg_3src_decoder[i].value) { + return arm_decode_unknown(instr, type, immediate, op); + } + } + + *type = INSN_OTHER; + return 0; +} + +unsigned long arch_jump_destination(struct instruction *insn) +{ + return insn->offset + insn->immediate; +} + +static struct aarch64_insn_decoder sve_enc_decoder[] = { + { + .mask = 0b1111010000111000, + .value = 0b0000010000011000, + }, + { + .mask = 0b1111110000111000, + .value = 0b0001110000000000, + }, + { + .mask = 0b1111010000110000, + .value = 0b0011010000010000, + }, + { + .mask = 0b1111011100111000, + .value = 0b0011010100101000, + }, + { + .mask = 0b1111011000110000, + .value = 0b0011011000100000, + }, + { + .mask = 0b1111010000100000, + .value = 0b0100000000100000, + }, + { + .mask = 0b1111000000000000, + .value = 0b0101000000000000, + }, + { + .mask = 0b1111011111111000, + .value = 0b0110000000101000, + }, + { + .mask = 0b1111011111110000, + .value = 0b0110000000110000, + }, + { + .mask = 0b1111011111100000, + .value = 0b0110000001100000, + }, + { + .mask = 0b1111011110100000, + .value = 0b0110000010100000, + }, + { + .mask = 0b1111011100100000, + .value = 0b0110000100100000, + }, + { + .mask = 0b1111011000100000, + .value = 0b0110001000100000, + }, + { + .mask = 0b1111010000110110, + .value = 0b0110010000000010, + }, + { + .mask = 0b1111010000111111, + .value = 0b0110010000001001, + }, + { + .mask = 0b1111010000111100, + .value = 0b0110010000001100, + }, + { + .mask = 0b1111010000110000, + .value = 0b0110010000010000, + }, + { + .mask = 0b1111010000100000, + .value = 0b0110010000100000, + }, + { + .mask = 0b1111011100111100, + .value = 0b0111000100001000, + }, +}; + +/* + * Since these instructions are optional (not present on all arm processors) + * we consider that they will never be used to save/restore stack frame. + */ +int arm_decode_sve_encoding(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op) +{ + int i = 0; + unsigned char op0 = 0, op1 = 0, op2 = 0, op3 = 0; + u32 decode_field = 0; + + op0 = (instr >> 29) & ONES(3); + op1 = (instr >> 23) & ONES(2); + op2 = (instr >> 17) & ONES(5); + op3 = (instr >> 10) & ONES(6); + + decode_field = (op0 << 2) | op1; + decode_field = (decode_field << 5) | op2; + decode_field = (decode_field << 6) | op3; + + for (i = 0; i < ARRAY_SIZE(sve_enc_decoder); i++) { + if ((decode_field & sve_enc_decoder[i].mask) == + sve_enc_decoder[i].value) + return arm_decode_unknown(instr, type, immediate, op); + } + + *type = INSN_OTHER; + + return 0; +} diff --git a/tools/objtool/arch/arm64/include/arch_special.h b/tools/objtool/arch/arm64/include/arch_special.h new file mode 100644 index 000000000000..63da775d0581 --- /dev/null +++ b/tools/objtool/arch/arm64/include/arch_special.h @@ -0,0 +1,36 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ +#ifndef _ARM64_ARCH_SPECIAL_H +#define _ARM64_ARCH_SPECIAL_H + +#define EX_ENTRY_SIZE 8 +#define EX_ORIG_OFFSET 0 +#define EX_NEW_OFFSET 4 + +#define JUMP_ENTRY_SIZE 16 +#define JUMP_ORIG_OFFSET 0 +#define JUMP_NEW_OFFSET 4 + +#define ALT_ENTRY_SIZE 12 +#define ALT_ORIG_OFFSET 0 +#define ALT_NEW_OFFSET 4 +#define ALT_FEATURE_OFFSET 8 +#define ALT_ORIG_LEN_OFFSET 10 +#define ALT_NEW_LEN_OFFSET 11 + +#define X86_FEATURE_POPCNT (4 * 32 + 23) +#define X86_FEATURE_SMAP (9 * 32 + 20) + +#endif /* _ARM64_ARCH_SPECIAL_H */ diff --git a/tools/objtool/arch/arm64/include/asm/orc_types.h b/tools/objtool/arch/arm64/include/asm/orc_types.h new file mode 100644 index 000000000000..9b04885eb785 --- /dev/null +++ b/tools/objtool/arch/arm64/include/asm/orc_types.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 Josh Poimboeuf + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef _ORC_TYPES_H +#define _ORC_TYPES_H + +#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 current + * function. + * + * ORC_REG_UNDEFINED means the corresponding register's value didn't change in + * the current frame. + * + * The most commonly used base registers are SP and BP -- which the previous SP + * is usually based on -- and PREV_SP and UNDEFINED -- which the previous BP is + * usually based on. + * + * The rest of the base registers are needed for special cases like entry code + * and GCC realigned stacks. + */ +#define ORC_REG_UNDEFINED 0 +#define ORC_REG_PREV_SP 1 +#define ORC_REG_DX 2 +#define ORC_REG_DI 3 +#define ORC_REG_BP 4 +#define ORC_REG_SP 5 +#define ORC_REG_R10 6 +#define ORC_REG_R13 7 +#define ORC_REG_BP_INDIRECT 8 +#define ORC_REG_SP_INDIRECT 9 +#define ORC_REG_MAX 15 + +/* + * ORC_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 + * functions, i.e. all C code and all callable asm functions. + * + * ORC_TYPE_REGS: Used in entry code to indicate that sp_reg+sp_offset points + * to a fully populated pt_regs from a syscall, interrupt, or exception. + * + * ORC_TYPE_REGS_IRET: Used in entry code to indicate that sp_reg+sp_offset + * points to the iret return frame. + * + * The UNWIND_HINT macros are used only for the unwind_hint struct. They + * aren't used in struct orc_entry due to size and complexity constraints. + * Objtool converts them to real types when it converts the hints to orc + * entries. + */ +#define ORC_TYPE_CALL 0 +#define ORC_TYPE_REGS 1 +#define ORC_TYPE_REGS_IRET 2 +#define UNWIND_HINT_TYPE_SAVE 3 +#define UNWIND_HINT_TYPE_RESTORE 4 + +#ifndef __ASSEMBLY__ +/* + * This struct is more or less a vastly simplified version of the DWARF Call + * Frame Information standard. It contains only the necessary parts of DWARF + * 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 corresponds + * to one or more code locations. + */ +struct orc_entry { + s16 sp_offset; + s16 bp_offset; + unsigned sp_reg:4; + unsigned bp_reg:4; + unsigned type:2; + unsigned end:1; +} __packed; + +#endif /* __ASSEMBLY__ */ + +#endif /* _ORC_TYPES_H */ diff --git a/tools/objtool/arch/arm64/include/bit_operations.h b/tools/objtool/arch/arm64/include/bit_operations.h new file mode 100644 index 000000000000..c198c0724b7c --- /dev/null +++ b/tools/objtool/arch/arm64/include/bit_operations.h @@ -0,0 +1,24 @@ +#ifndef _BIT_OPERATIONS_H +#define _BIT_OPERATIONS_H + +#include +#include +#include + +#define ONES(N) (((__uint128_t)1 << (N)) - 1) +#define ZERO_EXTEND(X, N) ((X) & ONES(N)) +#define EXTRACT_BIT(X, N) (((X) >> (N)) & ONES(1)) +#define SIGN_EXTEND(X, N) ((((unsigned long)-1 + (EXTRACT_BIT(X, (N) - 1) ^ 1)) << (N)) | X) + +u64 replicate(u64 x, int size, int n); + +u64 ror(u64 x, int size, int shift); + +int highest_set_bit(u32 x); + +__uint128_t decode_bit_masks(unsigned char N, + unsigned char imms, + unsigned char immr, + bool immediate); + +#endif /* _BIT_OPERATIONS_H */ diff --git a/tools/objtool/arch/arm64/include/cfi.h b/tools/objtool/arch/arm64/include/cfi.h new file mode 100644 index 000000000000..dbe973c4fe68 --- /dev/null +++ b/tools/objtool/arch/arm64/include/cfi.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2015-2017 Josh Poimboeuf + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef _OBJTOOL_CFI_H +#define _OBJTOOL_CFI_H + +#define CFI_UNDEFINED -1 +#define CFI_CFA -2 +#define CFI_SP_INDIRECT -3 +#define CFI_BP_INDIRECT -4 + +#define CFI_R0 0 +#define CFI_R1 1 +#define CFI_R2 2 +#define CFI_R3 3 +#define CFI_R4 4 +#define CFI_R5 5 +#define CFI_R6 6 +#define CFI_R7 7 +#define CFI_R8 8 +#define CFI_R9 9 +#define CFI_R10 10 +#define CFI_R11 11 +#define CFI_R12 12 +#define CFI_R13 13 +#define CFI_R14 14 +#define CFI_R15 15 +#define CFI_R16 16 +#define CFI_R17 17 +#define CFI_R18 18 +#define CFI_R19 19 +#define CFI_R20 20 +#define CFI_R21 21 +#define CFI_R22 22 +#define CFI_R23 23 +#define CFI_R24 24 +#define CFI_R25 25 +#define CFI_R26 26 +#define CFI_R27 27 +#define CFI_R28 28 +#define CFI_R29 29 +#define CFI_FP CFI_R29 +#define CFI_BP CFI_FP +#define CFI_R30 30 +#define CFI_LR CFI_R30 +#define CFI_SP 31 + +#define CFI_NUM_REGS 32 + +struct cfi_reg { + int base; + int offset; +}; + +struct cfi_state { + struct cfi_reg cfa; + struct cfi_reg regs[CFI_NUM_REGS]; +}; + +#endif /* _OBJTOOL_CFI_H */ diff --git a/tools/objtool/arch/arm64/include/insn_decode.h b/tools/objtool/arch/arm64/include/insn_decode.h new file mode 100644 index 000000000000..eb54fc39dca5 --- /dev/null +++ b/tools/objtool/arch/arm64/include/insn_decode.h @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2019 Raphael Gault + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _ARM_INSN_DECODE_H +#define _ARM_INSN_DECODE_H + +#include "../../../arch.h" + +#define INSN_RESERVED 0b0000 +#define INSN_UNKNOWN 0b0001 +#define INSN_SVE_ENC 0b0010 +#define INSN_UNALLOC 0b0011 +#define INSN_DP_IMM 0b1001 //0x100x +#define INSN_BRANCH 0b1011 //0x101x +#define INSN_LD_ST_4 0b0100 //0bx1x0 +#define INSN_LD_ST_6 0b0110 //0bx1x0 +#define INSN_LD_ST_C 0b1100 //0bx1x0 +#define INSN_LD_ST_E 0b1110 //0bx1x0 +#define INSN_DP_REG_5 0b0101 //0bx101 +#define INSN_DP_REG_D 0b1101 //0bx101 +#define INSN_DP_SIMD_7 0b0111 //0bx111 +#define INSN_DP_SIMD_F 0b1111 //0bx111 + +#define INSN_PCREL 0b001 //0b00x +#define INSN_ADD_SUB 0b010 +#define INSN_ADD_TAG 0b011 +#define INSN_LOGICAL 0b100 +#define INSN_MOVE_WIDE 0b101 +#define INSN_BITFIELD 0b110 +#define INSN_EXTRACT 0b111 + +#define INSN_BR_UNCOND_IMM_L 0b0001 +#define INSN_CP_BR_IMM_L 0b0010 +#define INSN_TST_BR_IMM_L 0b0011 +#define INSN_BR_COND_IMM 0b0100 +#define INSN_BR_UNKNOWN_IMM 0b0111 +#define INSN_BR_UNCOND_IMM_H 0b1001 +#define INSN_CP_BR_IMM_H 0b1010 +#define INSN_TST_BR_IMM_H 0b1011 +#define INSN_BR_SYS_NO_IMM 0b1101 + +#define INSN_OP1_HINTS 0b01000000110010 +#define INSN_OP1_BARRIERS 0b01000000110011 + +#define COMPOSED_INSN_REGS_NUM 2 +#define INSN_COMPOSED 1 + +#define ADR_SOURCE -1 + +typedef int (*arm_decode_class)(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); + +struct aarch64_insn_decoder { + u32 mask; + u32 value; + arm_decode_class decode_func; +}; + +/* arm64 instruction classes */ +int arm_decode_reserved(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_sve_encoding(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_dp_imm(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_dp_reg(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_br_sys(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_ld_st(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_dp_simd(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_unknown(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); + +/* arm64 data processing -- immediate subclasses */ +int arm_decode_pcrel(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_add_sub(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_add_sub_tags(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_logical(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_move_wide(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_bitfield(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_extract(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); + +/* arm64 branch, exception generation, system insn subclasses */ +int arm_decode_br_uncond_imm(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_br_comp_imm(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_br_tst_imm(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_br_cond_imm(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); + +int arm_decode_br_uncond_reg(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); + +int arm_decode_br_reg(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_except_gen(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_hints(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_barriers(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_pstate(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_system_insn(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_system_regs(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); + +/* arm64 load/store instructions */ +int arm_decode_adv_simd_mult(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_adv_simd_mult_post(u32 instr, unsigned char *type, + unsigned long *immediate, + struct stack_op *op); +int arm_decode_adv_simd_single(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_adv_simd_single_post(u32 instr, unsigned char *type, + unsigned long *immediate, + struct stack_op *op); +int arm_decode_ld_st_mem_tags(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_ldapr_stlr_unsc_imm(u32 instr, unsigned char *type, + unsigned long *immediate, + struct stack_op *op); +int arm_decode_ld_regs_literal(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_ld_st_noalloc_pair_off(u32 instr, unsigned char *type, + unsigned long *immediate, + struct stack_op *op); +int arm_decode_ld_st_regs_pair_post(u32 instr, unsigned char *type, + unsigned long *immediate, + struct stack_op *op); +int arm_decode_ld_st_regs_pair_off(u32 instr, unsigned char *type, + unsigned long *immediate, + struct stack_op *op); +int arm_decode_ld_st_regs_pair_pre(u32 instr, unsigned char *type, + unsigned long *immediate, + struct stack_op *op); +int arm_decode_ld_st_regs_unsc_imm(u32 instr, unsigned char *type, + unsigned long *immediate, + struct stack_op *op); +int arm_decode_ld_st_imm_post(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_ld_st_imm_unpriv(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_ld_st_imm_pre(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_atomic(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_ld_st_regs_off(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_ld_st_regs_pac(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_ld_st_regs_unsigned(u32 instr, unsigned char *type, + unsigned long *immediate, + struct stack_op *op); + +int arm_decode_ld_st_exclusive(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); + +/* arm64 data processing -- registers instructions */ +int arm_decode_dp_reg_1src(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_dp_reg_2src(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_dp_reg_3src(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_dp_reg_adde(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_dp_reg_cmpi(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_dp_reg_eval(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_dp_reg_cmpr(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_dp_reg_rota(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_dp_reg_csel(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_dp_reg_addc(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_dp_reg_adds(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +int arm_decode_dp_reg_logi(u32 instr, unsigned char *type, + unsigned long *immediate, struct stack_op *op); +#endif /* _ARM_INSN_DECODE_H */ diff --git a/tools/objtool/arch/arm64/orc_dump.c b/tools/objtool/arch/arm64/orc_dump.c new file mode 100644 index 000000000000..d1dc39829c9e --- /dev/null +++ b/tools/objtool/arch/arm64/orc_dump.c @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2017 Josh Poimboeuf + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#include "../../orc.h" +#include "../../warn.h" + +int orc_dump(const char *_objname) +{ + WARN("arm64 architecture does not yet support orc"); + return -1; +} diff --git a/tools/objtool/arch/arm64/orc_gen.c b/tools/objtool/arch/arm64/orc_gen.c new file mode 100644 index 000000000000..81383d34a743 --- /dev/null +++ b/tools/objtool/arch/arm64/orc_gen.c @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2017 Josh Poimboeuf + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#include + +#include "../../orc.h" +#include "../../check.h" +#include "../../warn.h" + +int arch_create_orc(struct objtool_file *file) +{ + WARN("arm64 architecture does not yet support orc"); + return -1; +} + +int arch_create_orc_sections(struct objtool_file *file) +{ + WARN("arm64 architecture does not yet support orc"); + return -1; +} + +int arch_orc_read_unwind_hints(struct objtool_file *file) +{ + return 0; +} From patchwork Thu May 16 10:36:44 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Raphael Gault X-Patchwork-Id: 10946325 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A9C6E924 for ; Thu, 16 May 2019 10:38:47 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 96AF42854F for ; Thu, 16 May 2019 10:38:47 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 87D2628842; Thu, 16 May 2019 10:38:47 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 275182854F for ; Thu, 16 May 2019 10:38:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=d/6VCh5Vz5c9vks9dDXouXrvIuClNxlT+Ej7oIZITF0=; b=dnugMnhu52+y7ujq73J8xQl7O+ cbmqvqPbhTI4ky3JN9W77YXLKIUpbQcSwE4cSEhp6vro/ei3zb8fXmJ4ZEs8LARDsqtroCXVL3jRo A6jYGaHGTGCkaialOQ8+sVGGdJiqFbAVv6nj5di1MiX/iotSMExCGNnTm34wvfLruYbnrHAn57Gta 5Yz+HErVq8BOZDp70/OZawifQnMRGletQCbelJt8Xj6LhQ9edf3td2NtOJVXktX6YQqTk+h/sWCrC ERq57qvmWW0GOWeO1svjwTy9TofLdSOGse4Y8EhK6lK2B8pODOAwlnJ36GvCxLdWDwlhNUKzs/KQE YE3KZuFQ==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1hRDmb-0006Ix-S0; Thu, 16 May 2019 10:38:41 +0000 Received: from foss.arm.com ([217.140.101.70]) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1hRDm5-0005es-Qm for linux-arm-kernel@lists.infradead.org; Thu, 16 May 2019 10:38:11 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id A9E671A25; Thu, 16 May 2019 03:38:09 -0700 (PDT) Received: from e121650-lin.cambridge.arm.com (e121650-lin.cambridge.arm.com [10.1.196.108]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 2F3EF3F703; Thu, 16 May 2019 03:38:08 -0700 (PDT) From: Raphael Gault To: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [RFC 05/16] objtool: arm64: Handle hypercalls as nops Date: Thu, 16 May 2019 11:36:44 +0100 Message-Id: <20190516103655.5509-6-raphael.gault@arm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190516103655.5509-1-raphael.gault@arm.com> References: <20190516103655.5509-1-raphael.gault@arm.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20190516_033810_131576_2C276B09 X-CRM114-Status: GOOD ( 11.13 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: julien.thierry@arm.com, peterz@infradead.org, catalin.marinas@arm.com, will.deacon@arm.com, Raphael Gault , jpoimboe@redhat.com MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP We consider that the hypervisor/secure-monitor is behaving correctly. This enables us to handle hvc/smc/svc context switching instructions as nop since we consider that the context is restored correctly. This enables us to get rid of the "unsupported instruction in callable function" warning which is not really useful. Note that those instruction/warnings are caused by hypervisor-related calls. Signed-off-by: Raphael Gault --- tools/objtool/arch/arm64/decode.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/objtool/arch/arm64/decode.c b/tools/objtool/arch/arm64/decode.c index 721152342dd3..6c77ad1a08ec 100644 --- a/tools/objtool/arch/arm64/decode.c +++ b/tools/objtool/arch/arm64/decode.c @@ -577,8 +577,11 @@ int arm_decode_except_gen(u32 instr, unsigned char *type, case INSN_SVC: case INSN_HVC: case INSN_SMC: - *immediate = imm16; - *type = INSN_CONTEXT_SWITCH; + /* + * We consider that the context will be restored correctly + * with an unchanged sp and the same general registers + */ + *type = INSN_NOP; return 0; case INSN_BRK: if (imm16 == 0x800) From patchwork Thu May 16 10:36:45 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Raphael Gault X-Patchwork-Id: 10946329 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id AA5C4912 for ; Thu, 16 May 2019 10:39:06 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 98DD52854F for ; Thu, 16 May 2019 10:39:06 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 8D20128842; Thu, 16 May 2019 10:39:06 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 6DBDB2854F for ; Thu, 16 May 2019 10:39:05 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=LqIF3whFTOJcAbhOpETXB8QgFdy9SlQ9UuCYDjupZ9M=; b=gGcNaKzmxzhsVCI2HhlXnJmgW5 08bP7dCCTXgWiml54Q1z+ghnBzrdWDEAgE/jdmYvVIWaAvecFj1c1AxyyS4klye5W7PGZQOvR0I0w zcVdBxoQ7/2frsLMamI7lfW4ynqN1Pxlo8QZOtm5LnDBj3uxkuLbk2ShDoKI7QsKjyme48MhO8mNr C5tHWkWFerDOcAIhMdHLa2xMWU1FXxzHFrijfU0/NoLpEpAHCYS9UDiiXloio7F8jwQUD650P8Lc6 c/TX8nWGvlWo5zviae3gH3St2LwPtEoBJjb5ndD4u2lkYBo3D7g4tET4yggt2dGCUmOClIJRFZcIG PfOt5owQ==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1hRDmt-0006fn-JD; Thu, 16 May 2019 10:38:59 +0000 Received: from usa-sjc-mx-foss1.foss.arm.com ([217.140.101.70] helo=foss.arm.com) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1hRDm7-0005hl-NZ for linux-arm-kernel@lists.infradead.org; Thu, 16 May 2019 10:38:16 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 6CE7919F6; Thu, 16 May 2019 03:38:11 -0700 (PDT) Received: from e121650-lin.cambridge.arm.com (e121650-lin.cambridge.arm.com [10.1.196.108]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id E6AEC3F703; Thu, 16 May 2019 03:38:09 -0700 (PDT) From: Raphael Gault To: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [RFC 06/16] arm64: alternative: Mark .altinstr_replacement as containing executable instructions Date: Thu, 16 May 2019 11:36:45 +0100 Message-Id: <20190516103655.5509-7-raphael.gault@arm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190516103655.5509-1-raphael.gault@arm.com> References: <20190516103655.5509-1-raphael.gault@arm.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20190516_033812_198268_EFCFB79B X-CRM114-Status: GOOD ( 12.44 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: julien.thierry@arm.com, peterz@infradead.org, catalin.marinas@arm.com, will.deacon@arm.com, Raphael Gault , jpoimboe@redhat.com MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP Until now, the section .altinstr_replacement wasn't marked as containing executable instructions on arm64. This patch changes that so that it is coherent with what is done on x86. Signed-off-by: Raphael Gault --- arch/arm64/include/asm/alternative.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/include/asm/alternative.h b/arch/arm64/include/asm/alternative.h index b9f8d787eea9..e9e6b81e3eb4 100644 --- a/arch/arm64/include/asm/alternative.h +++ b/arch/arm64/include/asm/alternative.h @@ -71,7 +71,7 @@ static inline void apply_alternatives_module(void *start, size_t length) { } ALTINSTR_ENTRY(feature,cb) \ ".popsection\n" \ " .if " __stringify(cb) " == 0\n" \ - ".pushsection .altinstr_replacement, \"a\"\n" \ + ".pushsection .altinstr_replacement, \"ax\"\n" \ "663:\n\t" \ newinstr "\n" \ "664:\n\t" \ From patchwork Thu May 16 10:36:46 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Raphael Gault X-Patchwork-Id: 10946331 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 66B90924 for ; Thu, 16 May 2019 10:39:17 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 543312854F for ; Thu, 16 May 2019 10:39:17 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 45D3428842; Thu, 16 May 2019 10:39:17 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id AF73C2854F for ; Thu, 16 May 2019 10:39:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=p6wT/l/1JAGWjp/WJzUWZd2kFG8RpC+wTMymmAotyOM=; b=OaU3VT1hClJ6/GBADJgBCmd6mL pBKBU0o2WMtj4jIaqy+dcOWA0VIw1VDKbJyKeI5Ulq4F0r3pDd1L65X11EvTD8Ft/EJ67Y6jRFqQh /D7QANMyEQ/Nh2cg8tFPJhIWRljXPaEWcaebR3PW5gLLRHYNEsG65q+Kz2HG53/zpsosJG6POVfif Z9yAIo/7MejgQdyvQtGCcB2P/dmR2NevkPVkG0Gh9dG81le9S22RDNhpVxpd/aUMihvaZY/mn6R7n zliu2rzKQ/K1TkaW7joxl8v91dXknUBjm1ITRuEFGk3rkYAzkocSUCS4qKq6FnjGh7PULYiodBR54 dNHvkLjw==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1hRDn4-0006uj-Gf; Thu, 16 May 2019 10:39:10 +0000 Received: from usa-sjc-mx-foss1.foss.arm.com ([217.140.101.70] helo=foss.arm.com) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1hRDm9-0005jk-Jg for linux-arm-kernel@lists.infradead.org; Thu, 16 May 2019 10:38:21 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 313251A25; Thu, 16 May 2019 03:38:13 -0700 (PDT) Received: from e121650-lin.cambridge.arm.com (e121650-lin.cambridge.arm.com [10.1.196.108]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id AA3BE3F703; Thu, 16 May 2019 03:38:11 -0700 (PDT) From: Raphael Gault To: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [RFC 07/16] objtool: special: Adapt special section handling Date: Thu, 16 May 2019 11:36:46 +0100 Message-Id: <20190516103655.5509-8-raphael.gault@arm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190516103655.5509-1-raphael.gault@arm.com> References: <20190516103655.5509-1-raphael.gault@arm.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20190516_033813_938670_20C5608D X-CRM114-Status: GOOD ( 18.26 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: julien.thierry@arm.com, peterz@infradead.org, catalin.marinas@arm.com, will.deacon@arm.com, Raphael Gault , jpoimboe@redhat.com MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP This patch abstracts the few architecture dependent tests that are perform when handling special section and switch tables. It enables any architecture to ignore a particular CPU feature or not to handle switch tables. Signed-off-by: Raphael Gault --- tools/objtool/arch/arm64/Build | 1 + tools/objtool/arch/arm64/include/arch_special.h | 10 ++++++++-- tools/objtool/arch/x86/Build | 1 + tools/objtool/arch/x86/include/arch_special.h | 9 +++++++++ tools/objtool/check.c | 15 +++++++++++++-- tools/objtool/special.c | 9 ++------- tools/objtool/special.h | 3 +++ 7 files changed, 37 insertions(+), 11 deletions(-) diff --git a/tools/objtool/arch/arm64/Build b/tools/objtool/arch/arm64/Build index bf7a32c2b9e9..3d09be745a84 100644 --- a/tools/objtool/arch/arm64/Build +++ b/tools/objtool/arch/arm64/Build @@ -1,3 +1,4 @@ +objtool-y += arch_special.o objtool-y += decode.o objtool-y += orc_dump.o objtool-y += orc_gen.o diff --git a/tools/objtool/arch/arm64/include/arch_special.h b/tools/objtool/arch/arm64/include/arch_special.h index 63da775d0581..185103be8a51 100644 --- a/tools/objtool/arch/arm64/include/arch_special.h +++ b/tools/objtool/arch/arm64/include/arch_special.h @@ -30,7 +30,13 @@ #define ALT_ORIG_LEN_OFFSET 10 #define ALT_NEW_LEN_OFFSET 11 -#define X86_FEATURE_POPCNT (4 * 32 + 23) -#define X86_FEATURE_SMAP (9 * 32 + 20) +static inline bool arch_should_ignore_feature(unsigned short feature) +{ + return false; +} +static inline bool arch_support_switch_table(void) +{ + return false; +} #endif /* _ARM64_ARCH_SPECIAL_H */ diff --git a/tools/objtool/arch/x86/Build b/tools/objtool/arch/x86/Build index 1f11b45999d0..63e167775bc8 100644 --- a/tools/objtool/arch/x86/Build +++ b/tools/objtool/arch/x86/Build @@ -1,3 +1,4 @@ +objtool-y += arch_special.o objtool-y += decode.o objtool-y += orc_dump.o objtool-y += orc_gen.o diff --git a/tools/objtool/arch/x86/include/arch_special.h b/tools/objtool/arch/x86/include/arch_special.h index 424ce47013e3..fce2b1193194 100644 --- a/tools/objtool/arch/x86/include/arch_special.h +++ b/tools/objtool/arch/x86/include/arch_special.h @@ -33,4 +33,13 @@ #define X86_FEATURE_POPCNT (4 * 32 + 23) #define X86_FEATURE_SMAP (9 * 32 + 20) +static inline bool arch_should_ignore_feature(unsigned short feature) +{ + return feature == X86_FEATURE_POPCNT; +} + +static inline bool arch_support_switch_table(void) +{ + return true; +} #endif /* _X86_ARCH_SPECIAL_H */ diff --git a/tools/objtool/check.c b/tools/objtool/check.c index cd9cd26206d1..0ee3b781ddd8 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -738,7 +738,7 @@ static int handle_group_alt(struct objtool_file *file, last_orig_insn = insn; } - if (next_insn_same_sec(file, last_orig_insn)) { + if (last_orig_insn && next_insn_same_sec(file, last_orig_insn)) { fake_jump = malloc(sizeof(*fake_jump)); if (!fake_jump) { WARN("malloc failed"); @@ -1054,6 +1054,17 @@ static struct rela *find_switch_table(struct objtool_file *file, if (find_symbol_containing(rodata_sec, table_offset)) continue; + /* + * If we are on arm64 architecture, we now that we + * are in presence of a switch table thanks to + * the `br ` insn. but we can't retrieve it yet. + * So we just ignore unreachable for this file. + */ + if (!arch_support_switch_table()) { + file->ignore_unreachables = true; + return NULL; + } + rodata_rela = find_rela_by_dest(rodata_sec, table_offset); if (rodata_rela) { /* @@ -1853,7 +1864,7 @@ static int validate_branch(struct objtool_file *file, struct instruction *first, insn = first; sec = insn->sec; - if (insn->alt_group && list_empty(&insn->alts)) { + if (!insn->visited && insn->alt_group && list_empty(&insn->alts)) { WARN_FUNC("don't know how to handle branch to middle of alternative instruction group", sec, insn->offset); return 1; diff --git a/tools/objtool/special.c b/tools/objtool/special.c index fd7c928fa1d6..e33321637932 100644 --- a/tools/objtool/special.c +++ b/tools/objtool/special.c @@ -93,7 +93,7 @@ static int get_alt_entry(struct elf *elf, struct special_entry *entry, * feature path which is a "very very small percentage of * machines". */ - if (feature == X86_FEATURE_POPCNT) + if (arch_should_ignore_feature(feature)) alt->skip_orig = true; /* @@ -105,12 +105,7 @@ static int get_alt_entry(struct elf *elf, struct special_entry *entry, * find paths that see the STAC but take the NOP instead of * CLAC and the other way around. */ - if (feature == X86_FEATURE_SMAP) { - if (uaccess) - alt->skip_orig = true; - else - alt->skip_alt = true; - } + arch_force_alt_path(feature, uaccess, alt); } orig_rela = find_rela_by_dest(sec, offset + entry->orig); diff --git a/tools/objtool/special.h b/tools/objtool/special.h index d5c062e718ef..05f1e496bf7c 100644 --- a/tools/objtool/special.h +++ b/tools/objtool/special.h @@ -39,5 +39,8 @@ struct special_alt { }; int special_get_alts(struct elf *elf, struct list_head *alts); +void arch_force_alt_path(unsigned short feature, + bool uaccess, + struct special_alt *alt); #endif /* _SPECIAL_H */ From patchwork Thu May 16 10:36:47 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Raphael Gault X-Patchwork-Id: 10946335 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id F010A912 for ; Thu, 16 May 2019 10:39:39 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D9C352854F for ; Thu, 16 May 2019 10:39:39 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id CB25A28842; Thu, 16 May 2019 10:39:39 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 100962854F for ; Thu, 16 May 2019 10:39:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=MXwAGTEng9KrWK9FjTpPXvMLAoivtjGeIj7oCDHLoas=; b=TZhTeskfpZejnzIDfI4k+dsZIX MPoCg8aa/heHaS4H8K3dzQc8bZ3tyUaSagnndUmQEM+gBqbeVyY6rjAHLJG2mT0u8+vJ3flFqE4Fj d2g4owUjkJkyKIFIMFmHWBu2mSQszazJEWk2LmB6j7h0DORt5xWRHhqMq72lvHcD1UnAtC/1fFffy rMKgz7WvK2/LxGGiMDO2hTB7LSvC4R3kNNoXFmUqxy8tyJdlhDyc+DV0k0Qj1JFToRQTOS8Bovy9z XycCqEdw2U6K9NiioDTpHpKgr6+m41f2dTukCfRJnLoVuNMUBb+xKde9Tkei3Bf3yZ8KD3KvCCYfj KFHq6xBw==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1hRDnQ-0007Pa-9e; Thu, 16 May 2019 10:39:32 +0000 Received: from foss.arm.com ([217.140.101.70]) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1hRDmB-0005na-KK for linux-arm-kernel@lists.infradead.org; Thu, 16 May 2019 10:38:30 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id E8E931AED; Thu, 16 May 2019 03:38:14 -0700 (PDT) Received: from e121650-lin.cambridge.arm.com (e121650-lin.cambridge.arm.com [10.1.196.108]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 6E9C53F703; Thu, 16 May 2019 03:38:13 -0700 (PDT) From: Raphael Gault To: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [RFC 08/16] objtool: arm64: Adapt the stack frame checks for arm architecture Date: Thu, 16 May 2019 11:36:47 +0100 Message-Id: <20190516103655.5509-9-raphael.gault@arm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190516103655.5509-1-raphael.gault@arm.com> References: <20190516103655.5509-1-raphael.gault@arm.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20190516_033816_376312_8CC18324 X-CRM114-Status: GOOD ( 20.06 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: julien.thierry@arm.com, peterz@infradead.org, catalin.marinas@arm.com, will.deacon@arm.com, Raphael Gault , jpoimboe@redhat.com MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP Since the way the initial stack frame when entering a function is different that what is done in the x86_64 architecture, we need to add some more check to support the different cases. As opposed as for x86_64, the return address is not stored by the call instruction but is instead loaded in a register. The initial stack frame is thus empty when entering a function and 2 push operations are needed to set it up correctly. All the different combinations need to be taken into account. Signed-off-by: Raphael Gault --- tools/objtool/arch.h | 2 + tools/objtool/arch/arm64/decode.c | 28 +++++++++ tools/objtool/arch/x86/decode.c | 5 ++ tools/objtool/check.c | 100 ++++++++++++++++++++++++++++-- tools/objtool/elf.c | 3 +- 5 files changed, 131 insertions(+), 7 deletions(-) diff --git a/tools/objtool/arch.h b/tools/objtool/arch.h index bb3494e431b7..c1ea6ecdd5d2 100644 --- a/tools/objtool/arch.h +++ b/tools/objtool/arch.h @@ -101,4 +101,6 @@ unsigned long arch_jump_destination(struct instruction *insn); unsigned long arch_dest_rela_offset(int addend); +bool arch_is_insn_sibling_call(struct instruction *insn); + #endif /* _ARCH_H */ diff --git a/tools/objtool/arch/arm64/decode.c b/tools/objtool/arch/arm64/decode.c index 6c77ad1a08ec..5be1d87b1a1c 100644 --- a/tools/objtool/arch/arm64/decode.c +++ b/tools/objtool/arch/arm64/decode.c @@ -106,6 +106,34 @@ unsigned long arch_dest_rela_offset(int addend) return addend; } +/* + * In order to know if we are in presence of a sibling + * call and not in presence of a switch table we look + * back at the previous instructions and see if we are + * jumping inside the same function that we are already + * in. + */ +bool arch_is_insn_sibling_call(struct instruction *insn) +{ + struct instruction *prev; + struct list_head *l; + struct symbol *sym; + list_for_each_prev(l, &insn->list) { + prev = list_entry(l, struct instruction, list); + if (!prev->func || + prev->func->pfunc != insn->func->pfunc) + return false; + if (prev->stack_op.src.reg != ADR_SOURCE) + continue; + sym = find_symbol_containing(insn->sec, insn->immediate); + if (!sym || sym->type != STT_FUNC) + return false; + else if (sym->type == STT_FUNC) + return true; + break; + } + return false; +} static int is_arm64(struct elf *elf) { switch (elf->ehdr.e_machine) { diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c index c1b95ea447c0..9af5522cb994 100644 --- a/tools/objtool/arch/x86/decode.c +++ b/tools/objtool/arch/x86/decode.c @@ -84,6 +84,11 @@ unsigned long arch_dest_rela_offset(int addend) return addend + 4; } +bool arch_is_insn_sibling_call(struct instruction *insn) +{ + return true; +} + int arch_decode_instruction(struct elf *elf, struct section *sec, unsigned long offset, unsigned int maxlen, unsigned int *len, unsigned char *type, diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 0ee3b781ddd8..bfb36cca9be1 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -577,10 +577,10 @@ static int add_jump_destinations(struct objtool_file *file) dest_off = arch_jump_destination(insn); } else if (rela->sym->type == STT_SECTION) { dest_sec = rela->sym->sec; - dest_off = rela->addend + 4; + dest_off = arch_dest_rela_offset(rela->addend); } else if (rela->sym->sec->idx) { dest_sec = rela->sym->sec; - dest_off = rela->sym->sym.st_value + rela->addend + 4; + dest_off = rela->sym->sym.st_value + arch_dest_rela_offset(rela->addend); } else if (strstr(rela->sym->name, "_indirect_thunk_")) { /* * Retpoline jumps are really dynamic jumps in @@ -1348,8 +1348,8 @@ static void save_reg(struct insn_state *state, unsigned char reg, int base, static void restore_reg(struct insn_state *state, unsigned char reg) { - state->regs[reg].base = CFI_UNDEFINED; - state->regs[reg].offset = 0; + state->regs[reg].base = initial_func_cfi.regs[reg].base; + state->regs[reg].offset = initial_func_cfi.regs[reg].offset; } /* @@ -1505,8 +1505,32 @@ static int update_insn_state(struct instruction *insn, struct insn_state *state) /* add imm, %rsp */ state->stack_size -= op->src.offset; - if (cfa->base == CFI_SP) + if (cfa->base == CFI_SP) { cfa->offset -= op->src.offset; + if (state->stack_size == 0 && + initial_func_cfi.cfa.base == CFI_CFA) { + cfa->base = CFI_CFA; + cfa->offset = 0; + } + } + /* + * on arm64 the save/restore of sp into fp is not automatic + * and the first one can be done without the other so we + * need to be careful not to invalidate the stack frame in such + * cases. + */ + else if (cfa->base == CFI_BP) { + if (state->stack_size == 0 && + initial_func_cfi.cfa.base == CFI_CFA) { + cfa->base = CFI_CFA; + cfa->offset = 0; + restore_reg(state, CFI_BP); + } + } else if (cfa->base == CFI_CFA) { + cfa->base = CFI_SP; + if (state->stack_size >= 16) + cfa->offset = 16; + } break; } @@ -1517,6 +1541,15 @@ static int update_insn_state(struct instruction *insn, struct insn_state *state) break; } + if (op->src.reg == CFI_SP && op->dest.reg == CFI_BP && + cfa->base == CFI_SP && + regs[CFI_BP].base == CFI_CFA && + regs[CFI_BP].offset == -cfa->offset) { + /* mov %rsp, %rbp */ + cfa->base = op->dest.reg; + state->bp_scratch = false; + break; + } if (op->src.reg == CFI_SP && cfa->base == CFI_SP) { /* drap: lea disp(%rsp), %drap */ @@ -1609,6 +1642,22 @@ static int update_insn_state(struct instruction *insn, struct insn_state *state) state->stack_size -= 8; if (cfa->base == CFI_SP) cfa->offset -= 8; + if (cfa->base == CFI_SP && + cfa->offset == 0 && + initial_func_cfi.cfa.base == CFI_CFA) + cfa->base = CFI_CFA; + + if (op->extra.used) { + if (regs[op->extra.reg].offset == -state->stack_size) + restore_reg(state, op->extra.reg); + state->stack_size -= 8; + if (cfa->base == CFI_SP) + cfa->offset -= 8; + if (cfa->base == CFI_SP && + cfa->offset == 0 && + initial_func_cfi.cfa.base == CFI_CFA) + cfa->base = CFI_CFA; + } break; @@ -1628,12 +1677,22 @@ static int update_insn_state(struct instruction *insn, struct insn_state *state) /* drap: mov disp(%rbp), %reg */ restore_reg(state, op->dest.reg); + if (op->extra.used && + op->src.reg == CFI_BP && + op->extra.offset == regs[op->extra.reg].offset) + restore_reg(state, op->extra.reg); + } else if (op->src.reg == cfa->base && op->src.offset == regs[op->dest.reg].offset + cfa->offset) { /* mov disp(%rbp), %reg */ /* mov disp(%rsp), %reg */ restore_reg(state, op->dest.reg); + + if (op->extra.used && + op->src.reg == cfa->base && + op->extra.offset == regs[op->extra.reg].offset + cfa->offset) + restore_reg(state, op->extra.reg); } break; @@ -1649,6 +1708,8 @@ static int update_insn_state(struct instruction *insn, struct insn_state *state) case OP_DEST_PUSH: case OP_DEST_PUSHF: state->stack_size += 8; + if (cfa->base == CFI_CFA) + cfa->base = CFI_SP; if (cfa->base == CFI_SP) cfa->offset += 8; @@ -1682,6 +1743,21 @@ static int update_insn_state(struct instruction *insn, struct insn_state *state) save_reg(state, op->src.reg, CFI_CFA, -state->stack_size); } + if (op->extra.used) { + state->stack_size += 8; + if (cfa->base == CFI_CFA) + cfa->base = CFI_SP; + if (cfa->base == CFI_SP) + cfa->offset += 8; + if (!state->drap || + (!(op->extra.reg == cfa->base && + op->extra.reg == state->drap_reg) && + !(op->extra.reg == CFI_BP && + cfa->base == state->drap_reg) && + regs[op->extra.reg].base == CFI_UNDEFINED)) + save_reg(state, op->extra.reg, CFI_CFA, + -state->stack_size); + } /* detect when asm code uses rbp as a scratch register */ if (!no_fp && insn->func && op->src.reg == CFI_BP && cfa->base != CFI_BP) @@ -1700,11 +1776,19 @@ static int update_insn_state(struct instruction *insn, struct insn_state *state) /* save drap offset so we know when to restore it */ state->drap_offset = op->dest.offset; } + if (op->extra.used && op->extra.reg == cfa->base && + op->extra.reg == state->drap_reg) { + cfa->base = CFI_BP_INDIRECT; + cfa->offset = op->extra.offset; + } else if (regs[op->src.reg].base == CFI_UNDEFINED) { /* drap: mov reg, disp(%rbp) */ save_reg(state, op->src.reg, CFI_BP, op->dest.offset); + if (op->extra.used) + save_reg(state, op->extra.reg, CFI_BP, + op->extra.offset); } } else if (op->dest.reg == cfa->base) { @@ -1713,8 +1797,12 @@ static int update_insn_state(struct instruction *insn, struct insn_state *state) /* mov reg, disp(%rsp) */ save_reg(state, op->src.reg, CFI_CFA, op->dest.offset - state->cfa.offset); + if (op->extra.used) + save_reg(state, op->extra.reg, CFI_CFA, + op->extra.offset - state->cfa.offset); } + break; case OP_DEST_LEAVE: @@ -1837,7 +1925,7 @@ static int validate_call(struct instruction *insn, struct insn_state *state) static int validate_sibling_call(struct instruction *insn, struct insn_state *state) { - if (has_modified_stack_frame(state)) { + if (arch_is_insn_sibling_call(insn) && has_modified_stack_frame(state)) { WARN_FUNC("sibling call from callable instruction with modified stack frame", insn->sec, insn->offset); return 1; diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index dd198d53387d..42a64ff05f69 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -74,7 +74,8 @@ struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset) struct symbol *sym; list_for_each_entry(sym, &sec->symbol_list, list) - if (sym->type != STT_SECTION && + if (sym->type != STT_NOTYPE && + sym->type != STT_SECTION && sym->offset == offset) return sym; From patchwork Thu May 16 10:36:48 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Raphael Gault X-Patchwork-Id: 10946333 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id EFA3E924 for ; Thu, 16 May 2019 10:39:28 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id DD3102854F for ; Thu, 16 May 2019 10:39:28 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D140D28842; Thu, 16 May 2019 10:39:28 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 8787A2854F for ; Thu, 16 May 2019 10:39:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=xFfiD1hzi0boA9Fr08VXC0yOATr/uZ3ZBKNzvjasdWA=; b=L7l+5bZRifuMiOK1YAcV2m3qNN GsrjTY7QqeOWfxsV7G2DM0ttETgJWJSIF/OBYR6BpA1A/5100RpzZaslj3lcwFPRR03rFAOO45W2C pcGsf2o/9KyURQeoDcziSl2JSXAIPikRH/E3v1PV4Vul8t3noZB3CY12fzE3UYPd7+9hUqO1fFQYq JqYKpHimFaCXQGC0dz23yXh99j7CjzsK7rHeehG+OLe1DYaOcEceOGuxkwYb4TBM9Wcog1Qg1YRZo 7KNnA9AKx95Geo9wIckPy77nwX96B24Uqq8xBj25AoLk/8gKdgJLsFG0WlFxMo7s4dii3sPf5Q5MK Ru0G9HlA==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1hRDnF-00078e-PJ; Thu, 16 May 2019 10:39:21 +0000 Received: from usa-sjc-mx-foss1.foss.arm.com ([217.140.101.70] helo=foss.arm.com) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1hRDmC-0005hl-T3 for linux-arm-kernel@lists.infradead.org; Thu, 16 May 2019 10:38:29 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id AE6DF1B4B; Thu, 16 May 2019 03:38:16 -0700 (PDT) Received: from e121650-lin.cambridge.arm.com (e121650-lin.cambridge.arm.com [10.1.196.108]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 322813F703; Thu, 16 May 2019 03:38:15 -0700 (PDT) From: Raphael Gault To: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [RFC 09/16] arm64: assembler: Add macro to annotate asm function having non standard stack-frame. Date: Thu, 16 May 2019 11:36:48 +0100 Message-Id: <20190516103655.5509-10-raphael.gault@arm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190516103655.5509-1-raphael.gault@arm.com> References: <20190516103655.5509-1-raphael.gault@arm.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20190516_033817_921155_BB27EC87 X-CRM114-Status: GOOD ( 10.42 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: julien.thierry@arm.com, peterz@infradead.org, catalin.marinas@arm.com, will.deacon@arm.com, Raphael Gault , jpoimboe@redhat.com MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP Some functions don't have standard stack-frames but are intended this way. In order for objtool to ignore those particular cases we add a macro that enables us to annotate the cases we chose to mark as particular. Signed-off-by: Raphael Gault --- arch/arm64/include/asm/assembler.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h index c5308d01e228..8948474a9bcb 100644 --- a/arch/arm64/include/asm/assembler.h +++ b/arch/arm64/include/asm/assembler.h @@ -760,4 +760,17 @@ USER(\label, ic ivau, \tmp2) // invalidate I line PoU .Lyield_out_\@ : .endm + /* + * This macro is the arm64 assembler equivalent of the + * macro STACK_FRAME_NON_STANDARD define at + * ~/include/linux/frame.h + */ + .macro asm_stack_frame_non_standard func +#ifdef CONFIG_STACK_VALIDATION + .pushsection ".discard.func_stack_frame_non_standard" + .8byte \func + .popsection +#endif + .endm + #endif /* __ASM_ASSEMBLER_H */ From patchwork Thu May 16 10:36:49 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Raphael Gault X-Patchwork-Id: 10946337 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 01607924 for ; Thu, 16 May 2019 10:39:51 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E3CCB28842 for ; Thu, 16 May 2019 10:39:50 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D766A288BB; Thu, 16 May 2019 10:39:50 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 78D1F28842 for ; Thu, 16 May 2019 10:39:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=jklVUAW0mWOCOif2EWj1RQTsnId/6mJGs8ghenpwhy4=; b=Z/dErAvM5CM5vH1PCubpmRunjm 6ZVaF/YLI0888LGgO8PGK5t/9AmZsJh0aw9HW1sOkrG4U8HOy5wQkLAhMOETJ5YvRbgSfirMJJvud jmnIk0XWltACz8YxO1LrZzCeYCAjsS5a9ELSjtx4sWPaQhMIfxvrp8wv6nHkuH2iz6/ultgSY7Vm7 QkwL6ilNxMEL9nRZ5NXs29GPwOtHZa+RaY95NdqEI8jSEirgvEayKoX9DsmBb80cz8lWWnn/7XHur /o5CCKd9lBSBtwwm03GEjACVzoAhDCfErSJARwGf0yqTQKnBSmjuRKDrO9YQpeedlsqfS/4q+O5KX zkxm2Rfw==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1hRDnb-0007eG-Ey; Thu, 16 May 2019 10:39:43 +0000 Received: from foss.arm.com ([217.140.101.70]) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1hRDmE-0005sB-K4 for linux-arm-kernel@lists.infradead.org; Thu, 16 May 2019 10:38:34 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 7099219F6; Thu, 16 May 2019 03:38:18 -0700 (PDT) Received: from e121650-lin.cambridge.arm.com (e121650-lin.cambridge.arm.com [10.1.196.108]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id E9BD83F703; Thu, 16 May 2019 03:38:16 -0700 (PDT) From: Raphael Gault To: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [RFC 10/16] arm64: sleep: Prevent stack frame warnings from objtool Date: Thu, 16 May 2019 11:36:49 +0100 Message-Id: <20190516103655.5509-11-raphael.gault@arm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190516103655.5509-1-raphael.gault@arm.com> References: <20190516103655.5509-1-raphael.gault@arm.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20190516_033819_342660_9212D67A X-CRM114-Status: UNSURE ( 7.96 ) X-CRM114-Notice: Please train this message. X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: julien.thierry@arm.com, peterz@infradead.org, catalin.marinas@arm.com, will.deacon@arm.com, Raphael Gault , jpoimboe@redhat.com MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP This code doesn't respect the Arm PCS but it is intended this way. Adapting it to respect the PCS would result in altering the behaviour. In order to suppress objtool's warnings, we setup a stack frame for __cpu_suspend_enter and annotate cpu_resume and _cpu_resume as having non-standard stack frames. Signed-off-by: Raphael Gault --- arch/arm64/kernel/sleep.S | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/kernel/sleep.S b/arch/arm64/kernel/sleep.S index 3e53ffa07994..eb434525fe82 100644 --- a/arch/arm64/kernel/sleep.S +++ b/arch/arm64/kernel/sleep.S @@ -90,6 +90,7 @@ ENTRY(__cpu_suspend_enter) str x0, [x1] add x0, x0, #SLEEP_STACK_DATA_SYSTEM_REGS stp x29, lr, [sp, #-16]! + mov x29, sp bl cpu_do_suspend ldp x29, lr, [sp], #16 mov x0, #1 @@ -146,3 +147,6 @@ ENTRY(_cpu_resume) mov x0, #0 ret ENDPROC(_cpu_resume) + + asm_stack_frame_non_standard cpu_resume + asm_stack_frame_non_standard _cpu_resume From patchwork Thu May 16 10:36:50 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Raphael Gault X-Patchwork-Id: 10946339 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 9178A924 for ; Thu, 16 May 2019 10:39:58 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7EFC22854F for ; Thu, 16 May 2019 10:39:58 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 731BE28842; Thu, 16 May 2019 10:39:58 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 1E6302854F for ; Thu, 16 May 2019 10:39:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=szQ4kOhYi5F1NRBdtL3jjbrFjy4D+nXJzLOMmy9wqZY=; b=lGNT8Em/T4EwqWyF4FIzImyMB3 ZDcUU3BXyowAC0nQ7vdqRgAQprsHW+IVmyybw2KqD9OjkfllPgVzM0+OPxLpD1z9QEZ8QIeVdRwiC AtwRUe6l9DVpPfLQSoYFoMFYR0RVWj9WtH+F6trEPvHhi90rrpCx4HeJjfrV+Yx5WVs0nw+0UqXPO nb+tlSCU0wOlP+NwNjiDy1sWTqneROYx3BvGYNaSUkbyZ+hMhW/vU0cbCeWWH0iDUw0+J0vI2ZULy OV3jclHo4e9swh0y8/bewyk/27FTYee32JTUD29+DBiKd5QOq8blOpMmWPXseXDC+72faT7Atq8n8 mkQMsluQ==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1hRDnk-0007sR-Iv; Thu, 16 May 2019 10:39:52 +0000 Received: from usa-sjc-mx-foss1.foss.arm.com ([217.140.101.70] helo=foss.arm.com) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1hRDmG-0005ut-EB for linux-arm-kernel@lists.infradead.org; Thu, 16 May 2019 10:38:36 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 3DA8C1B55; Thu, 16 May 2019 03:38:20 -0700 (PDT) Received: from e121650-lin.cambridge.arm.com (e121650-lin.cambridge.arm.com [10.1.196.108]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id AD5393F703; Thu, 16 May 2019 03:38:18 -0700 (PDT) From: Raphael Gault To: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [RFC 11/16] objtool: arm64: Enable stack validation for arm64 Date: Thu, 16 May 2019 11:36:50 +0100 Message-Id: <20190516103655.5509-12-raphael.gault@arm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190516103655.5509-1-raphael.gault@arm.com> References: <20190516103655.5509-1-raphael.gault@arm.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20190516_033821_270920_451F3CD2 X-CRM114-Status: GOOD ( 10.17 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: julien.thierry@arm.com, peterz@infradead.org, catalin.marinas@arm.com, will.deacon@arm.com, Raphael Gault , jpoimboe@redhat.com MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP Signed-off-by: Raphael Gault --- arch/arm64/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 7e34b9eba5de..01ef19d26bfa 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -152,6 +152,7 @@ config ARM64 select HAVE_RCU_TABLE_INVALIDATE select HAVE_RSEQ select HAVE_STACKPROTECTOR + select HAVE_STACK_VALIDATION select HAVE_SYSCALL_TRACEPOINTS select HAVE_KPROBES select HAVE_KRETPROBES From patchwork Thu May 16 10:36:51 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Raphael Gault X-Patchwork-Id: 10946341 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A0CBE924 for ; Thu, 16 May 2019 10:40:11 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8A96F27F97 for ; Thu, 16 May 2019 10:40:11 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 77D0C280CF; Thu, 16 May 2019 10:40:11 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 2BEC127F97 for ; Thu, 16 May 2019 10:40:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=gg03djby57K/JU6aW0xq2OJDCf9KXjKSj9DbtMvf0ck=; b=jNycVksXctXxrIRt9DQMvyV4bx vf6ktM2PC6gqevCdD+cMUr3MAOfaMCErZpDGoWw7c7a631Dqfj66g9eGR042dHl+R+Z3wvyw1Flle bNtM8nLsx8JAOXDUSeIiBWhxCXNwQG07sZN0u3+/9dp7BHwk86AWN7qU4UhSrIgySmsZ33Ikl/YSg INkVs69FQ3qmHSwf46rQgRNHI4/IRCQUmI50sYOn5NAC06l04RaaE3Ui9Se+QdkasMNGkXIcX4H8h IcA5NS2Nx3GfwllxiKZDmlBo+HxJ6x0PQVr6zCR91eolS/ybTFjG5d76Qxbfxa6l02pXcgBykn3pf rO2jNt3w==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1hRDo0-0008K3-NL; Thu, 16 May 2019 10:40:08 +0000 Received: from usa-sjc-mx-foss1.foss.arm.com ([217.140.101.70] helo=foss.arm.com) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1hRDmI-0005jk-1W for linux-arm-kernel@lists.infradead.org; Thu, 16 May 2019 10:38:37 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 024C51A25; Thu, 16 May 2019 03:38:22 -0700 (PDT) Received: from e121650-lin.cambridge.arm.com (e121650-lin.cambridge.arm.com [10.1.196.108]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 7B8043F703; Thu, 16 May 2019 03:38:20 -0700 (PDT) From: Raphael Gault To: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [RFC 12/16] arm64: kvm: Annotate non-standard stack frame functions Date: Thu, 16 May 2019 11:36:51 +0100 Message-Id: <20190516103655.5509-13-raphael.gault@arm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190516103655.5509-1-raphael.gault@arm.com> References: <20190516103655.5509-1-raphael.gault@arm.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20190516_033822_832689_249201B1 X-CRM114-Status: GOOD ( 10.27 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: julien.thierry@arm.com, peterz@infradead.org, catalin.marinas@arm.com, will.deacon@arm.com, Raphael Gault , jpoimboe@redhat.com MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP Both __guest_entry and __guest_exit functions do not setup a correct stack frame. Because they can be considered as callable functions, even if they are particular cases, we chose to silence the warnings given by objtool by annotating them as non-standard. Signed-off-by: Raphael Gault --- arch/arm64/kvm/hyp/entry.S | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/kvm/hyp/entry.S b/arch/arm64/kvm/hyp/entry.S index 675fdc186e3b..a7b6d4ef35da 100644 --- a/arch/arm64/kvm/hyp/entry.S +++ b/arch/arm64/kvm/hyp/entry.S @@ -85,6 +85,7 @@ ENTRY(__guest_enter) eret sb ENDPROC(__guest_enter) +asm_stack_frame_non_standard __guest_enter ENTRY(__guest_exit) // x0: return code @@ -167,3 +168,4 @@ abort_guest_exit_end: orr x0, x0, x5 1: ret ENDPROC(__guest_exit) +asm_stack_frame_non_standard __guest_exit From patchwork Thu May 16 10:36:52 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Raphael Gault X-Patchwork-Id: 10946343 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 85820912 for ; Thu, 16 May 2019 10:40:28 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 73C1727F97 for ; Thu, 16 May 2019 10:40:28 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 6589C280CF; Thu, 16 May 2019 10:40:28 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 1031C27F97 for ; Thu, 16 May 2019 10:40:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=JNYLhd2Ikh/wUgVeTOT595UZlIl3+dP1Y9W2To5PObM=; b=FapwnNIS8+7vsyiTZuKjznl/xl 1C2QpUQpMKRrhDq3R6wX5TtAAn90VR5B3Qsd+wPexf472zDZGEKYziofiaqQurfNd2B89NbQEZeKm 6wfXk6D61SgU9iEvK4BCrCpf7Pkz0xpdjZwWM9af1QN8aFPytT4mAzMoLBD3vB9Z3xRT2bCZCJWq1 17cuL3C7VVo2L7DsfPqfRu3dBaXHBerI6I/27cTl35Ir4cYEhgsZFiyvrG5VqRvOJtmA8SBj010bP nfvIVM5T+lDWa8p9frXTW8L5senSp16Q5CAyA/Injqv8nmQpoB4aa8mFjUv+lFzz+8+h0XRapVkjI Y0hlsYmw==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1hRDoB-00018r-FL; Thu, 16 May 2019 10:40:19 +0000 Received: from usa-sjc-mx-foss1.foss.arm.com ([217.140.101.70] helo=foss.arm.com) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1hRDmJ-0005zu-UB for linux-arm-kernel@lists.infradead.org; Thu, 16 May 2019 10:38:38 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id BAF591B8E; Thu, 16 May 2019 03:38:23 -0700 (PDT) Received: from e121650-lin.cambridge.arm.com (e121650-lin.cambridge.arm.com [10.1.196.108]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 4040B3F703; Thu, 16 May 2019 03:38:22 -0700 (PDT) From: Raphael Gault To: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [RFC 13/16] arm64: kernel: Add exception on kuser32 to prevent stack analysis Date: Thu, 16 May 2019 11:36:52 +0100 Message-Id: <20190516103655.5509-14-raphael.gault@arm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190516103655.5509-1-raphael.gault@arm.com> References: <20190516103655.5509-1-raphael.gault@arm.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20190516_033824_468819_EE076DE5 X-CRM114-Status: GOOD ( 10.80 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: julien.thierry@arm.com, peterz@infradead.org, catalin.marinas@arm.com, will.deacon@arm.com, Raphael Gault , jpoimboe@redhat.com MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP kuser32 being used for compatibility, it contains a32 instructions which are not recognised by objtool when trying to analyse arm64 object files. Thus, we add an exception to skip validation on this particular file. Signed-off-by: Raphael Gault --- arch/arm64/kernel/Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index cd434d0719c1..c564f722ebca 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -29,6 +29,9 @@ $(obj)/%.stub.o: $(obj)/%.o FORCE obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \ sys_compat.o + +OBJECT_FILES_NON_STANDARD_kuser32.o := y + obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o entry-ftrace.o obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_ARM64_MODULE_PLTS) += module-plts.o From patchwork Thu May 16 10:36:53 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Raphael Gault X-Patchwork-Id: 10946347 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 62FC9912 for ; Thu, 16 May 2019 10:40:55 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5197B28A8E for ; Thu, 16 May 2019 10:40:55 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 45EF828A93; Thu, 16 May 2019 10:40:55 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id D8B4028A8E for ; Thu, 16 May 2019 10:40:54 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=vL8nJu6E1XoHl03W8W5wrbCImFP2HLXhJCllwcIuJRU=; b=tbY95bbVU5ToCbrbASkQEH1dSB QkcpiqBQZn9AQE0mgT98UPfXtJu1LzhsIRfT5CXSbGVW0Xvglp09Lz2XUUXtPF+eS3oNL+XbsOhuK d1aA6WkA1iab7Au18QfmC2zp1qSJg74bf1MXDBoYcmjZy+a99qR6PUMNoKHjwlgIvVWJqPHWiZzLA 4mjMZejHfoW1I8XblnwF7NE8Dndklv4tf4m3lpMw/3t3DyeoFRlorOgcoWfp+DMCxiEaZN6Y1BQkD GG2Ok6PDcrBJJy9huujacRpCHOqPrKeYIQ+WyENonkYSMuD8+WIqqkeIdzrn1q+Ain+2dtcXRUeYz L+JXNOYQ==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1hRDoe-0001jE-SI; Thu, 16 May 2019 10:40:48 +0000 Received: from foss.arm.com ([217.140.101.70]) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1hRDmL-000635-Rx for linux-arm-kernel@lists.infradead.org; Thu, 16 May 2019 10:38:42 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 7F59F1B96; Thu, 16 May 2019 03:38:25 -0700 (PDT) Received: from e121650-lin.cambridge.arm.com (e121650-lin.cambridge.arm.com [10.1.196.108]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 0489E3F703; Thu, 16 May 2019 03:38:23 -0700 (PDT) From: Raphael Gault To: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [RFC 14/16] arm64: crypto: Add exceptions for crypto object to prevent stack analysis Date: Thu, 16 May 2019 11:36:53 +0100 Message-Id: <20190516103655.5509-15-raphael.gault@arm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190516103655.5509-1-raphael.gault@arm.com> References: <20190516103655.5509-1-raphael.gault@arm.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20190516_033826_957116_822AC321 X-CRM114-Status: GOOD ( 10.04 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: julien.thierry@arm.com, peterz@infradead.org, catalin.marinas@arm.com, will.deacon@arm.com, Raphael Gault , jpoimboe@redhat.com MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP Some crypto modules contain `.word` of data in the .text section. Since objtool can't make the distinction between data and incorrect instruction, it gives a warning about the instruction beeing unknown and stops the analysis of the object file. The exception can be removed if the data are moved to another section or if objtool is tweaked to handle this particular case. Signed-off-by: Raphael Gault --- arch/arm64/crypto/Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/crypto/Makefile b/arch/arm64/crypto/Makefile index e766daf43b7c..d9125e7d4546 100644 --- a/arch/arm64/crypto/Makefile +++ b/arch/arm64/crypto/Makefile @@ -46,9 +46,11 @@ aes-neon-blk-y := aes-glue-neon.o aes-neon.o obj-$(CONFIG_CRYPTO_SHA256_ARM64) += sha256-arm64.o sha256-arm64-y := sha256-glue.o sha256-core.o +OBJECT_FILES_NON_STANDARD_sha256-core.o := y obj-$(CONFIG_CRYPTO_SHA512_ARM64) += sha512-arm64.o sha512-arm64-y := sha512-glue.o sha512-core.o +OBJECT_FILES_NON_STANDARD_sha512-core.o := y obj-$(CONFIG_CRYPTO_CHACHA20_NEON) += chacha-neon.o chacha-neon-y := chacha-neon-core.o chacha-neon-glue.o @@ -61,6 +63,7 @@ aes-arm64-y := aes-cipher-core.o aes-cipher-glue.o obj-$(CONFIG_CRYPTO_AES_ARM64_BS) += aes-neon-bs.o aes-neon-bs-y := aes-neonbs-core.o aes-neonbs-glue.o +OBJECT_FILES_NON_STANDARD_aes-neonbs-core.o := y CFLAGS_aes-glue-ce.o := -DUSE_V8_CRYPTO_EXTENSIONS From patchwork Thu May 16 10:36:54 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Raphael Gault X-Patchwork-Id: 10946349 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B8308924 for ; Thu, 16 May 2019 10:41:06 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A4CDE28A8E for ; Thu, 16 May 2019 10:41:06 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 98E7D28A93; Thu, 16 May 2019 10:41:06 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 2C6E128A8E for ; Thu, 16 May 2019 10:41:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=sMxZO+0Qos2nKMv0JUOuWuqoj90SWTY10s4Kgoew1Dw=; b=Rca1hlxyIHZQfLQGuleMb+fWLb sFuFTEUsa8ySKzsfDvqhgJGKfaBJXPQJ1FTucNyE2nmhnnYjtbqJxg/b5KCuWCiL1EgTGW5a1WOFn uiaA/FwjrzefYuiLhncm68WGzAOfOxB1Fu/oM33qtP0mXI67mF2UBcdr1kQY73U8zHF6IO6qeV6NV 4wiebqW5IvvYnS5/LYhIk+YM8nS7MdkDNXDiv3TFC7Yv+RHSHfW6fP5Xg17MmXv1YJ2aOX6EnvciQ DCT3/X6crpRclV1PG/55Zx8HcBZegycZOjQ1bL9dvaAi5PpoWqwyx9dibosDuy9/p0Je0VZgg0JR/ dE1D4IJQ==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1hRDop-0001x7-LM; Thu, 16 May 2019 10:40:59 +0000 Received: from foss.arm.com ([217.140.101.70]) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1hRDmN-00065o-Gv for linux-arm-kernel@lists.infradead.org; Thu, 16 May 2019 10:38:45 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 44CC71BA8; Thu, 16 May 2019 03:38:27 -0700 (PDT) Received: from e121650-lin.cambridge.arm.com (e121650-lin.cambridge.arm.com [10.1.196.108]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id BCFF53F703; Thu, 16 May 2019 03:38:25 -0700 (PDT) From: Raphael Gault To: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [RFC 15/16] objtool: Introduce INSN_UNKNOWN type Date: Thu, 16 May 2019 11:36:54 +0100 Message-Id: <20190516103655.5509-16-raphael.gault@arm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190516103655.5509-1-raphael.gault@arm.com> References: <20190516103655.5509-1-raphael.gault@arm.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20190516_033828_002114_F768421D X-CRM114-Status: GOOD ( 15.61 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: julien.thierry@arm.com, peterz@infradead.org, catalin.marinas@arm.com, will.deacon@arm.com, Raphael Gault , jpoimboe@redhat.com MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP On arm64 some object files contain data stored in the .text section. This data is interpreted by objtool as instruction but can't be identified as a valid one. In order to keep analysing those files we introduce INSN_UNKNOWN type. The "unknown instruction" warning will thus only be raised if such instructions are uncountered while validating an execution branch. This change doesn't impact the x86 decoding logic since 0 is still used as a way to specify an unknown type, raising the "unknown instruction" warning during the decoding phase still. Signed-off-by: Raphael Gault --- tools/objtool/arch.h | 3 ++- tools/objtool/arch/arm64/decode.c | 8 ++++---- tools/objtool/arch/arm64/include/insn_decode.h | 4 ++-- tools/objtool/check.c | 10 +++++++++- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/tools/objtool/arch.h b/tools/objtool/arch.h index c1ea6ecdd5d2..1f84690ad9f5 100644 --- a/tools/objtool/arch.h +++ b/tools/objtool/arch.h @@ -38,7 +38,8 @@ #define INSN_CLAC 12 #define INSN_STD 13 #define INSN_CLD 14 -#define INSN_OTHER 15 +#define INSN_UNKNOWN 15 +#define INSN_OTHER 16 #define INSN_LAST INSN_OTHER enum op_dest_type { diff --git a/tools/objtool/arch/arm64/decode.c b/tools/objtool/arch/arm64/decode.c index 5be1d87b1a1c..a40338a895f5 100644 --- a/tools/objtool/arch/arm64/decode.c +++ b/tools/objtool/arch/arm64/decode.c @@ -37,9 +37,9 @@ */ static arm_decode_class aarch64_insn_class_decode_table[] = { [INSN_RESERVED] = arm_decode_reserved, - [INSN_UNKNOWN] = arm_decode_unknown, + [INSN_UNALLOC_1] = arm_decode_unknown, [INSN_SVE_ENC] = arm_decode_sve_encoding, - [INSN_UNALLOC] = arm_decode_unknown, + [INSN_UNALLOC_2] = arm_decode_unknown, [INSN_LD_ST_4] = arm_decode_ld_st, [INSN_DP_REG_5] = arm_decode_dp_reg, [INSN_LD_ST_6] = arm_decode_ld_st, @@ -191,7 +191,7 @@ int arch_decode_instruction(struct elf *elf, struct section *sec, int arm_decode_unknown(u32 instr, unsigned char *type, unsigned long *immediate, struct stack_op *op) { - *type = 0; + *type = INSN_UNKNOWN; return 0; } @@ -206,7 +206,7 @@ int arm_decode_reserved(u32 instr, unsigned char *type, unsigned long *immediate, struct stack_op *op) { *immediate = instr & ONES(16); - *type = INSN_BUG; + *type = INSN_UNKNOWN; return 0; } diff --git a/tools/objtool/arch/arm64/include/insn_decode.h b/tools/objtool/arch/arm64/include/insn_decode.h index eb54fc39dca5..a01d76306749 100644 --- a/tools/objtool/arch/arm64/include/insn_decode.h +++ b/tools/objtool/arch/arm64/include/insn_decode.h @@ -20,9 +20,9 @@ #include "../../../arch.h" #define INSN_RESERVED 0b0000 -#define INSN_UNKNOWN 0b0001 +#define INSN_UNALLOC_1 0b0001 #define INSN_SVE_ENC 0b0010 -#define INSN_UNALLOC 0b0011 +#define INSN_UNALLOC_2 0b0011 #define INSN_DP_IMM 0b1001 //0x100x #define INSN_BRANCH 0b1011 //0x101x #define INSN_LD_ST_4 0b0100 //0bx1x0 diff --git a/tools/objtool/check.c b/tools/objtool/check.c index bfb36cca9be1..90a26f238899 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -1961,6 +1961,13 @@ static int validate_branch(struct objtool_file *file, struct instruction *first, while (1) { next_insn = next_insn_same_sec(file, insn); + if (insn->type == INSN_UNKNOWN) { + WARN("%s+0x%lx unknown instruction type, should never be reached", + insn->sec->name, + insn->offset); + return 1; + } + if (file->c_file && func && insn->func && func != insn->func->pfunc) { WARN("%s() falls through to next function %s()", func->name, insn->func->name); @@ -2391,7 +2398,8 @@ static int validate_reachable_instructions(struct objtool_file *file) return 0; for_each_insn(file, insn) { - if (insn->visited || ignore_unreachable_insn(insn)) + if (insn->visited || ignore_unreachable_insn(insn) || + insn->type == INSN_UNKNOWN) continue; WARN_FUNC("unreachable instruction", insn->sec, insn->offset); From patchwork Thu May 16 10:36:55 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Raphael Gault X-Patchwork-Id: 10946369 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B12636C5 for ; Thu, 16 May 2019 10:54:27 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9FB2028B49 for ; Thu, 16 May 2019 10:54:27 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 93C8928B4B; Thu, 16 May 2019 10:54:27 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 25A2128B49 for ; Thu, 16 May 2019 10:54:27 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=fPBra5ght+gZrGU7ayHCM2ceSKarj6g/aBep90WrpMk=; b=SzZF7UVkDV+Q0+1qcx5o23AYSY igbV86xXDSbXw7wQgGaOjW6XBmx+9sGrEacMmKwZxeeNowarWYZdemcik6Dm/MxrrFB53T2DRc30l btmZhAKaoNoIEIjMpXVuwjq+KwqRlsPk0e8q5eM9Ke0xIMZppG/wRJpfoJq4wqMv62jxUdrmI8XA5 7jdb13RcEcnnwudypNx8Kh2oC3FqZzUVy8AQ3GQ/cMwTmKvJ42rbsnghbd7+dQ0szJ3hCARH4lOTg bH7gJB6eiS2YB0zsvQJZtti175Upeq6jR1hLaWnflWjihngEtBpaoS5pMgGQWMUaF8P6YjRRlJ3CH jOoyRLCg==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1hRE1q-0006qu-3y; Thu, 16 May 2019 10:54:26 +0000 Received: from casper.infradead.org ([2001:8b0:10b:1236::1]) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1hRE1o-0006gi-BH for linux-arm-kernel@bombadil.infradead.org; Thu, 16 May 2019 10:54:24 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=References:In-Reply-To:Message-Id:Date: Subject:Cc:To:From:Sender:Reply-To:MIME-Version:Content-Type: Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id: List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive; bh=z912eElseHarlLlLSfN0X6jYDSi4HF3peDyqZ/OF9Is=; b=SAQVBQx4A/XSrCPO/csr4zMW0 2nxGbXyN9q3cENJ49pa/pEKxxirsNHwyI9bAxB1h6fqHxaE4Cp0eaJ8b4lt2uFoU9Q9J2XsiGFTtw tfqf4oXXDCexxykT9AhacfmxD6W28ACnlfasznZpWSGQizt3F6UjKO+8lG6McRwNxrKg5SubV3tH3 6UtTM9/jNJzPReSEO20hIIwfEkvqmROxkpvwvuYg1hSvoAsEhkLo2J3oi7a8akogESFxR/P5fcqmy h9a/shov0T+uzpQGq51haw9KQsBZsbLcT8JZPkpDD8vIlOFsavgiigfLHdkJEpxpJ3V6Lu9Rb+grp cU1XFY4zA==; Received: from foss.arm.com ([217.140.101.70]) by casper.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1hRDmP-0001x6-Jf for linux-arm-kernel@lists.infradead.org; Thu, 16 May 2019 10:38:31 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 0A3381BB0; Thu, 16 May 2019 03:38:29 -0700 (PDT) Received: from e121650-lin.cambridge.arm.com (e121650-lin.cambridge.arm.com [10.1.196.108]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 834C03F703; Thu, 16 May 2019 03:38:27 -0700 (PDT) From: Raphael Gault To: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [RFC 16/16] arm64: kernel: Annotate non-standard stack frame functions Date: Thu, 16 May 2019 11:36:55 +0100 Message-Id: <20190516103655.5509-17-raphael.gault@arm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190516103655.5509-1-raphael.gault@arm.com> References: <20190516103655.5509-1-raphael.gault@arm.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20190516_113829_783575_86DC923A X-CRM114-Status: UNSURE ( 6.91 ) X-CRM114-Notice: Please train this message. X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: julien.thierry@arm.com, peterz@infradead.org, catalin.marinas@arm.com, will.deacon@arm.com, Raphael Gault , jpoimboe@redhat.com MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP Annotate assembler functions which are callable but do not setup a correct stack frame. Signed-off-by: Raphael Gault --- arch/arm64/kernel/hyp-stub.S | 2 ++ arch/arm64/kvm/hyp-init.S | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/arm64/kernel/hyp-stub.S b/arch/arm64/kernel/hyp-stub.S index 17f325ba831e..ded5a50d95bf 100644 --- a/arch/arm64/kernel/hyp-stub.S +++ b/arch/arm64/kernel/hyp-stub.S @@ -53,6 +53,7 @@ ENTRY(__hyp_stub_vectors) ventry el1_fiq_invalid // FIQ 32-bit EL1 ventry el1_error_invalid // Error 32-bit EL1 ENDPROC(__hyp_stub_vectors) +asm_stack_frame_non_standard __hyp_stub_vectors .align 11 @@ -80,6 +81,7 @@ el1_sync: 9: mov x0, xzr eret ENDPROC(el1_sync) +asm_stack_frame_non_standard el1_sync .macro invalid_vector label \label: diff --git a/arch/arm64/kvm/hyp-init.S b/arch/arm64/kvm/hyp-init.S index 4576b86a5579..2ef2e2c51824 100644 --- a/arch/arm64/kvm/hyp-init.S +++ b/arch/arm64/kvm/hyp-init.S @@ -129,6 +129,7 @@ CPU_BE( orr x4, x4, #SCTLR_ELx_EE) /* Hello, World! */ eret ENDPROC(__kvm_hyp_init) +asm_stack_frame_non_standard __kvm_hyp_init ENTRY(__kvm_handle_stub_hvc) cmp x0, #HVC_SOFT_RESTART @@ -170,6 +171,7 @@ reset: eret ENDPROC(__kvm_handle_stub_hvc) +asm_stack_frame_non_standard __kvm_handle_stub_hvc .ltorg