linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC v5 00/57] objtool: Add support for arm64
@ 2020-01-09 16:02 Julien Thierry
  2020-01-09 16:02 ` [RFC v5 01/57] objtool: check: Remove redundant checks on operand type Julien Thierry
                   ` (59 more replies)
  0 siblings, 60 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

Hi,

This patch series is the continuation of Raphael's work [1]. All the
patches can be retrieved from:
git clone -b arm64-objtool-v5 https://github.com/julien-thierry/linux.git

There still are some outstanding issues but the series is starting to
get pretty big so it is probably good to start having some discussions
on the current state of things.

It felt necessary to split some of the patches (especially the arm64
decoder). In order to give Raphael credit for his work I used the
"Suggested-by" tag. If this is not the right way to give credit or if
it should be present on more patches do let me know.

There still are some shortcomings. On defconfig here are the remaining
warnings:
* arch/arm64/crypto/crct10dif-ce-core.o: warning: objtool: crc_t10dif_pmull_p8()+0xf0: unsupported intra-function call
* arch/arm64/kernel/cpu_errata.o: warning: objtool: qcom_link_stack_sanitization()+0x4: unsupported intra-function call
Objtool currently does not support bl from a procedure to itself. This
is also an issue with retpolines. I need to investigate more to figure
out whether something can be done for this or if this file should not be
validated by objtool.

* arch/arm64/kernel/efi-entry.o: warning: objtool: entry()+0xb0: sibling call from callable instruction with modified stack frame
The EFI entry jumps to code mapped by EFI. Objtool cannot know statically where the code flow is going.

* arch/arm64/kernel/entry.o: warning: objtool: .entry.tramp.text+0x404: unsupported intra-function call
Need to figure out what is needed to handle aarch64 trampolines. x86
explicitly annotates theirs with ANNOTATE_NOSPEC_ALTERNATIVE and
patching them as alternatives.

* arch/arm64/kernel/head.o: warning: objtool: .head.text+0x58: can't find jump dest instruction at .head.text+0x80884
This is actually a constant that turns out to be a valid branch opcode.
A possible solution could be to introduce a marco that explicitly
annotates constants placed in code sections.

* arch/arm64/kernel/hibernate-asm.o: warning: objtool: el1_sync()+0x4: unsupported instruction in callable function
Symbols el<x>_* shouldn't be considered as callable functions. Should we
use SYM_CODE_END instead of PROC_END?

* arch/arm64/kvm/hyp/hyp-entry.o: warning: objtool: .hyp.text: empty alternative at end of section
This is due to the arm64 alternative_cb. Currently, the feature
corresponding to the alternative_cb is defined as the current number of
features supported by the kernel, meaning the identifier is not fixed
accross kernel versions. This makes it a bit hard to detect these
alternative_cb for external tools.

Would it be acceptable to set a fixed identifier for alternative_cb?
(probably 0xFF so it is always higher than the number of real features)

* drivers/ata/libata-scsi.o: warning: objtool: ata_sas_queuecmd() falls through to next function ata_scsi_scan_host()
This is due to a limitation in the switch table metadata interpretation.
The compiler might create a table of unsigned offsets and then
compute the final offset as follows:

	ldrb    offset_reg, [<offset_table>, <offset_idx>, uxtw]
	adr     base_reg, <base_addr>
	add     res_addr, base_reg, offset_reg, sxtb #2

Effectively using the loaded offset as a signed value.
I don't have a simple way to solve this at the moment, I'd like to
avoid decoding the instructions to check which ones might sign extend
the loaded offset.

* kernel/bpf/core.o: warning: objtool: ___bpf_prog_run()+0x44: sibling call from callable instruction with modified stack frame
This is because the function uses a C jump table which differ from
basic jump tables. Also, the code generated for C jump tables on arm64
does not follow the same form as the one for x86. So the existing x86 objtool
code handling C jump tables can't be used.

I'll focus on understanding the arm64 pattern so objtool can handle them.


In the mean time, any feedback on the current state is appreciated.

* Patches 1 to 18 adapts the current objtool code to make it easier to
  support new architectures.
* Patches 19 to 45 add the support for arm64 architecture to objtool.
* Patches 46 to 57 fix warnings reported by objtool on the existing
  arm64 code.

Changes since RFCv4[1]:
* Rebase on v5.5-rc5
* Misc cleanup/bug fixes
* Fix some new objtool warnings reported on arm64 objects
* Make ORC subcommand optional since arm64 does not currently support it
* Support branch instructions in alternative sections when they jump
  within the same set of alternative instructions
* Replace the "extra" stack_op with a list of stack_op
* Split the decoder into multiple patches to ease review
* Mark constants generated by load literal instructions as bytes that
  should not be reached by execution flow
* Rework the switch table handling

[1] https://lkml.org/lkml/2019/8/16/400

Thanks,

Julien

-->

Julien Thierry (43):
  objtool: check: Remove redundant checks on operand type
  objtool: check: Clean instruction state before each function
    validation
  objtool: check: Use arch specific values in restore_reg()
  objtool: check: Ignore empty alternative groups
  objtool: Give ORC functions consistent name
  objtool: Make ORC support optional
  objtool: Split generic and arch specific CFI definitions
  objtool: Abstract alternative special case handling
  objtool: check: Allow jumps from an alternative group to itself
  objtool: Do not look for STT_NOTYPE symbols
  objtool: Support addition to set frame pointer
  objtool: Support restoring BP from the stack without POP
  objtool: Make stack validation more generic
  objtool: Support multiple stack_op per instruction
  objtool: arm64: Decode unknown instructions
  objtool: arm64: Decode simple data processing instructions
  objtool: arm64: Decode add/sub immediate instructions
  objtool: arm64: Decode logical data processing instructions
  objtool: arm64: Decode system instructions not affecting the flow
  objtool: arm64: Decode calls to higher EL
  objtool: arm64: Decode brk instruction
  objtool: arm64: Decode instruction triggering context switch
  objtool: arm64: Decode branch instructions with PC relative immediates
  objtool: arm64: Decode branch to register instruction
  objtool: arm64: Decode basic load/stores
  objtool: arm64: Decode load/store with register offset
  objtool: arm64: Decode load/store register pair instructions
  objtool: arm64: Decode FP/SIMD load/store instructions
  objtool: arm64: Decode load/store exclusive
  objtool: arm64: Decode atomic load/store
  objtool: arm64: Decode pointer auth load instructions
  objtool: arm64: Decode load acquire/store release
  objtool: arm64: Decode load/store with memory tag
  objtool: arm64: Decode load literal
  objtool: arm64: Decode register data processing instructions
  objtool: arm64: Decode FP/SIMD data processing instructions
  objtool: arm64: Decode SVE instructions
  objtool: arm64: Implement functions to add switch tables alternatives
  arm64: Generate no-ops to pad executable section
  arm64: Move constant to rodata
  arm64: Mark sigreturn32.o as containing non standard code
  arm64: entry: Avoid empty alternatives entries
  arm64: crypto: Remove redundant branch

Raphael Gault (14):
  objtool: Add abstraction for computation of symbols offsets
  objtool: orc: Refactor ORC API for other architectures to implement.
  objtool: Move registers and control flow to arch-dependent code
  objtool: Refactor switch-tables code to support other architectures
  objtool: arm64: Add required implementation for supporting the aarch64
    architecture in objtool.
  gcc-plugins: objtool: Add plugin to detect switch table on arm64
  objtool: arm64: Enable stack validation for arm64
  arm64: alternative: Mark .altinstr_replacement as containing
    executable instructions
  arm64: assembler: Add macro to annotate asm function having non
    standard stack-frame.
  arm64: sleep: Prevent stack frame warnings from objtool
  arm64: kvm: Annotate non-standard stack frame functions
  arm64: kernel: Add exception on kuser32 to prevent stack analysis
  arm64: crypto: Add exceptions for crypto object to prevent stack
    analysis
  arm64: kernel: Annotate non-standard stack frame functions

 arch/arm64/Kconfig                            |    2 +
 arch/arm64/crypto/Makefile                    |    3 +
 arch/arm64/crypto/sha1-ce-core.S              |    3 +-
 arch/arm64/crypto/sha2-ce-core.S              |    3 +-
 arch/arm64/crypto/sha3-ce-core.S              |    3 +-
 arch/arm64/crypto/sha512-ce-core.S            |    3 +-
 arch/arm64/include/asm/alternative.h          |    2 +-
 arch/arm64/kernel/Makefile                    |    4 +
 arch/arm64/kernel/entry.S                     |    4 +-
 arch/arm64/kernel/hyp-stub.S                  |    3 +
 arch/arm64/kernel/relocate_kernel.S           |    5 +
 arch/arm64/kernel/sleep.S                     |    5 +
 arch/arm64/kvm/hyp-init.S                     |    3 +
 arch/arm64/kvm/hyp/entry.S                    |    3 +
 include/linux/frame.h                         |   19 +-
 scripts/Makefile.gcc-plugins                  |    2 +
 scripts/gcc-plugins/Kconfig                   |    4 +
 .../arm64_switch_table_detection_plugin.c     |   94 +
 tools/objtool/Build                           |    4 +-
 tools/objtool/Makefile                        |   13 +-
 tools/objtool/arch.h                          |   14 +-
 tools/objtool/arch/arm64/Build                |    5 +
 tools/objtool/arch/arm64/arch_special.c       |  262 ++
 tools/objtool/arch/arm64/bit_operations.c     |   69 +
 tools/objtool/arch/arm64/decode.c             | 2866 +++++++++++++++++
 .../objtool/arch/arm64/include/arch_special.h |   23 +
 .../arch/arm64/include/bit_operations.h       |   31 +
 tools/objtool/arch/arm64/include/cfi_regs.h   |   44 +
 .../objtool/arch/arm64/include/insn_decode.h  |  206 ++
 tools/objtool/arch/x86/Build                  |    3 +
 tools/objtool/arch/x86/arch_special.c         |  182 ++
 tools/objtool/arch/x86/decode.c               |   29 +-
 tools/objtool/arch/x86/include/arch_special.h |   28 +
 tools/objtool/arch/x86/include/cfi_regs.h     |   25 +
 tools/objtool/{ => arch/x86}/orc_dump.c       |    4 +-
 tools/objtool/{ => arch/x86}/orc_gen.c        |  114 +-
 tools/objtool/cfi.h                           |   21 +-
 tools/objtool/check.c                         |  461 +--
 tools/objtool/check.h                         |   13 +-
 tools/objtool/elf.c                           |    3 +-
 tools/objtool/objtool.c                       |    2 +
 tools/objtool/orc.h                           |   38 +-
 tools/objtool/special.c                       |   44 +-
 tools/objtool/special.h                       |   13 +
 44 files changed, 4282 insertions(+), 400 deletions(-)
 create mode 100644 scripts/gcc-plugins/arm64_switch_table_detection_plugin.c
 create mode 100644 tools/objtool/arch/arm64/Build
 create mode 100644 tools/objtool/arch/arm64/arch_special.c
 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/bit_operations.h
 create mode 100644 tools/objtool/arch/arm64/include/cfi_regs.h
 create mode 100644 tools/objtool/arch/arm64/include/insn_decode.h
 create mode 100644 tools/objtool/arch/x86/arch_special.c
 create mode 100644 tools/objtool/arch/x86/include/arch_special.h
 create mode 100644 tools/objtool/arch/x86/include/cfi_regs.h
 rename tools/objtool/{ => arch/x86}/orc_dump.c (98%)
 rename tools/objtool/{ => arch/x86}/orc_gen.c (62%)

--
2.21.0


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

* [RFC v5 01/57] objtool: check: Remove redundant checks on operand type
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 02/57] objtool: check: Clean instruction state before each function validation Julien Thierry
                   ` (58 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

POP operations are already in code path where destination operand
is OP_DEST_REG. There is no need to check the operand type again.

Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/check.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 4768d91c6d68..a04778421144 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -1672,15 +1672,13 @@ static int update_insn_state(struct instruction *insn, struct insn_state *state)

 		case OP_SRC_POP:
 		case OP_SRC_POPF:
-			if (!state->drap && op->dest.type == OP_DEST_REG &&
-			    op->dest.reg == cfa->base) {
+			if (!state->drap && op->dest.reg == cfa->base) {

 				/* pop %rbp */
 				cfa->base = CFI_SP;
 			}

 			if (state->drap && cfa->base == CFI_BP_INDIRECT &&
-			    op->dest.type == OP_DEST_REG &&
 			    op->dest.reg == state->drap_reg &&
 			    state->drap_offset == -state->stack_size) {

--
2.21.0


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

* [RFC v5 02/57] objtool: check: Clean instruction state before each function validation
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
  2020-01-09 16:02 ` [RFC v5 01/57] objtool: check: Remove redundant checks on operand type Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 03/57] objtool: check: Use arch specific values in restore_reg() Julien Thierry
                   ` (57 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

When a function fails its validation, it might leave a stale state
that will be used for the validation of other functions. That would
cause false warnings on potentially valid functions.

Reset the instruction state before the validation of each individual
function.

Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/check.c | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index a04778421144..4784f0f6a3ae 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -2348,13 +2348,6 @@ static int validate_functions(struct objtool_file *file)
 	struct insn_state state;
 	int ret, warnings = 0;

-	clear_insn_state(&state);
-
-	state.cfa = initial_func_cfi.cfa;
-	memcpy(&state.regs, &initial_func_cfi.regs,
-	       CFI_NUM_REGS * sizeof(struct cfi_reg));
-	state.stack_size = initial_func_cfi.cfa.offset;
-
 	for_each_sec(file, sec) {
 		list_for_each_entry(func, &sec->symbol_list, list) {
 			if (func->type != STT_FUNC)
@@ -2373,6 +2366,12 @@ static int validate_functions(struct objtool_file *file)
 			if (!insn || insn->ignore || insn->visited)
 				continue;

+			clear_insn_state(&state);
+			state.cfa = initial_func_cfi.cfa;
+			memcpy(&state.regs, &initial_func_cfi.regs,
+			       CFI_NUM_REGS * sizeof(struct cfi_reg));
+			state.stack_size = initial_func_cfi.cfa.offset;
+
 			state.uaccess = func->uaccess_safe;

 			ret = validate_branch(file, func, insn, state);
--
2.21.0


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

* [RFC v5 03/57] objtool: check: Use arch specific values in restore_reg()
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
  2020-01-09 16:02 ` [RFC v5 01/57] objtool: check: Remove redundant checks on operand type Julien Thierry
  2020-01-09 16:02 ` [RFC v5 02/57] objtool: check: Clean instruction state before each function validation Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 04/57] objtool: check: Ignore empty alternative groups Julien Thierry
                   ` (56 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

Initial register state is set up by arch specific code. Use the value
the arch code has set when restoring registers from the stack.

Suggested-by: Raphael Gault <raphael.gault@arm.com>
Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/check.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 4784f0f6a3ae..5968e6f08891 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -1437,8 +1437,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;
 }
 
 /*
-- 
2.21.0


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

* [RFC v5 04/57] objtool: check: Ignore empty alternative groups
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (2 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 03/57] objtool: check: Use arch specific values in restore_reg() Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-21 16:30   ` Josh Poimboeuf
  2020-01-09 16:02 ` [RFC v5 05/57] objtool: Add abstraction for computation of symbols offsets Julien Thierry
                   ` (55 subsequent siblings)
  59 siblings, 1 reply; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

Atlernative section can contain entries for alternatives with no
instructions. Objtool will currently crash when handling such an entry.

Just skip that entry, but still give a warning to discourage useless
entries.

Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/check.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 5968e6f08891..27e5380e0e0b 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -866,6 +866,13 @@ static int add_special_section_alts(struct objtool_file *file)
 		}
 
 		if (special_alt->group) {
+			if (!special_alt->orig_len) {
+				WARN("empty alternative entry at %s+0x%lx",
+				     orig_insn->sec->name,
+				     orig_insn->offset);
+				continue;
+			}
+
 			ret = handle_group_alt(file, special_alt, orig_insn,
 					       &new_insn);
 			if (ret)
-- 
2.21.0


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

* [RFC v5 05/57] objtool: Add abstraction for computation of symbols offsets
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (3 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 04/57] objtool: check: Ignore empty alternative groups Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 06/57] objtool: Give ORC functions consistent name Julien Thierry
                   ` (54 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

From: Raphael Gault <raphael.gault@arm.com>

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 <raphael.gault@arm.com>
[J.T. Remove superfluous comment, replace other addend offsets
      with arch_dest_rela_offset]
Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/arch.h            |  6 ++++++
 tools/objtool/arch/x86/decode.c | 11 +++++++++++
 tools/objtool/check.c           | 18 ++++++++++--------
 3 files changed, 27 insertions(+), 8 deletions(-)

diff --git a/tools/objtool/arch.h b/tools/objtool/arch.h
index ced3765c4f44..a9a50a25ca66 100644
--- a/tools/objtool/arch.h
+++ b/tools/objtool/arch.h
@@ -66,6 +66,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,
@@ -75,4 +77,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 a62e032863a8..79ff33ffa6e0 100644
--- a/tools/objtool/arch/x86/decode.c
+++ b/tools/objtool/arch/x86/decode.c
@@ -11,6 +11,7 @@
 #include "../../../arch/x86/lib/inat.c"
 #include "../../../arch/x86/lib/insn.c"
 
+#include "../../check.h"
 #include "../../elf.h"
 #include "../../arch.h"
 #include "../../warn.h"
@@ -66,6 +67,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, enum insn_type *type,
@@ -497,3 +503,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 27e5380e0e0b..6a5f78cca27c 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -564,13 +564,14 @@ 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;
+			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
@@ -660,7 +661,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);
 
@@ -673,14 +674,15 @@ static int add_call_destinations(struct objtool_file *file)
 			}
 
 		} else if (rela->sym->type == STT_SECTION) {
+			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
@@ -771,7 +773,7 @@ static int handle_group_alt(struct objtool_file *file,
 		if (!insn->immediate)
 			continue;
 
-		dest_off = insn->offset + insn->len + insn->immediate;
+		dest_off = arch_jump_destination(insn);
 		if (dest_off == special_alt->new_off + special_alt->new_len) {
 			if (!fake_jump) {
 				WARN("%s: alternative jump to end of section",
-- 
2.21.0


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

* [RFC v5 06/57] objtool: Give ORC functions consistent name
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (4 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 05/57] objtool: Add abstraction for computation of symbols offsets Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 07/57] objtool: orc: Refactor ORC API for other architectures to implement Julien Thierry
                   ` (53 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

Rename ORC manipulating functions to have more consistent name. Have
"orc_" as a prefix for all of them.

No functionality change.

Suggested-by: Josh Poimboeuf <jpoimboe@redhat.com>
Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/check.c   |  4 ++--
 tools/objtool/orc.h     |  4 ++--
 tools/objtool/orc_gen.c | 14 +++++++-------
 3 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 6a5f78cca27c..dd155095251c 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -2481,11 +2481,11 @@ int check(const char *_objname, bool orc)
 	}
 
 	if (orc) {
-		ret = create_orc(&file);
+		ret = orc_init(&file);
 		if (ret < 0)
 			goto out;
 
-		ret = create_orc_sections(&file);
+		ret = orc_create_sections(&file);
 		if (ret < 0)
 			goto out;
 
diff --git a/tools/objtool/orc.h b/tools/objtool/orc.h
index ee2832221e62..cd44417487e4 100644
--- a/tools/objtool/orc.h
+++ b/tools/objtool/orc.h
@@ -10,8 +10,8 @@
 
 struct objtool_file;
 
-int create_orc(struct objtool_file *file);
-int create_orc_sections(struct objtool_file *file);
+int orc_init(struct objtool_file *file);
+int orc_create_sections(struct objtool_file *file);
 
 int orc_dump(const char *objname);
 
diff --git a/tools/objtool/orc_gen.c b/tools/objtool/orc_gen.c
index 27a4112848c2..29bee7bd212a 100644
--- a/tools/objtool/orc_gen.c
+++ b/tools/objtool/orc_gen.c
@@ -10,7 +10,7 @@
 #include "check.h"
 #include "warn.h"
 
-int create_orc(struct objtool_file *file)
+int orc_init(struct objtool_file *file)
 {
 	struct instruction *insn;
 
@@ -81,9 +81,9 @@ int create_orc(struct objtool_file *file)
 	return 0;
 }
 
-static int create_orc_entry(struct section *u_sec, struct section *ip_relasec,
-				unsigned int idx, struct section *insn_sec,
-				unsigned long insn_off, struct orc_entry *o)
+static int orc_create_entry(struct section *u_sec, struct section *ip_relasec,
+			    unsigned int idx, struct section *insn_sec,
+			    unsigned long insn_off, struct orc_entry *o)
 {
 	struct orc_entry *orc;
 	struct rela *rela;
@@ -116,7 +116,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 orc_create_sections(struct objtool_file *file)
 {
 	struct instruction *insn, *prev_insn;
 	struct section *sec, *u_sec, *ip_relasec;
@@ -182,7 +182,7 @@ int create_orc_sections(struct objtool_file *file)
 			if (!prev_insn || memcmp(&insn->orc, &prev_insn->orc,
 						 sizeof(struct orc_entry))) {
 
-				if (create_orc_entry(u_sec, ip_relasec, idx,
+				if (orc_create_entry(u_sec, ip_relasec, idx,
 						     insn->sec, insn->offset,
 						     &insn->orc))
 					return -1;
@@ -194,7 +194,7 @@ int create_orc_sections(struct objtool_file *file)
 
 		/* section terminator */
 		if (prev_insn) {
-			if (create_orc_entry(u_sec, ip_relasec, idx,
+			if (orc_create_entry(u_sec, ip_relasec, idx,
 					     prev_insn->sec,
 					     prev_insn->offset + prev_insn->len,
 					     &empty))
-- 
2.21.0


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

* [RFC v5 07/57] objtool: orc: Refactor ORC API for other architectures to implement.
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (5 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 06/57] objtool: Give ORC functions consistent name Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 08/57] objtool: Make ORC support optional Julien Thierry
                   ` (52 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

From: Raphael Gault <raphael.gault@arm.com>

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,
move the implementation be done in the architecture dependent code.

Signed-off-by: Raphael Gault <raphael.gault@arm.com>
[J.T. Rebase on orc name changes,
      Move arch_orc_read_unwind_hints() to orc.h,
      Reword commit message to use imperative language]
Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/Build                     |   2 -
 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                     |   5 +-
 6 files changed, 109 insertions(+), 107 deletions(-)
 rename tools/objtool/{ => arch/x86}/orc_dump.c (98%)
 rename tools/objtool/{ => arch/x86}/orc_gen.c (66%)

diff --git a/tools/objtool/Build b/tools/objtool/Build
index 8dc4f0848362..d069d26d97fa 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/x86/Build b/tools/objtool/arch/x86/Build
index 7c5004008e97..e43fd6fa0ee1 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 13ccf775a83a..cfe8f96bdd68 100644
--- a/tools/objtool/orc_dump.c
+++ b/tools/objtool/arch/x86/orc_dump.c
@@ -4,8 +4,8 @@
  */
 
 #include <unistd.h>
-#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 66%
rename from tools/objtool/orc_gen.c
rename to tools/objtool/arch/x86/orc_gen.c
index 29bee7bd212a..e8be41a1bf94 100644
--- a/tools/objtool/orc_gen.c
+++ b/tools/objtool/arch/x86/orc_gen.c
@@ -6,11 +6,11 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include "orc.h"
-#include "check.h"
-#include "warn.h"
+#include "../../orc.h"
+#include "../../check.h"
+#include "../../warn.h"
 
-int orc_init(struct objtool_file *file)
+int arch_orc_init(struct objtool_file *file)
 {
 	struct instruction *insn;
 
@@ -116,7 +116,7 @@ static int orc_create_entry(struct section *u_sec, struct section *ip_relasec,
 	return 0;
 }
 
-int orc_create_sections(struct objtool_file *file)
+int arch_orc_create_sections(struct objtool_file *file)
 {
 	struct instruction *insn, *prev_insn;
 	struct section *sec, *u_sec, *ip_relasec;
@@ -209,3 +209,97 @@ int orc_create_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 dd155095251c..2c5ccf61510a 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -1167,99 +1167,6 @@ static int add_jump_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)
 {
@@ -1359,7 +1266,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;
 
@@ -2481,11 +2388,11 @@ int check(const char *_objname, bool orc)
 	}
 
 	if (orc) {
-		ret = orc_init(&file);
+		ret = arch_orc_init(&file);
 		if (ret < 0)
 			goto out;
 
-		ret = orc_create_sections(&file);
+		ret = arch_orc_create_sections(&file);
 		if (ret < 0)
 			goto out;
 
diff --git a/tools/objtool/orc.h b/tools/objtool/orc.h
index cd44417487e4..ffda072cf4ad 100644
--- a/tools/objtool/orc.h
+++ b/tools/objtool/orc.h
@@ -10,8 +10,9 @@
 
 struct objtool_file;
 
-int orc_init(struct objtool_file *file);
-int orc_create_sections(struct objtool_file *file);
+int arch_orc_init(struct objtool_file *file);
+int arch_orc_create_sections(struct objtool_file *file);
+int arch_orc_read_unwind_hints(struct objtool_file *file);
 
 int orc_dump(const char *objname);
 
-- 
2.21.0


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

* [RFC v5 08/57] objtool: Make ORC support optional
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (6 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 07/57] objtool: orc: Refactor ORC API for other architectures to implement Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-21 16:37   ` Josh Poimboeuf
  2020-01-09 16:02 ` [RFC v5 09/57] objtool: Move registers and control flow to arch-dependent code Julien Thierry
                   ` (51 subsequent siblings)
  59 siblings, 1 reply; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

Currently, only x86 supports ORC. To simplify the addition of other
supported architectures to objtool 'check' command, make the 'orc'
objtool command optional to implement for a given architecture.

Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/Build     |  2 +-
 tools/objtool/Makefile  | 10 +++++++++-
 tools/objtool/check.c   |  4 ++++
 tools/objtool/objtool.c |  2 ++
 tools/objtool/orc.h     | 33 +++++++++++++++++++++++++++++++--
 5 files changed, 47 insertions(+), 4 deletions(-)

diff --git a/tools/objtool/Build b/tools/objtool/Build
index d069d26d97fa..6e7163f9522a 100644
--- a/tools/objtool/Build
+++ b/tools/objtool/Build
@@ -1,6 +1,6 @@
 objtool-y += arch/$(SRCARCH)/
 objtool-y += builtin-check.o
-objtool-y += builtin-orc.o
+objtool-$(OBJTOOL_ORC) += builtin-orc.o
 objtool-y += check.o
 objtool-y += elf.o
 objtool-y += special.o
diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile
index d2a19b0bc05a..24d653e0b6ec 100644
--- a/tools/objtool/Makefile
+++ b/tools/objtool/Makefile
@@ -6,6 +6,10 @@ ifeq ($(ARCH),x86_64)
 ARCH := x86
 endif
 
+ifeq ($(ARCH),x86)
+OBJTOOL_ORC := y
+endif
+
 # always use the host compiler
 HOSTAR	?= ar
 HOSTCC	?= gcc
@@ -42,8 +46,12 @@ LDFLAGS  += $(LIBELF_LIBS) $(LIBSUBCMD) $(KBUILD_HOSTLDFLAGS)
 elfshdr := $(shell echo '$(pound)include <libelf.h>' | $(CC) $(CFLAGS) -x c -E - | grep elf_getshdr)
 CFLAGS += $(if $(elfshdr),,-DLIBELF_USE_DEPRECATED)
 
+ifeq ($(OBJTOOL_ORC),y)
+CFLAGS	+= -DOBJTOOL_ORC
+endif
+
 AWK = awk
-export srctree OUTPUT CFLAGS SRCARCH AWK
+export srctree OUTPUT CFLAGS SRCARCH AWK OBJTOOL_ORC
 include $(srctree)/tools/build/Makefile.include
 
 $(OBJTOOL_IN): fixdep FORCE
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 2c5ccf61510a..8f2ff030936d 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -1317,6 +1317,7 @@ static bool has_valid_stack_frame(struct insn_state *state)
 	return false;
 }
 
+#ifdef OBJTOOL_ORC
 static int update_insn_state_regs(struct instruction *insn, struct insn_state *state)
 {
 	struct cfi_reg *cfa = &state->cfa;
@@ -1340,6 +1341,7 @@ static int update_insn_state_regs(struct instruction *insn, struct insn_state *s
 
 	return 0;
 }
+#endif
 
 static void save_reg(struct insn_state *state, unsigned char reg, int base,
 		     int offset)
@@ -1425,8 +1427,10 @@ static int update_insn_state(struct instruction *insn, struct insn_state *state)
 		return 0;
 	}
 
+#ifdef OBJTOOL_ORC
 	if (state->type == ORC_TYPE_REGS || state->type == ORC_TYPE_REGS_IRET)
 		return update_insn_state_regs(insn, state);
+#endif
 
 	switch (op->dest.type) {
 
diff --git a/tools/objtool/objtool.c b/tools/objtool/objtool.c
index 0b3528f05053..8db7139b72cd 100644
--- a/tools/objtool/objtool.c
+++ b/tools/objtool/objtool.c
@@ -34,7 +34,9 @@ static const char objtool_usage_string[] =
 
 static struct cmd_struct objtool_cmds[] = {
 	{"check",	cmd_check,	"Perform stack metadata validation on an object file" },
+#ifdef OBJTOOL_ORC
 	{"orc",		cmd_orc,	"Generate in-place ORC unwind tables for an object file" },
+#endif
 };
 
 bool help;
diff --git a/tools/objtool/orc.h b/tools/objtool/orc.h
index ffda072cf4ad..f5303b8264e3 100644
--- a/tools/objtool/orc.h
+++ b/tools/objtool/orc.h
@@ -6,14 +6,43 @@
 #ifndef _ORC_H
 #define _ORC_H
 
-#include <asm/orc_types.h>
-
 struct objtool_file;
 
+#ifdef OBJTOOL_ORC
+
+#include <asm/orc_types.h>
+
 int arch_orc_init(struct objtool_file *file);
 int arch_orc_create_sections(struct objtool_file *file);
 int arch_orc_read_unwind_hints(struct objtool_file *file);
 
 int orc_dump(const char *objname);
 
+#else
+
+struct orc_entry {
+};
+
+static inline int arch_orc_init(struct objtool_file *file)
+{
+	return 0;
+}
+
+static inline int arch_orc_create_sections(struct objtool_file *file)
+{
+	return 0;
+}
+
+static inline int arch_orc_read_unwind_hints(struct objtool_file *file)
+{
+	return 0;
+}
+
+static inline int orc_dump(const char *objname)
+{
+	return 0;
+}
+
+#endif /* OBJTOOL_ORC */
+
 #endif /* _ORC_H */
-- 
2.21.0


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

* [RFC v5 09/57] objtool: Move registers and control flow to arch-dependent code
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (7 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 08/57] objtool: Make ORC support optional Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 10/57] objtool: Split generic and arch specific CFI definitions Julien Thierry
                   ` (50 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

From: Raphael Gault <raphael.gault@arm.com>

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 <raphael.gault@arm.com>
[J.T. : Added objtool arch specific include to build flags,
        Use SPDX identifier for new header]
Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/Makefile                        |  3 ++-
 tools/objtool/arch/x86/include/arch_special.h | 23 +++++++++++++++++++
 tools/objtool/{ => arch/x86/include}/cfi.h    |  0
 tools/objtool/check.h                         |  1 +
 tools/objtool/special.c                       | 19 +--------------
 5 files changed, 27 insertions(+), 19 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/Makefile b/tools/objtool/Makefile
index 24d653e0b6ec..be735e4f27f5 100644
--- a/tools/objtool/Makefile
+++ b/tools/objtool/Makefile
@@ -37,7 +37,8 @@ all: $(OBJTOOL)
 
 INCLUDES := -I$(srctree)/tools/include \
 	    -I$(srctree)/tools/arch/$(HOSTARCH)/include/uapi \
-	    -I$(srctree)/tools/arch/$(ARCH)/include
+	    -I$(srctree)/tools/arch/$(ARCH)/include \
+	    -I$(srctree)/tools/objtool/arch/$(ARCH)/include
 WARNINGS := $(EXTRA_WARNINGS) -Wno-switch-default -Wno-switch-enum -Wno-packed
 CFLAGS   := -Werror $(WARNINGS) $(KBUILD_HOSTCFLAGS) -g $(INCLUDES) $(LIBELF_FLAGS)
 LDFLAGS  += $(LIBELF_LIBS) $(LIBSUBCMD) $(KBUILD_HOSTLDFLAGS)
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..426178d504a8
--- /dev/null
+++ b/tools/objtool/arch/x86/include/arch_special.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#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 6d875ca6fce0..af87b55db454 100644
--- a/tools/objtool/check.h
+++ b/tools/objtool/check.h
@@ -11,6 +11,7 @@
 #include "cfi.h"
 #include "arch.h"
 #include "orc.h"
+#include "arch_special.h"
 #include <linux/hashtable.h>
 
 struct insn_state {
diff --git a/tools/objtool/special.c b/tools/objtool/special.c
index fdbaa611146d..b8ccee1b5382 100644
--- a/tools/objtool/special.c
+++ b/tools/objtool/special.c
@@ -14,24 +14,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;
-- 
2.21.0


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

* [RFC v5 10/57] objtool: Split generic and arch specific CFI definitions
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (8 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 09/57] objtool: Move registers and control flow to arch-dependent code Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 11/57] objtool: Abstract alternative special case handling Julien Thierry
                   ` (49 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

Some CFI definitions used by generic objtool code have no reason to vary
from one architecture to another. Move those definition to generic code
and keep a separate per arch header to provide architecture specific CFI
definitions.

Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/arch/x86/include/cfi_regs.h  | 25 ++++++++++++++++++++++
 tools/objtool/{arch/x86/include => }/cfi.h | 21 ++----------------
 2 files changed, 27 insertions(+), 19 deletions(-)
 create mode 100644 tools/objtool/arch/x86/include/cfi_regs.h
 rename tools/objtool/{arch/x86/include => }/cfi.h (54%)

diff --git a/tools/objtool/arch/x86/include/cfi_regs.h b/tools/objtool/arch/x86/include/cfi_regs.h
new file mode 100644
index 000000000000..79bc517efba8
--- /dev/null
+++ b/tools/objtool/arch/x86/include/cfi_regs.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef _OBJTOOL_CFI_REGS_H
+#define _OBJTOOL_CFI_REGS_H
+
+#define CFI_AX			0
+#define CFI_DX			1
+#define CFI_CX			2
+#define CFI_BX			3
+#define CFI_SI			4
+#define CFI_DI			5
+#define CFI_BP			6
+#define CFI_SP			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_RA			16
+#define CFI_NUM_REGS		17
+
+#endif /* _OBJTOOL_CFI_REGS_H */
diff --git a/tools/objtool/arch/x86/include/cfi.h b/tools/objtool/cfi.h
similarity index 54%
rename from tools/objtool/arch/x86/include/cfi.h
rename to tools/objtool/cfi.h
index 4427bf8ed686..1a3e7b807994 100644
--- a/tools/objtool/arch/x86/include/cfi.h
+++ b/tools/objtool/cfi.h
@@ -6,30 +6,13 @@
 #ifndef _OBJTOOL_CFI_H
 #define _OBJTOOL_CFI_H
 
+#include "cfi_regs.h"
+
 #define CFI_UNDEFINED		-1
 #define CFI_CFA			-2
 #define CFI_SP_INDIRECT		-3
 #define CFI_BP_INDIRECT		-4
 
-#define CFI_AX			0
-#define CFI_DX			1
-#define CFI_CX			2
-#define CFI_BX			3
-#define CFI_SI			4
-#define CFI_DI			5
-#define CFI_BP			6
-#define CFI_SP			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_RA			16
-#define CFI_NUM_REGS		17
-
 struct cfi_reg {
 	int base;
 	int offset;
-- 
2.21.0


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

* [RFC v5 11/57] objtool: Abstract alternative special case handling
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (9 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 10/57] objtool: Split generic and arch specific CFI definitions Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-20 14:54   ` Peter Zijlstra
  2020-01-09 16:02 ` [RFC v5 12/57] objtool: check: Allow jumps from an alternative group to itself Julien Thierry
                   ` (48 subsequent siblings)
  59 siblings, 1 reply; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

Some alternatives associated with a specific feature need to be treated
in a special way. Since the features and how to treat them vary from one
architecture to another, move the special case handling to arch specific
code.

Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/arch/x86/Build                  |  1 +
 tools/objtool/arch/x86/arch_special.c         | 34 +++++++++++++++++++
 tools/objtool/arch/x86/include/arch_special.h |  5 +++
 tools/objtool/special.c                       | 25 +-------------
 tools/objtool/special.h                       |  8 +++++
 5 files changed, 49 insertions(+), 24 deletions(-)
 create mode 100644 tools/objtool/arch/x86/arch_special.c

diff --git a/tools/objtool/arch/x86/Build b/tools/objtool/arch/x86/Build
index e43fd6fa0ee1..971f9fa90a3c 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/arch_special.c b/tools/objtool/arch/x86/arch_special.c
new file mode 100644
index 000000000000..6dba31f419d0
--- /dev/null
+++ b/tools/objtool/arch/x86/arch_special.c
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include "../../special.h"
+#include "../../builtin.h"
+
+void arch_handle_alternative(unsigned short feature, struct special_alt *alt)
+{
+	/*
+	 * If UACCESS validation is enabled; force that alternative;
+	 * otherwise force it the other way.
+	 *
+	 * What we want to avoid is having both the original and the
+	 * alternative code flow at the same time, in that case we can
+	 * find paths that see the STAC but take the NOP instead of
+	 * CLAC and the other way around.
+	 */
+	switch (feature) {
+	case X86_FEATURE_SMAP:
+		if (uaccess)
+			alt->skip_orig = true;
+		else
+			alt->skip_alt = true;
+		break;
+	case X86_FEATURE_POPCNT:
+		/*
+		 * It has been requested that we don't validate the !POPCNT
+		 * feature path which is a "very very small percentage of
+		 * machines".
+		 */
+		alt->skip_orig = true;
+		break;
+	default:
+		break;
+	}
+}
diff --git a/tools/objtool/arch/x86/include/arch_special.h b/tools/objtool/arch/x86/include/arch_special.h
index 426178d504a8..3ab2dc32424b 100644
--- a/tools/objtool/arch/x86/include/arch_special.h
+++ b/tools/objtool/arch/x86/include/arch_special.h
@@ -20,4 +20,9 @@
 #define X86_FEATURE_POPCNT (4 * 32 + 23)
 #define X86_FEATURE_SMAP   (9 * 32 + 20)
 
+struct special_alt;
+
+#define arch_handle_alternative arch_handle_alternative
+void arch_handle_alternative(unsigned short feature, struct special_alt *alt);
+
 #endif /* _X86_ARCH_SPECIAL_H */
diff --git a/tools/objtool/special.c b/tools/objtool/special.c
index b8ccee1b5382..67461b25e649 100644
--- a/tools/objtool/special.c
+++ b/tools/objtool/special.c
@@ -75,30 +75,7 @@ static int get_alt_entry(struct elf *elf, struct special_entry *entry,
 
 		feature = *(unsigned short *)(sec->data->d_buf + offset +
 					      entry->feature);
-
-		/*
-		 * It has been requested that we don't validate the !POPCNT
-		 * feature path which is a "very very small percentage of
-		 * machines".
-		 */
-		if (feature == X86_FEATURE_POPCNT)
-			alt->skip_orig = true;
-
-		/*
-		 * If UACCESS validation is enabled; force that alternative;
-		 * otherwise force it the other way.
-		 *
-		 * What we want to avoid is having both the original and the
-		 * alternative code flow at the same time, in that case we can
-		 * 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_handle_alternative(feature, alt);
 	}
 
 	orig_rela = find_rela_by_dest(sec, offset + entry->orig);
diff --git a/tools/objtool/special.h b/tools/objtool/special.h
index 35061530e46e..738a05bc6d3a 100644
--- a/tools/objtool/special.h
+++ b/tools/objtool/special.h
@@ -8,6 +8,7 @@
 
 #include <stdbool.h>
 #include "elf.h"
+#include "arch_special.h"
 
 struct special_alt {
 	struct list_head list;
@@ -28,4 +29,11 @@ struct special_alt {
 
 int special_get_alts(struct elf *elf, struct list_head *alts);
 
+#ifndef arch_handle_alternative
+static inline void arch_handle_alternative(unsigned short feature,
+					   struct special_alt *alt)
+{
+}
+#endif
+
 #endif /* _SPECIAL_H */
-- 
2.21.0


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

* [RFC v5 12/57] objtool: check: Allow jumps from an alternative group to itself
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (10 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 11/57] objtool: Abstract alternative special case handling Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-20 14:56   ` Peter Zijlstra
  2020-01-21 17:33   ` Josh Poimboeuf
  2020-01-09 16:02 ` [RFC v5 13/57] objtool: Refactor switch-tables code to support other architectures Julien Thierry
                   ` (47 subsequent siblings)
  59 siblings, 2 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

Alternatives can contain instructions that jump to another instruction
in the same alternative group. This is actually a common pattern on
arm64.

Keep track of instructions jumping within their own alternative group
and carry on validating such branches.

Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/check.c | 48 ++++++++++++++++++++++++++++++++++---------
 tools/objtool/check.h |  1 +
 2 files changed, 39 insertions(+), 10 deletions(-)

diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 8f2ff030936d..c7b3f1e2a628 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -722,6 +722,14 @@ static int handle_group_alt(struct objtool_file *file,
 	sec_for_each_insn_from(file, insn) {
 		if (insn->offset >= special_alt->orig_off + special_alt->orig_len)
 			break;
+		/* Is insn a jump to an instruction within the alt_group */
+		if (insn->jump_dest && insn->sec == insn->jump_dest->sec &&
+		    (insn->type == INSN_JUMP_CONDITIONAL ||
+		     insn->type == INSN_JUMP_UNCONDITIONAL)) {
+			dest_off = insn->jump_dest->offset;
+			insn->intra_group_jump = special_alt->orig_off <= dest_off &&
+				dest_off < special_alt->orig_off + special_alt->orig_len;
+		}
 
 		insn->alt_group = true;
 		last_orig_insn = insn;
@@ -1853,14 +1861,33 @@ static int validate_sibling_call(struct instruction *insn, struct insn_state *st
 	return validate_call(insn, state);
 }
 
+static int validate_branch_alt_safe(struct objtool_file *file,
+				    struct symbol *func,
+				    struct instruction *first,
+				    struct insn_state state);
+
+static int validate_branch(struct objtool_file *file, struct symbol *func,
+			   struct instruction *first, struct insn_state state)
+{
+	if (first->alt_group && list_empty(&first->alts)) {
+		WARN_FUNC("don't know how to handle branch to middle of alternative instruction group",
+			  first->sec, first->offset);
+		return 1;
+	}
+
+	return validate_branch_alt_safe(file, func, first, state);
+}
+
 /*
  * Follow the branch starting at the given instruction, and recursively follow
  * any other branches (jumps).  Meanwhile, track the frame pointer state at
  * each instruction and validate all the rules described in
  * tools/objtool/Documentation/stack-validation.txt.
  */
-static int validate_branch(struct objtool_file *file, struct symbol *func,
-			   struct instruction *first, struct insn_state state)
+static int validate_branch_alt_safe(struct objtool_file *file,
+				    struct symbol *func,
+				    struct instruction *first,
+				    struct insn_state state)
 {
 	struct alternative *alt;
 	struct instruction *insn, *next_insn;
@@ -1871,12 +1898,6 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
 	insn = first;
 	sec = insn->sec;
 
-	if (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;
-	}
-
 	while (1) {
 		next_insn = next_insn_same_sec(file, insn);
 
@@ -2023,8 +2044,15 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
 					return ret;
 
 			} else if (insn->jump_dest) {
-				ret = validate_branch(file, func,
-						      insn->jump_dest, state);
+				if (insn->intra_group_jump)
+					ret = validate_branch_alt_safe(file,
+								       func,
+								       insn->jump_dest,
+								       state);
+				else
+					ret = validate_branch(file, func,
+							      insn->jump_dest,
+							      state);
 				if (ret) {
 					if (backtrace)
 						BT_FUNC("(branch)", insn);
diff --git a/tools/objtool/check.h b/tools/objtool/check.h
index af87b55db454..d13ee02f28a4 100644
--- a/tools/objtool/check.h
+++ b/tools/objtool/check.h
@@ -46,6 +46,7 @@ struct instruction {
 	struct stack_op stack_op;
 	struct insn_state state;
 	struct orc_entry orc;
+	bool intra_group_jump;
 };
 
 struct objtool_file {
-- 
2.21.0


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

* [RFC v5 13/57] objtool: Refactor switch-tables code to support other architectures
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (11 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 12/57] objtool: check: Allow jumps from an alternative group to itself Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 14/57] objtool: Do not look for STT_NOTYPE symbols Julien Thierry
                   ` (46 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

From: Raphael Gault <raphael.gault@arm.com>

The way to identify switch-tables and retrieves all the data necessary
to handle the different execution branches is not the same on all
architecture. In order to be able to add other architecture support,
this patch defines arch-dependent functions to process jump-tables.

Signed-off-by: Raphael Gault <raphael.gault@arm.com>
[J.T.: Move arm64 bits out of this patch,
       rename arch_add_jump_table to arch_add_jump_table_dests,
       remove redundant/unused arguments]
Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/arch/x86/arch_special.c | 148 ++++++++++++++++++++++++++
 tools/objtool/check.c                 | 148 +-------------------------
 tools/objtool/check.h                 |   7 ++
 tools/objtool/special.h               |   5 +
 4 files changed, 164 insertions(+), 144 deletions(-)

diff --git a/tools/objtool/arch/x86/arch_special.c b/tools/objtool/arch/x86/arch_special.c
index 6dba31f419d0..9e382155298b 100644
--- a/tools/objtool/arch/x86/arch_special.c
+++ b/tools/objtool/arch/x86/arch_special.c
@@ -1,6 +1,9 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
+#include <stdlib.h>
+
 #include "../../special.h"
 #include "../../builtin.h"
+#include "../../warn.h"
 
 void arch_handle_alternative(unsigned short feature, struct special_alt *alt)
 {
@@ -32,3 +35,148 @@ void arch_handle_alternative(unsigned short feature, struct special_alt *alt)
 		break;
 	}
 }
+
+int arch_add_jump_table_dests(struct objtool_file *file,
+			      struct instruction *insn)
+{
+	struct rela *table = insn->jump_table;
+	struct rela *rela = table;
+	struct instruction *dest_insn;
+	struct alternative *alt;
+	struct symbol *pfunc = insn->func->pfunc;
+	unsigned int prev_offset = 0;
+
+	/*
+	 * Each @rela is a switch table relocation which points to the target
+	 * instruction.
+	 */
+	list_for_each_entry_from(rela, &table->sec->rela_list, list) {
+
+		/* Check for the end of the table: */
+		if (rela != table && rela->jump_table_start)
+			break;
+
+		/* Make sure the table entries are consecutive: */
+		if (prev_offset && rela->offset != prev_offset + 8)
+			break;
+
+		/* Detect function pointers from contiguous objects: */
+		if (rela->sym->sec == pfunc->sec &&
+		    rela->addend == pfunc->offset)
+			break;
+
+		dest_insn = find_insn(file, rela->sym->sec, rela->addend);
+		if (!dest_insn)
+			break;
+
+		/* Make sure the destination is in the same function: */
+		if (!dest_insn->func || dest_insn->func->pfunc != pfunc)
+			break;
+
+		alt = malloc(sizeof(*alt));
+		if (!alt) {
+			WARN("malloc failed");
+			return -1;
+		}
+
+		alt->insn = dest_insn;
+		list_add_tail(&alt->list, &insn->alts);
+		prev_offset = rela->offset;
+	}
+
+	if (!prev_offset) {
+		WARN_FUNC("can't find switch jump table",
+			  insn->sec, insn->offset);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * There are 3 basic jump table patterns:
+ *
+ * 1. jmpq *[rodata addr](,%reg,8)
+ *
+ *    This is the most common case by far.  It jumps to an address in a simple
+ *    jump table which is stored in .rodata.
+ *
+ * 2. jmpq *[rodata addr](%rip)
+ *
+ *    This is caused by a rare GCC quirk, currently only seen in three driver
+ *    functions in the kernel, only with certain obscure non-distro configs.
+ *
+ *    As part of an optimization, GCC makes a copy of an existing switch jump
+ *    table, modifies it, and then hard-codes the jump (albeit with an indirect
+ *    jump) to use a single entry in the table.  The rest of the jump table and
+ *    some of its jump targets remain as dead code.
+ *
+ *    In such a case we can just crudely ignore all unreachable instruction
+ *    warnings for the entire object file.  Ideally we would just ignore them
+ *    for the function, but that would require redesigning the code quite a
+ *    bit.  And honestly that's just not worth doing: unreachable instruction
+ *    warnings are of questionable value anyway, and this is such a rare issue.
+ *
+ * 3. mov [rodata addr],%reg1
+ *    ... some instructions ...
+ *    jmpq *(%reg1,%reg2,8)
+ *
+ *    This is a fairly uncommon pattern which is new for GCC 6.  As of this
+ *    writing, there are 11 occurrences of it in the allmodconfig kernel.
+ *
+ *    As of GCC 7 there are quite a few more of these and the 'in between' code
+ *    is significant. Esp. with KASAN enabled some of the code between the mov
+ *    and jmpq uses .rodata itself, which can confuse things.
+ *
+ *    TODO: Once we have DWARF CFI and smarter instruction decoding logic,
+ *    ensure the same register is used in the mov and jump instructions.
+ *
+ *    NOTE: RETPOLINE made it harder still to decode dynamic jumps.
+ */
+struct rela *arch_find_switch_table(struct objtool_file *file,
+				    struct instruction *insn)
+{
+	struct rela *text_rela, *rodata_rela;
+	struct section *table_sec;
+	unsigned long table_offset;
+
+	/* look for a relocation which references .rodata */
+	text_rela = find_rela_by_dest_range(insn->sec, insn->offset,
+					    insn->len);
+	if (!text_rela || text_rela->sym->type != STT_SECTION ||
+	    !text_rela->sym->sec->rodata)
+		return NULL;
+	table_offset = text_rela->addend;
+	table_sec = text_rela->sym->sec;
+
+	if (text_rela->type == R_X86_64_PC32)
+		table_offset += 4;
+
+	/*
+	 * Make sure the .rodata address isn't associated with a
+	 * symbol.  GCC jump tables are anonymous data.
+	 *
+	 * Also support C jump tables which are in the same format as
+	 * switch jump tables.  For objtool to recognize them, they
+	 * need to be placed in the C_JUMP_TABLE_SECTION section.  They
+	 * have symbols associated with them.
+	 */
+	if (find_symbol_containing(table_sec, table_offset) &&
+	    strcmp(table_sec->name, C_JUMP_TABLE_SECTION))
+		return NULL;
+
+	rodata_rela = find_rela_by_dest(table_sec, table_offset);
+	if (rodata_rela) {
+		/*
+		 * Use of RIP-relative switch jumps is quite rare, and
+		 * indicates a rare GCC quirk/bug which can leave dead
+		 * code behind.
+		 */
+		if (text_rela->type == R_X86_64_PC32)
+			file->ignore_unreachables = true;
+
+		return rodata_rela;
+	}
+
+	return NULL;
+}
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index c7b3f1e2a628..19e96c4ad0a3 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -18,14 +18,6 @@
 
 #define FAKE_JUMP_OFFSET -1
 
-#define C_JUMP_TABLE_SECTION ".rodata..c_jump_table"
-
-struct alternative {
-	struct list_head list;
-	struct instruction *insn;
-	bool skip_orig;
-};
-
 const char *objname;
 struct cfi_state initial_func_cfi;
 
@@ -914,113 +906,16 @@ static int add_special_section_alts(struct objtool_file *file)
 	return ret;
 }
 
-static int add_jump_table(struct objtool_file *file, struct instruction *insn,
-			    struct rela *table)
-{
-	struct rela *rela = table;
-	struct instruction *dest_insn;
-	struct alternative *alt;
-	struct symbol *pfunc = insn->func->pfunc;
-	unsigned int prev_offset = 0;
-
-	/*
-	 * Each @rela is a switch table relocation which points to the target
-	 * instruction.
-	 */
-	list_for_each_entry_from(rela, &table->sec->rela_list, list) {
-
-		/* Check for the end of the table: */
-		if (rela != table && rela->jump_table_start)
-			break;
-
-		/* Make sure the table entries are consecutive: */
-		if (prev_offset && rela->offset != prev_offset + 8)
-			break;
-
-		/* Detect function pointers from contiguous objects: */
-		if (rela->sym->sec == pfunc->sec &&
-		    rela->addend == pfunc->offset)
-			break;
-
-		dest_insn = find_insn(file, rela->sym->sec, rela->addend);
-		if (!dest_insn)
-			break;
-
-		/* Make sure the destination is in the same function: */
-		if (!dest_insn->func || dest_insn->func->pfunc != pfunc)
-			break;
-
-		alt = malloc(sizeof(*alt));
-		if (!alt) {
-			WARN("malloc failed");
-			return -1;
-		}
-
-		alt->insn = dest_insn;
-		list_add_tail(&alt->list, &insn->alts);
-		prev_offset = rela->offset;
-	}
-
-	if (!prev_offset) {
-		WARN_FUNC("can't find switch jump table",
-			  insn->sec, insn->offset);
-		return -1;
-	}
-
-	return 0;
-}
-
 /*
  * find_jump_table() - Given a dynamic jump, find the switch jump table in
- * .rodata associated with it.
- *
- * There are 3 basic patterns:
- *
- * 1. jmpq *[rodata addr](,%reg,8)
- *
- *    This is the most common case by far.  It jumps to an address in a simple
- *    jump table which is stored in .rodata.
- *
- * 2. jmpq *[rodata addr](%rip)
- *
- *    This is caused by a rare GCC quirk, currently only seen in three driver
- *    functions in the kernel, only with certain obscure non-distro configs.
- *
- *    As part of an optimization, GCC makes a copy of an existing switch jump
- *    table, modifies it, and then hard-codes the jump (albeit with an indirect
- *    jump) to use a single entry in the table.  The rest of the jump table and
- *    some of its jump targets remain as dead code.
- *
- *    In such a case we can just crudely ignore all unreachable instruction
- *    warnings for the entire object file.  Ideally we would just ignore them
- *    for the function, but that would require redesigning the code quite a
- *    bit.  And honestly that's just not worth doing: unreachable instruction
- *    warnings are of questionable value anyway, and this is such a rare issue.
- *
- * 3. mov [rodata addr],%reg1
- *    ... some instructions ...
- *    jmpq *(%reg1,%reg2,8)
- *
- *    This is a fairly uncommon pattern which is new for GCC 6.  As of this
- *    writing, there are 11 occurrences of it in the allmodconfig kernel.
- *
- *    As of GCC 7 there are quite a few more of these and the 'in between' code
- *    is significant. Esp. with KASAN enabled some of the code between the mov
- *    and jmpq uses .rodata itself, which can confuse things.
- *
- *    TODO: Once we have DWARF CFI and smarter instruction decoding logic,
- *    ensure the same register is used in the mov and jump instructions.
- *
- *    NOTE: RETPOLINE made it harder still to decode dynamic jumps.
+ * associated with it.
  */
 static struct rela *find_jump_table(struct objtool_file *file,
 				      struct symbol *func,
 				      struct instruction *insn)
 {
-	struct rela *text_rela, *table_rela;
+	struct rela *table_rela;
 	struct instruction *orig_insn = insn;
-	struct section *table_sec;
-	unsigned long table_offset;
 
 	/*
 	 * Backward search using the @first_jump_src links, these help avoid
@@ -1044,45 +939,10 @@ static struct rela *find_jump_table(struct objtool_file *file,
 		     insn->jump_dest->offset > orig_insn->offset))
 		    break;
 
-		/* look for a relocation which references .rodata */
-		text_rela = find_rela_by_dest_range(insn->sec, insn->offset,
-						    insn->len);
-		if (!text_rela || text_rela->sym->type != STT_SECTION ||
-		    !text_rela->sym->sec->rodata)
-			continue;
-
-		table_offset = text_rela->addend;
-		table_sec = text_rela->sym->sec;
-
-		if (text_rela->type == R_X86_64_PC32)
-			table_offset += 4;
-
-		/*
-		 * Make sure the .rodata address isn't associated with a
-		 * symbol.  GCC jump tables are anonymous data.
-		 *
-		 * Also support C jump tables which are in the same format as
-		 * switch jump tables.  For objtool to recognize them, they
-		 * need to be placed in the C_JUMP_TABLE_SECTION section.  They
-		 * have symbols associated with them.
-		 */
-		if (find_symbol_containing(table_sec, table_offset) &&
-		    strcmp(table_sec->name, C_JUMP_TABLE_SECTION))
-			continue;
-
-		/* Each table entry has a rela associated with it. */
-		table_rela = find_rela_by_dest(table_sec, table_offset);
+		table_rela = arch_find_switch_table(file, insn);
 		if (!table_rela)
 			continue;
 
-		/*
-		 * Use of RIP-relative switch jumps is quite rare, and
-		 * indicates a rare GCC quirk/bug which can leave dead code
-		 * behind.
-		 */
-		if (text_rela->type == R_X86_64_PC32)
-			file->ignore_unreachables = true;
-
 		return table_rela;
 	}
 
@@ -1138,7 +998,7 @@ static int add_func_jump_tables(struct objtool_file *file,
 		if (!insn->jump_table)
 			continue;
 
-		ret = add_jump_table(file, insn, insn->jump_table);
+		ret = arch_add_jump_table_dests(file, insn);
 		if (ret)
 			return ret;
 	}
diff --git a/tools/objtool/check.h b/tools/objtool/check.h
index d13ee02f28a4..843094cbae87 100644
--- a/tools/objtool/check.h
+++ b/tools/objtool/check.h
@@ -49,6 +49,12 @@ struct instruction {
 	bool intra_group_jump;
 };
 
+struct alternative {
+	struct list_head list;
+	struct instruction *insn;
+	bool skip_orig;
+};
+
 struct objtool_file {
 	struct elf *elf;
 	struct list_head insn_list;
@@ -70,5 +76,6 @@ struct instruction *find_insn(struct objtool_file *file,
 			insn->sec == sec;				\
 	     insn = list_next_entry(insn, list))
 
+#define C_JUMP_TABLE_SECTION ".rodata..c_jump_table"
 
 #endif /* _CHECK_H */
diff --git a/tools/objtool/special.h b/tools/objtool/special.h
index 738a05bc6d3a..7f258d87e9f8 100644
--- a/tools/objtool/special.h
+++ b/tools/objtool/special.h
@@ -7,6 +7,7 @@
 #define _SPECIAL_H
 
 #include <stdbool.h>
+#include "check.h"
 #include "elf.h"
 #include "arch_special.h"
 
@@ -36,4 +37,8 @@ static inline void arch_handle_alternative(unsigned short feature,
 }
 #endif
 
+int arch_add_jump_table_dests(struct objtool_file *file,
+			      struct instruction *insn);
+struct rela *arch_find_switch_table(struct objtool_file *file,
+				    struct instruction *insn);
 #endif /* _SPECIAL_H */
-- 
2.21.0


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

* [RFC v5 14/57] objtool: Do not look for STT_NOTYPE symbols
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (12 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 13/57] objtool: Refactor switch-tables code to support other architectures Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-13 10:20   ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 15/57] objtool: Support addition to set frame pointer Julien Thierry
                   ` (45 subsequent siblings)
  59 siblings, 1 reply; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

ELF symbols can have type STT_NOTYPE which have no standard semantics.

Arm64 objects will contain STT_NOTYPE symbols at the beginning of each
section which aren't of any use to generic objtool code. Those symbols
unfortunately overlap with the first function of the section.

Skip symbols with type STT_NOTYPE when looking up symbols.

Suggested-by: Raphael Gault <raphael.gault@arm.com>
Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/elf.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
index edba4745f25a..c6ac0b771b73 100644
--- a/tools/objtool/elf.c
+++ b/tools/objtool/elf.c
@@ -62,7 +62,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;
 
-- 
2.21.0


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

* [RFC v5 15/57] objtool: Support addition to set frame pointer
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (13 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 14/57] objtool: Do not look for STT_NOTYPE symbols Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 16/57] objtool: Support restoring BP from the stack without POP Julien Thierry
                   ` (44 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

Support updating the frame pointer by adding an immediate value to the
stack pointer in the CFA tracking code.

Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/check.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 19e96c4ad0a3..5b2539eaccba 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -1394,6 +1394,18 @@ static int update_insn_state(struct instruction *insn, struct insn_state *state)
 				break;
 			}
 
+			if (op->src.reg == CFI_SP && cfa->base == CFI_SP &&
+			    op->dest.reg == CFI_BP &&
+			    regs[CFI_BP].base == CFI_CFA &&
+			    regs[CFI_BP].offset == -cfa->offset + op->src.offset) {
+
+				/* lea disp(%rsp), %rbp */
+				cfa->base = CFI_BP;
+				cfa->offset -= op->src.offset;
+				state->bp_scratch = false;
+				break;
+			}
+
 			if (op->src.reg == CFI_SP && cfa->base == CFI_SP) {
 
 				/* drap: lea disp(%rsp), %drap */
-- 
2.21.0


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

* [RFC v5 16/57] objtool: Support restoring BP from the stack without POP
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (14 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 15/57] objtool: Support addition to set frame pointer Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 17/57] objtool: Make stack validation more generic Julien Thierry
                   ` (43 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

Support instruction that set BP to its previous value (base on the
current CFA state) from the stack without modifying the stack pointer.

Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/check.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 5b2539eaccba..0a5c51e4e24c 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -1507,6 +1507,12 @@ static int update_insn_state(struct instruction *insn, struct insn_state *state)
 				cfa->base = state->drap_reg;
 				cfa->offset = 0;
 				state->drap_offset = -1;
+			} else if (!state->drap && op->src.reg == CFI_SP &&
+				op->dest.reg == cfa->base) {
+
+				/* mov disp(%rsp), %rbp */
+				cfa->base = CFI_SP;
+				cfa->offset += op->src.offset;
 			}
 
 			if (state->drap && op->src.reg == CFI_BP &&
-- 
2.21.0


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

* [RFC v5 17/57] objtool: Make stack validation more generic
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (15 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 16/57] objtool: Support restoring BP from the stack without POP Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 18/57] objtool: Support multiple stack_op per instruction Julien Thierry
                   ` (42 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

On x86, when calling a function, the new call frame is alway placed at
the start of the stack space this function can freely use. So the frame
pointer is always saved at <function stack start> - 16.

This is not true for the calling convention of all architecture.

When validating the call frame before a call instruction, all that can
be done is check that a frame was created by the current function and
that the frame pointer is correctly pointing to it.

Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/check.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 0a5c51e4e24c..04434cdbdab6 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -1176,7 +1176,7 @@ static bool has_modified_stack_frame(struct insn_state *state)
 static bool has_valid_stack_frame(struct insn_state *state)
 {
 	if (state->cfa.base == CFI_BP && state->regs[CFI_BP].base == CFI_CFA &&
-	    state->regs[CFI_BP].offset == -16)
+	    state->regs[CFI_BP].offset == -state->cfa.offset)
 		return true;
 
 	if (state->drap && state->regs[CFI_BP].base == CFI_BP)
-- 
2.21.0


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

* [RFC v5 18/57] objtool: Support multiple stack_op per instruction
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (16 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 17/57] objtool: Make stack validation more generic Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 19/57] objtool: arm64: Add required implementation for supporting the aarch64 architecture in objtool Julien Thierry
                   ` (41 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

Instruction sets can include more or less complex operations which might
not fit the currently defined set of stack_ops.

Combining more than one stack_op provides more flexibility to describe
the behaviour of an instruction. This also reduces the need to define
new stack_ops specific to a single instruction set.

Allow instruction decoders to generate multiple stack_op per
instruction.

Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/arch.h            |  4 +-
 tools/objtool/arch/x86/decode.c | 13 +++++-
 tools/objtool/check.c           | 79 +++++++++++++++++++++------------
 tools/objtool/check.h           |  2 +-
 4 files changed, 67 insertions(+), 31 deletions(-)

diff --git a/tools/objtool/arch.h b/tools/objtool/arch.h
index a9a50a25ca66..f9883c431949 100644
--- a/tools/objtool/arch.h
+++ b/tools/objtool/arch.h
@@ -64,6 +64,7 @@ struct op_src {
 struct stack_op {
 	struct op_dest dest;
 	struct op_src src;
+	struct list_head list;
 };
 
 struct instruction;
@@ -73,7 +74,8 @@ void arch_initial_func_cfi_state(struct cfi_state *state);
 int arch_decode_instruction(struct elf *elf, struct section *sec,
 			    unsigned long offset, unsigned int maxlen,
 			    unsigned int *len, enum insn_type *type,
-			    unsigned long *immediate, struct stack_op *op);
+			    unsigned long *immediate,
+			    struct list_head *ops_list);
 
 bool arch_callee_saved_reg(unsigned char reg);
 
diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c
index 79ff33ffa6e0..650e5d021486 100644
--- a/tools/objtool/arch/x86/decode.c
+++ b/tools/objtool/arch/x86/decode.c
@@ -75,13 +75,15 @@ unsigned long arch_dest_rela_offset(int addend)
 int arch_decode_instruction(struct elf *elf, struct section *sec,
 			    unsigned long offset, unsigned int maxlen,
 			    unsigned int *len, enum insn_type *type,
-			    unsigned long *immediate, struct stack_op *op)
+			    unsigned long *immediate,
+			    struct list_head *ops_list)
 {
 	struct insn insn;
 	int x86_64, sign;
 	unsigned char op1, op2, rex = 0, rex_b = 0, rex_r = 0, rex_w = 0,
 		      rex_x = 0, modrm = 0, modrm_mod = 0, modrm_rm = 0,
 		      modrm_reg = 0, sib = 0;
+	struct stack_op *op;
 
 	x86_64 = is_x86_64(elf);
 	if (x86_64 == -1)
@@ -122,6 +124,10 @@ int arch_decode_instruction(struct elf *elf, struct section *sec,
 	if (insn.sib.nbytes)
 		sib = insn.sib.bytes[0];
 
+	op = calloc(1, sizeof(*op));
+	if (!op)
+		return -1;
+
 	switch (op1) {
 
 	case 0x1:
@@ -483,6 +489,11 @@ int arch_decode_instruction(struct elf *elf, struct section *sec,
 
 	*immediate = insn.immediate.nbytes ? insn.immediate.value : 0;
 
+	if (*type == INSN_STACK)
+		list_add_tail(&op->list, ops_list);
+	else
+		free(op);
+
 	return 0;
 }
 
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 04434cdbdab6..48aec56a7760 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -246,6 +246,7 @@ static int decode_instructions(struct objtool_file *file)
 			}
 			memset(insn, 0, sizeof(*insn));
 			INIT_LIST_HEAD(&insn->alts);
+			INIT_LIST_HEAD(&insn->stack_ops);
 			clear_insn_state(&insn->state);
 
 			insn->sec = sec;
@@ -255,7 +256,7 @@ static int decode_instructions(struct objtool_file *file)
 						      sec->len - offset,
 						      &insn->len, &insn->type,
 						      &insn->immediate,
-						      &insn->stack_op);
+						      &insn->stack_ops);
 			if (ret)
 				goto err;
 
@@ -735,6 +736,7 @@ static int handle_group_alt(struct objtool_file *file,
 		}
 		memset(fake_jump, 0, sizeof(*fake_jump));
 		INIT_LIST_HEAD(&fake_jump->alts);
+		INIT_LIST_HEAD(&fake_jump->stack_ops);
 		clear_insn_state(&fake_jump->state);
 
 		fake_jump->sec = special_alt->new_sec;
@@ -1186,10 +1188,11 @@ static bool has_valid_stack_frame(struct insn_state *state)
 }
 
 #ifdef OBJTOOL_ORC
-static int update_insn_state_regs(struct instruction *insn, struct insn_state *state)
+static int update_insn_state_regs(struct instruction *insn,
+				  struct insn_state *state,
+				  struct stack_op *op)
 {
 	struct cfi_reg *cfa = &state->cfa;
-	struct stack_op *op = &insn->stack_op;
 
 	if (cfa->base != CFI_SP)
 		return 0;
@@ -1280,9 +1283,9 @@ static void restore_reg(struct insn_state *state, unsigned char reg)
  *   41 5d			pop    %r13
  *   c3				retq
  */
-static int update_insn_state(struct instruction *insn, struct insn_state *state)
+static int update_insn_state(struct instruction *insn, struct insn_state *state,
+			     struct stack_op *op)
 {
-	struct stack_op *op = &insn->stack_op;
 	struct cfi_reg *cfa = &state->cfa;
 	struct cfi_reg *regs = state->regs;
 
@@ -1297,7 +1300,7 @@ static int update_insn_state(struct instruction *insn, struct insn_state *state)
 
 #ifdef OBJTOOL_ORC
 	if (state->type == ORC_TYPE_REGS || state->type == ORC_TYPE_REGS_IRET)
-		return update_insn_state_regs(insn, state);
+		return update_insn_state_regs(insn, state, op);
 #endif
 
 	switch (op->dest.type) {
@@ -1653,6 +1656,42 @@ static int update_insn_state(struct instruction *insn, struct insn_state *state)
 	return 0;
 }
 
+static int handle_insn_ops(struct instruction *insn, struct insn_state *state)
+{
+	struct stack_op *op;
+
+	list_for_each_entry(op, &insn->stack_ops, list) {
+		int res;
+
+		res = update_insn_state(insn, state, op);
+		if (res)
+			return res;
+
+		if (op->dest.type == OP_DEST_PUSHF) {
+			if (!state->uaccess_stack) {
+				state->uaccess_stack = 1;
+			} else if (state->uaccess_stack >> 31) {
+				WARN_FUNC("PUSHF stack exhausted",
+					  insn->sec, insn->offset);
+				return 1;
+			}
+			state->uaccess_stack <<= 1;
+			state->uaccess_stack  |= state->uaccess;
+		}
+
+		if (op->src.type == OP_SRC_POPF) {
+			if (state->uaccess_stack) {
+				state->uaccess = state->uaccess_stack & 1;
+				state->uaccess_stack >>= 1;
+				if (state->uaccess_stack == 1)
+					state->uaccess_stack = 0;
+			}
+		}
+	}
+
+	return 0;
+}
+
 static bool insn_state_match(struct instruction *insn, struct insn_state *state)
 {
 	struct insn_state *state1 = &insn->state, *state2 = state;
@@ -1965,29 +2004,8 @@ static int validate_branch_alt_safe(struct objtool_file *file,
 			return 0;
 
 		case INSN_STACK:
-			if (update_insn_state(insn, &state))
+			if (handle_insn_ops(insn, &state))
 				return 1;
-
-			if (insn->stack_op.dest.type == OP_DEST_PUSHF) {
-				if (!state.uaccess_stack) {
-					state.uaccess_stack = 1;
-				} else if (state.uaccess_stack >> 31) {
-					WARN_FUNC("PUSHF stack exhausted", sec, insn->offset);
-					return 1;
-				}
-				state.uaccess_stack <<= 1;
-				state.uaccess_stack  |= state.uaccess;
-			}
-
-			if (insn->stack_op.src.type == OP_SRC_POPF) {
-				if (state.uaccess_stack) {
-					state.uaccess = state.uaccess_stack & 1;
-					state.uaccess_stack >>= 1;
-					if (state.uaccess_stack == 1)
-						state.uaccess_stack = 0;
-				}
-			}
-
 			break;
 
 		case INSN_STAC:
@@ -2232,12 +2250,17 @@ static void cleanup(struct objtool_file *file)
 {
 	struct instruction *insn, *tmpinsn;
 	struct alternative *alt, *tmpalt;
+	struct stack_op *op, *tmpop;
 
 	list_for_each_entry_safe(insn, tmpinsn, &file->insn_list, list) {
 		list_for_each_entry_safe(alt, tmpalt, &insn->alts, list) {
 			list_del(&alt->list);
 			free(alt);
 		}
+		list_for_each_entry_safe(op, tmpop, &insn->stack_ops, list) {
+			list_del(&op->list);
+			free(op);
+		}
 		list_del(&insn->list);
 		hash_del(&insn->hash);
 		free(insn);
diff --git a/tools/objtool/check.h b/tools/objtool/check.h
index 843094cbae87..91adec42782c 100644
--- a/tools/objtool/check.h
+++ b/tools/objtool/check.h
@@ -43,7 +43,7 @@ struct instruction {
 	struct rela *jump_table;
 	struct list_head alts;
 	struct symbol *func;
-	struct stack_op stack_op;
+	struct list_head stack_ops;
 	struct insn_state state;
 	struct orc_entry orc;
 	bool intra_group_jump;
-- 
2.21.0


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

* [RFC v5 19/57] objtool: arm64: Add required implementation for supporting the aarch64 architecture in objtool.
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (17 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 18/57] objtool: Support multiple stack_op per instruction Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 20/57] objtool: arm64: Decode unknown instructions Julien Thierry
                   ` (40 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

From: Raphael Gault <raphael.gault@arm.com>

Provide implementation for the arch-dependent functions that are called by
the main check function of objtool.

Provide an empty squeleton for the aarch64 decoder that shall be
completed in later patches.

Signed-off-by: Raphael Gault <raphael.gault@arm.com>
[J.T.: Use enum for instruction type,
       Remove orc functions,
       Remove x86 feature macros from arm64 header,
       Split decoder over multiple patches,
       Use SPDX identifiers]
Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/arch/arm64/Build                |   5 +
 tools/objtool/arch/arm64/arch_special.c       |  15 +++
 tools/objtool/arch/arm64/bit_operations.c     |  69 ++++++++++
 tools/objtool/arch/arm64/decode.c             | 127 ++++++++++++++++++
 .../objtool/arch/arm64/include/arch_special.h |  21 +++
 .../arch/arm64/include/bit_operations.h       |  31 +++++
 tools/objtool/arch/arm64/include/cfi_regs.h   |  44 ++++++
 .../objtool/arch/arm64/include/insn_decode.h  |  15 +++
 8 files changed, 327 insertions(+)
 create mode 100644 tools/objtool/arch/arm64/Build
 create mode 100644 tools/objtool/arch/arm64/arch_special.c
 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/bit_operations.h
 create mode 100644 tools/objtool/arch/arm64/include/cfi_regs.h
 create mode 100644 tools/objtool/arch/arm64/include/insn_decode.h

diff --git a/tools/objtool/arch/arm64/Build b/tools/objtool/arch/arm64/Build
new file mode 100644
index 000000000000..2a554af43e96
--- /dev/null
+++ b/tools/objtool/arch/arm64/Build
@@ -0,0 +1,5 @@
+objtool-y += arch_special.o
+objtool-y += bit_operations.o
+objtool-y += decode.o
+
+CFLAGS_decode.o += -I$(OUTPUT)arch/arm64/lib
diff --git a/tools/objtool/arch/arm64/arch_special.c b/tools/objtool/arch/arm64/arch_special.c
new file mode 100644
index 000000000000..5239489c9c57
--- /dev/null
+++ b/tools/objtool/arch/arm64/arch_special.c
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "../../special.h"
+
+int arch_add_jump_table_dests(struct objtool_file *file,
+			      struct instruction *insn)
+{
+	return 0;
+}
+
+struct rela *arch_find_switch_table(struct objtool_file *file,
+				    struct instruction *insn)
+{
+	return NULL;
+}
diff --git a/tools/objtool/arch/arm64/bit_operations.c b/tools/objtool/arch/arm64/bit_operations.c
new file mode 100644
index 000000000000..cd44138956bb
--- /dev/null
+++ b/tools/objtool/arch/arm64/bit_operations.c
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <stdio.h>
+#include <stdlib.h>
+#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..4d0ab2acca27
--- /dev/null
+++ b/tools/objtool/arch/arm64/decode.c
@@ -0,0 +1,127 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "insn_decode.h"
+#include "cfi_regs.h"
+#include "bit_operations.h"
+
+#include "../../check.h"
+#include "../../arch.h"
+#include "../../elf.h"
+#include "../../warn.h"
+
+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_SP;
+	state->cfa.offset = 0;
+}
+
+unsigned long arch_dest_rela_offset(int addend)
+{
+	return addend;
+}
+
+unsigned long arch_jump_destination(struct instruction *insn)
+{
+	return insn->offset + insn->immediate;
+}
+
+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;
+	}
+}
+
+/*
+ * static int (*arm_decode_class)(u32 instr,
+ *				 unsigned int *len,
+ *				 enum insn_type *type,
+ *				 unsigned long *immediate,
+ *				 struct list_head *ops_list);
+ */
+static arm_decode_class aarch64_insn_class_decode_table[NR_INSN_CLASS] = {
+	NULL,
+};
+
+/*
+ * 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, enum insn_type *type,
+			    unsigned long *immediate,
+			    struct list_head *ops_list)
+{
+	arm_decode_class decode_fun;
+	int arm64 = 0;
+	u32 insn = 0;
+	int res;
+
+	*len = 4;
+	*immediate = 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
+	decode_fun = aarch64_insn_class_decode_table[INSN_CLASS(insn)];
+	if (decode_fun)
+		res = decode_fun(insn, type, immediate, ops_list);
+	else
+		res = -1;
+
+	if (res)
+		WARN_FUNC("Unsupported instruction", sec, offset);
+	return res;
+}
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..a82a9b3e51df
--- /dev/null
+++ b/tools/objtool/arch/arm64/include/arch_special.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#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
+
+#endif /* _ARM64_ARCH_SPECIAL_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..8554adb0df70
--- /dev/null
+++ b/tools/objtool/arch/arm64/include/bit_operations.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef _BIT_OPERATIONS_H
+#define _BIT_OPERATIONS_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <linux/types.h>
+
+#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)	sign_extend((X), (N))
+
+static inline unsigned long sign_extend(unsigned long x, int nbits)
+{
+	return ((~0UL + (EXTRACT_BIT(x, nbits - 1) ^ 1)) << nbits) | 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_regs.h b/tools/objtool/arch/arm64/include/cfi_regs.h
new file mode 100644
index 000000000000..d48f41e7890b
--- /dev/null
+++ b/tools/objtool/arch/arm64/include/cfi_regs.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef _OBJTOOL_CFI_REGS_H
+#define _OBJTOOL_CFI_REGS_H
+
+#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
+
+#endif /* _OBJTOOL_CFI_REGS_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..c56b72ac4633
--- /dev/null
+++ b/tools/objtool/arch/arm64/include/insn_decode.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef _ARM_INSN_DECODE_H
+#define _ARM_INSN_DECODE_H
+
+#include "../../../arch.h"
+
+#define NR_INSN_CLASS	16
+#define INSN_CLASS(opcode)	(((opcode) >> 25) & (NR_INSN_CLASS - 1))
+
+typedef int (*arm_decode_class)(u32 instr, enum insn_type *type,
+				unsigned long *immediate,
+				struct list_head *ops_list);
+
+#endif /* _ARM_INSN_DECODE_H */
-- 
2.21.0


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

* [RFC v5 20/57] objtool: arm64: Decode unknown instructions
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (18 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 19/57] objtool: arm64: Add required implementation for supporting the aarch64 architecture in objtool Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 21/57] objtool: arm64: Decode simple data processing instructions Julien Thierry
                   ` (39 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

For aarch64, it is possible to have byte sequences that aren't valid
opcodes in the code sections. Do not report an error when the decoder
finds such a sequence, but make sure that those bytes cannot be reached
in the execution flow.

Suggested-by: Raphael Gault <raphael.gault@arm.com>
Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/arch.h                          |  1 +
 tools/objtool/arch/arm64/decode.c             | 22 ++++++++++++++++++-
 .../objtool/arch/arm64/include/insn_decode.h  |  7 ++++++
 tools/objtool/check.c                         | 10 ++++++++-
 4 files changed, 38 insertions(+), 2 deletions(-)

diff --git a/tools/objtool/arch.h b/tools/objtool/arch.h
index f9883c431949..0336efecb9d9 100644
--- a/tools/objtool/arch.h
+++ b/tools/objtool/arch.h
@@ -28,6 +28,7 @@ enum insn_type {
 	INSN_STD,
 	INSN_CLD,
 	INSN_OTHER,
+	INSN_INVALID,
 };
 
 enum op_dest_type {
diff --git a/tools/objtool/arch/arm64/decode.c b/tools/objtool/arch/arm64/decode.c
index 4d0ab2acca27..04358f41ef1d 100644
--- a/tools/objtool/arch/arm64/decode.c
+++ b/tools/objtool/arch/arm64/decode.c
@@ -78,7 +78,9 @@ static int is_arm64(struct elf *elf)
  *				 struct list_head *ops_list);
  */
 static arm_decode_class aarch64_insn_class_decode_table[NR_INSN_CLASS] = {
-	NULL,
+	[INSN_RESERVED]			= arm_decode_unknown,
+	[INSN_UNKNOWN]			= arm_decode_unknown,
+	[INSN_UNALLOC]			= arm_decode_unknown,
 };
 
 /*
@@ -125,3 +127,21 @@ int arch_decode_instruction(struct elf *elf, struct section *sec,
 		WARN_FUNC("Unsupported instruction", sec, offset);
 	return res;
 }
+
+int arm_decode_unknown(u32 instr, enum insn_type *type,
+		       unsigned long *immediate, struct list_head *ops_list)
+{
+	/*
+	 * There are a few reasons we might have non-valid opcodes in
+	 * code sections:
+	 * - For load literal, assembler can generate the data to be loaded in
+	 *   the code section
+	 * - Compiler/assembler can generate zeroes to pad function that do not
+	 *   end on 8-byte alignment
+	 * - Hand written assembly code might contain constants in the code
+	 *   section
+	 */
+	*type = INSN_INVALID;
+
+	return 0;
+}
diff --git a/tools/objtool/arch/arm64/include/insn_decode.h b/tools/objtool/arch/arm64/include/insn_decode.h
index c56b72ac4633..16066f8fca0d 100644
--- a/tools/objtool/arch/arm64/include/insn_decode.h
+++ b/tools/objtool/arch/arm64/include/insn_decode.h
@@ -5,6 +5,10 @@
 
 #include "../../../arch.h"
 
+#define INSN_RESERVED	0b0000
+#define INSN_UNKNOWN	0b0001
+#define INSN_UNALLOC	0b0011
+
 #define NR_INSN_CLASS	16
 #define INSN_CLASS(opcode)	(((opcode) >> 25) & (NR_INSN_CLASS - 1))
 
@@ -12,4 +16,7 @@ typedef int (*arm_decode_class)(u32 instr, enum insn_type *type,
 				unsigned long *immediate,
 				struct list_head *ops_list);
 
+/* arm64 instruction classes */
+int arm_decode_unknown(u32 instr, enum insn_type *type,
+		       unsigned long *immediate, struct list_head *ops_list);
 #endif /* _ARM_INSN_DECODE_H */
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 48aec56a7760..52a8e64e15ca 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -1818,6 +1818,13 @@ static int validate_branch_alt_safe(struct objtool_file *file,
 	while (1) {
 		next_insn = next_insn_same_sec(file, insn);
 
+		if (insn->type == INSN_INVALID) {
+			WARN("%s+0x%lx non-executable instruction, 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);
@@ -2137,7 +2144,8 @@ static bool ignore_unreachable_insn(struct instruction *insn)
 {
 	int i;
 
-	if (insn->ignore || insn->type == INSN_NOP)
+	if (insn->ignore || insn->type == INSN_NOP ||
+	    insn->type == INSN_INVALID)
 		return true;
 
 	/*
-- 
2.21.0


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

* [RFC v5 21/57] objtool: arm64: Decode simple data processing instructions
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (19 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 20/57] objtool: arm64: Decode unknown instructions Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 22/57] objtool: arm64: Decode add/sub immediate instructions Julien Thierry
                   ` (38 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

Decode data processing instructions that do not constitute stack
operations.

Suggested-by: Raphael Gault <raphael.gault@arm.com>
Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/arch/arm64/decode.c             | 104 ++++++++++++++++++
 .../objtool/arch/arm64/include/insn_decode.h  |  18 +++
 2 files changed, 122 insertions(+)

diff --git a/tools/objtool/arch/arm64/decode.c b/tools/objtool/arch/arm64/decode.c
index 04358f41ef1d..6c8db9335fc9 100644
--- a/tools/objtool/arch/arm64/decode.c
+++ b/tools/objtool/arch/arm64/decode.c
@@ -81,6 +81,7 @@ static arm_decode_class aarch64_insn_class_decode_table[NR_INSN_CLASS] = {
 	[INSN_RESERVED]			= arm_decode_unknown,
 	[INSN_UNKNOWN]			= arm_decode_unknown,
 	[INSN_UNALLOC]			= arm_decode_unknown,
+	[0b1000 ... INSN_DP_IMM]	= arm_decode_dp_imm,
 };
 
 /*
@@ -145,3 +146,106 @@ int arm_decode_unknown(u32 instr, enum insn_type *type,
 
 	return 0;
 }
+
+#define NR_DP_IMM_SUBCLASS	8
+#define INSN_DP_IMM_SUBCLASS(opcode)			\
+	(((opcode) >> 23) & (NR_DP_IMM_SUBCLASS - 1))
+
+static arm_decode_class aarch64_insn_dp_imm_decode_table[NR_DP_IMM_SUBCLASS] = {
+	[0 ... INSN_PCREL]	= arm_decode_pcrel,
+	[INSN_MOVE_WIDE]	= arm_decode_move_wide,
+	[INSN_BITFIELD]		= arm_decode_bitfield,
+	[INSN_EXTRACT]		= arm_decode_extract,
+};
+
+int arm_decode_dp_imm(u32 instr, enum insn_type *type,
+		      unsigned long *immediate, struct list_head *ops_list)
+{
+	arm_decode_class decode_fun;
+
+	decode_fun = aarch64_insn_dp_imm_decode_table[INSN_DP_IMM_SUBCLASS(instr)];
+	if (!decode_fun)
+		return -1;
+	return decode_fun(instr, type, immediate, ops_list);
+}
+
+int arm_decode_pcrel(u32 instr, enum insn_type *type,
+		     unsigned long *immediate, struct list_head *ops_list)
+{
+	unsigned char page = 0;
+	u32 immhi = 0, immlo = 0;
+
+	page = EXTRACT_BIT(instr, 31);
+	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;
+
+	return 0;
+}
+
+int arm_decode_move_wide(u32 instr, enum insn_type *type,
+			 unsigned long *immediate, struct list_head *ops_list)
+{
+	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, ops_list);
+
+	*type = INSN_OTHER;
+	*immediate = imm16;
+
+	return 0;
+}
+
+int arm_decode_bitfield(u32 instr, enum insn_type *type,
+			unsigned long *immediate, struct list_head *ops_list)
+{
+	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, ops_list);
+
+	*type = INSN_OTHER;
+
+	return 0;
+}
+
+int arm_decode_extract(u32 instr, enum insn_type *type,
+		       unsigned long *immediate, struct list_head *ops_list)
+{
+	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, ops_list);
+}
diff --git a/tools/objtool/arch/arm64/include/insn_decode.h b/tools/objtool/arch/arm64/include/insn_decode.h
index 16066f8fca0d..06235d81300c 100644
--- a/tools/objtool/arch/arm64/include/insn_decode.h
+++ b/tools/objtool/arch/arm64/include/insn_decode.h
@@ -8,15 +8,33 @@
 #define INSN_RESERVED	0b0000
 #define INSN_UNKNOWN	0b0001
 #define INSN_UNALLOC	0b0011
+#define INSN_DP_IMM	0b1001	//0x100x
 
 #define NR_INSN_CLASS	16
 #define INSN_CLASS(opcode)	(((opcode) >> 25) & (NR_INSN_CLASS - 1))
 
+#define INSN_PCREL	0b001	//0b00x
+#define INSN_MOVE_WIDE	0b101
+#define INSN_BITFIELD	0b110
+#define INSN_EXTRACT	0b111
+
 typedef int (*arm_decode_class)(u32 instr, enum insn_type *type,
 				unsigned long *immediate,
 				struct list_head *ops_list);
 
 /* arm64 instruction classes */
+int arm_decode_dp_imm(u32 instr, enum insn_type *type,
+		      unsigned long *immediate, struct list_head *ops_list);
 int arm_decode_unknown(u32 instr, enum insn_type *type,
 		       unsigned long *immediate, struct list_head *ops_list);
+
+/* arm64 data processing -- immediate subclasses */
+int arm_decode_pcrel(u32 instr, enum insn_type *type,
+		     unsigned long *immediate, struct list_head *ops_list);
+int arm_decode_move_wide(u32 instr, enum insn_type *type,
+			 unsigned long *immediate, struct list_head *ops_list);
+int arm_decode_bitfield(u32 instr, enum insn_type *type,
+			unsigned long *immediate, struct list_head *ops_list);
+int arm_decode_extract(u32 instr, enum insn_type *type,
+		       unsigned long *immediate, struct list_head *ops_list);
 #endif /* _ARM_INSN_DECODE_H */
-- 
2.21.0


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

* [RFC v5 22/57] objtool: arm64: Decode add/sub immediate instructions
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (20 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 21/57] objtool: arm64: Decode simple data processing instructions Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 23/57] objtool: arm64: Decode logical data processing instructions Julien Thierry
                   ` (37 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

Decode instruction adding immediates to registers. Create stack
operation for instructions interacting with the stack pointer or the
frame pointer.

Suggested-by: Raphael Gault <raphael.gault@arm.com>
Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/arch/arm64/decode.c             | 84 +++++++++++++++++++
 .../objtool/arch/arm64/include/insn_decode.h  |  7 ++
 2 files changed, 91 insertions(+)

diff --git a/tools/objtool/arch/arm64/decode.c b/tools/objtool/arch/arm64/decode.c
index 6c8db9335fc9..d240f29a2390 100644
--- a/tools/objtool/arch/arm64/decode.c
+++ b/tools/objtool/arch/arm64/decode.c
@@ -13,6 +13,11 @@
 #include "../../elf.h"
 #include "../../warn.h"
 
+static bool stack_related_reg(int reg)
+{
+	return reg == CFI_SP || reg == CFI_BP;
+}
+
 bool arch_callee_saved_reg(unsigned char reg)
 {
 	switch (reg) {
@@ -153,6 +158,8 @@ int arm_decode_unknown(u32 instr, enum insn_type *type,
 
 static arm_decode_class aarch64_insn_dp_imm_decode_table[NR_DP_IMM_SUBCLASS] = {
 	[0 ... INSN_PCREL]	= arm_decode_pcrel,
+	[INSN_ADD_SUB]		= arm_decode_add_sub,
+	[INSN_ADD_TAG]		= arm_decode_add_sub_tags,
 	[INSN_MOVE_WIDE]	= arm_decode_move_wide,
 	[INSN_BITFIELD]		= arm_decode_bitfield,
 	[INSN_EXTRACT]		= arm_decode_extract,
@@ -189,6 +196,83 @@ int arm_decode_pcrel(u32 instr, enum insn_type *type,
 	return 0;
 }
 
+int arm_decode_add_sub(u32 instr, enum insn_type *type,
+		       unsigned long *immediate, struct list_head *ops_list)
+{
+	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 (rd == CFI_BP || (!S && rd == CFI_SP) || stack_related_reg(rn)) {
+		struct stack_op *op;
+
+		*type = INSN_STACK;
+
+		op = calloc(1, sizeof(*op));
+		list_add_tail(&op->list, ops_list);
+
+		op->dest.type = OP_DEST_REG;
+		op->dest.offset = 0;
+		op->dest.reg = rd;
+		op->src.type = OP_SRC_ADD;
+		op->src.offset = op_bit ? -1 * imm : imm;
+		op->src.reg = rn;
+	}
+	return 0;
+}
+
+int arm_decode_add_sub_tags(u32 instr, enum insn_type *type,
+			    unsigned long *immediate,
+			    struct list_head *ops_list)
+{
+	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, ops_list);
+
+#undef ADDG_DECODE
+#undef SUBG_DECODE
+
+	if (stack_related_reg(rd)) {
+		struct stack_op *op;
+
+		*type = INSN_STACK;
+
+		op = calloc(1, sizeof(*op));
+		list_add_tail(&op->list, ops_list);
+
+		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;
+	}
+
+	return 0;
+}
+
 int arm_decode_move_wide(u32 instr, enum insn_type *type,
 			 unsigned long *immediate, struct list_head *ops_list)
 {
diff --git a/tools/objtool/arch/arm64/include/insn_decode.h b/tools/objtool/arch/arm64/include/insn_decode.h
index 06235d81300c..65e60b293a07 100644
--- a/tools/objtool/arch/arm64/include/insn_decode.h
+++ b/tools/objtool/arch/arm64/include/insn_decode.h
@@ -14,6 +14,8 @@
 #define INSN_CLASS(opcode)	(((opcode) >> 25) & (NR_INSN_CLASS - 1))
 
 #define INSN_PCREL	0b001	//0b00x
+#define INSN_ADD_SUB	0b010
+#define INSN_ADD_TAG	0b011
 #define INSN_MOVE_WIDE	0b101
 #define INSN_BITFIELD	0b110
 #define INSN_EXTRACT	0b111
@@ -31,6 +33,11 @@ int arm_decode_unknown(u32 instr, enum insn_type *type,
 /* arm64 data processing -- immediate subclasses */
 int arm_decode_pcrel(u32 instr, enum insn_type *type,
 		     unsigned long *immediate, struct list_head *ops_list);
+int arm_decode_add_sub(u32 instr, enum insn_type *type,
+		       unsigned long *immediate, struct list_head *ops_list);
+int arm_decode_add_sub_tags(u32 instr, enum insn_type *type,
+			    unsigned long *immediate,
+			    struct list_head *ops_list);
 int arm_decode_move_wide(u32 instr, enum insn_type *type,
 			 unsigned long *immediate, struct list_head *ops_list);
 int arm_decode_bitfield(u32 instr, enum insn_type *type,
-- 
2.21.0


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

* [RFC v5 23/57] objtool: arm64: Decode logical data processing instructions
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (21 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 22/57] objtool: arm64: Decode add/sub immediate instructions Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 24/57] objtool: arm64: Decode system instructions not affecting the flow Julien Thierry
                   ` (36 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

Decode instructions performing logical operations with immediate values.
Create a stack operation for and operation targeting the stack pointer.

Since OP_SRC_AND assumes the source and destination register are the same,
add a register assignment operation when the source operand of the logical
instruction is not the stack pointer.

Suggested-by: Raphael Gault <raphael.gault@arm.com>
Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/arch/arm64/decode.c             | 58 +++++++++++++++++++
 .../objtool/arch/arm64/include/insn_decode.h  |  3 +
 2 files changed, 61 insertions(+)

diff --git a/tools/objtool/arch/arm64/decode.c b/tools/objtool/arch/arm64/decode.c
index d240f29a2390..a30c3294cc21 100644
--- a/tools/objtool/arch/arm64/decode.c
+++ b/tools/objtool/arch/arm64/decode.c
@@ -160,6 +160,7 @@ static arm_decode_class aarch64_insn_dp_imm_decode_table[NR_DP_IMM_SUBCLASS] = {
 	[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,
@@ -273,6 +274,63 @@ int arm_decode_add_sub_tags(u32 instr, enum insn_type *type,
 	return 0;
 }
 
+int arm_decode_logical(u32 instr, enum insn_type *type,
+		       unsigned long *immediate, struct list_head *ops_list)
+{
+	unsigned char sf = 0, opc = 0, N = 0;
+	unsigned char imms = 0, immr = 0, rn = 0, rd = 0;
+	struct stack_op *op;
+
+	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, ops_list);
+
+	*type = INSN_OTHER;
+	*immediate = (decode_bit_masks(N, imms, immr, true) >> 64);
+
+	if (opc & 1)
+		return 0;
+
+	if (rd != CFI_SP)
+		return 0;
+
+	*type = INSN_STACK;
+
+	if (rn != CFI_SP) {
+		op = calloc(1, sizeof(*op));
+		list_add_tail(&op->list, ops_list);
+
+		op->dest.type = OP_DEST_REG;
+		op->dest.offset = 0;
+		op->dest.reg = rd;
+		op->src.type = OP_SRC_REG;
+		op->src.offset = 0;
+		op->src.reg = rn;
+	}
+
+	op = calloc(1, sizeof(*op));
+	list_add_tail(&op->list, ops_list);
+
+	op->dest.type = OP_DEST_REG;
+	op->dest.offset = 0;
+	op->dest.reg = rd;
+
+	op->src.type = OP_SRC_AND;
+	op->src.offset = 0;
+	op->src.reg = rd;
+
+	return 0;
+}
+
 int arm_decode_move_wide(u32 instr, enum insn_type *type,
 			 unsigned long *immediate, struct list_head *ops_list)
 {
diff --git a/tools/objtool/arch/arm64/include/insn_decode.h b/tools/objtool/arch/arm64/include/insn_decode.h
index 65e60b293a07..6f68e8887cdb 100644
--- a/tools/objtool/arch/arm64/include/insn_decode.h
+++ b/tools/objtool/arch/arm64/include/insn_decode.h
@@ -16,6 +16,7 @@
 #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
@@ -38,6 +39,8 @@ int arm_decode_add_sub(u32 instr, enum insn_type *type,
 int arm_decode_add_sub_tags(u32 instr, enum insn_type *type,
 			    unsigned long *immediate,
 			    struct list_head *ops_list);
+int arm_decode_logical(u32 instr, enum insn_type *type,
+		       unsigned long *immediate, struct list_head *ops_list);
 int arm_decode_move_wide(u32 instr, enum insn_type *type,
 			 unsigned long *immediate, struct list_head *ops_list);
 int arm_decode_bitfield(u32 instr, enum insn_type *type,
-- 
2.21.0


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

* [RFC v5 24/57] objtool: arm64: Decode system instructions not affecting the flow
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (22 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 23/57] objtool: arm64: Decode logical data processing instructions Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 25/57] objtool: arm64: Decode calls to higher EL Julien Thierry
                   ` (35 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

Decode basic system instructions that do not cause jumps or stack
pointer modifications.

Suggested-by: Raphael Gault <raphael.gault@arm.com>
Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/arch/arm64/decode.c             | 95 +++++++++++++++++++
 .../objtool/arch/arm64/include/insn_decode.h  | 23 +++++
 2 files changed, 118 insertions(+)

diff --git a/tools/objtool/arch/arm64/decode.c b/tools/objtool/arch/arm64/decode.c
index a30c3294cc21..c38d73fb57e1 100644
--- a/tools/objtool/arch/arm64/decode.c
+++ b/tools/objtool/arch/arm64/decode.c
@@ -87,6 +87,7 @@ static arm_decode_class aarch64_insn_class_decode_table[NR_INSN_CLASS] = {
 	[INSN_UNKNOWN]			= arm_decode_unknown,
 	[INSN_UNALLOC]			= arm_decode_unknown,
 	[0b1000 ... INSN_DP_IMM]	= arm_decode_dp_imm,
+	[0b1010 ... INSN_SYS_BRANCH]	= arm_decode_br_sys,
 };
 
 /*
@@ -391,3 +392,97 @@ int arm_decode_extract(u32 instr, enum insn_type *type,
 
 	return arm_decode_unknown(instr, type, immediate, ops_list);
 }
+
+static struct aarch64_insn_decoder br_sys_decoder[] = {
+	{
+		.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,
+	},
+};
+
+int arm_decode_br_sys(u32 instr, enum insn_type *type,
+		      unsigned long *immediate, struct list_head *ops_list)
+{
+	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,
+							     ops_list);
+		}
+	}
+
+	return arm_decode_unknown(instr, type, immediate, ops_list);
+}
+
+int arm_decode_hints(u32 instr, enum insn_type *type,
+		     unsigned long *immediate, struct list_head *ops_list)
+{
+	*type = INSN_NOP;
+	return 0;
+}
+
+int arm_decode_barriers(u32 instr, enum insn_type *type,
+			unsigned long *immediate, struct list_head *ops_list)
+{
+	/* TODO:check unallocated */
+	*type = INSN_OTHER;
+	return 0;
+}
+
+int arm_decode_pstate(u32 instr, enum insn_type *type,
+		      unsigned long *immediate, struct list_head *ops_list)
+{
+	/* TODO:check unallocated */
+	*type = INSN_OTHER;
+	return 0;
+}
+
+int arm_decode_system_insn(u32 instr, enum insn_type *type,
+			   unsigned long *immediate, struct list_head *ops_list)
+{
+	/* TODO:check unallocated */
+	*type = INSN_OTHER;
+	return 0;
+}
+
+int arm_decode_system_regs(u32 instr, enum insn_type *type,
+			   unsigned long *immediate, struct list_head *ops_list)
+{
+	/* TODO:check unallocated */
+	*type = INSN_OTHER;
+	return 0;
+}
diff --git a/tools/objtool/arch/arm64/include/insn_decode.h b/tools/objtool/arch/arm64/include/insn_decode.h
index 6f68e8887cdb..777a62f1a141 100644
--- a/tools/objtool/arch/arm64/include/insn_decode.h
+++ b/tools/objtool/arch/arm64/include/insn_decode.h
@@ -9,6 +9,7 @@
 #define INSN_UNKNOWN	0b0001
 #define INSN_UNALLOC	0b0011
 #define INSN_DP_IMM	0b1001	//0x100x
+#define INSN_SYS_BRANCH	0b1011	//0x101x
 
 #define NR_INSN_CLASS	16
 #define INSN_CLASS(opcode)	(((opcode) >> 25) & (NR_INSN_CLASS - 1))
@@ -25,9 +26,17 @@ typedef int (*arm_decode_class)(u32 instr, enum insn_type *type,
 				unsigned long *immediate,
 				struct list_head *ops_list);
 
+struct aarch64_insn_decoder {
+	u32 mask;
+	u32 value;
+	arm_decode_class decode_func;
+};
+
 /* arm64 instruction classes */
 int arm_decode_dp_imm(u32 instr, enum insn_type *type,
 		      unsigned long *immediate, struct list_head *ops_list);
+int arm_decode_br_sys(u32 instr, enum insn_type *type,
+		      unsigned long *immediate, struct list_head *ops_list);
 int arm_decode_unknown(u32 instr, enum insn_type *type,
 		       unsigned long *immediate, struct list_head *ops_list);
 
@@ -47,4 +56,18 @@ int arm_decode_bitfield(u32 instr, enum insn_type *type,
 			unsigned long *immediate, struct list_head *ops_list);
 int arm_decode_extract(u32 instr, enum insn_type *type,
 		       unsigned long *immediate, struct list_head *ops_list);
+
+/* arm64 branch, exception generation, system insn subclasses */
+int arm_decode_hints(u32 instr, enum insn_type *type,
+		     unsigned long *immediate, struct list_head *ops_list);
+int arm_decode_barriers(u32 instr, enum insn_type *type,
+			unsigned long *immediate, struct list_head *ops_list);
+int arm_decode_pstate(u32 instr, enum insn_type *type,
+		      unsigned long *immediate, struct list_head *ops_list);
+int arm_decode_system_insn(u32 instr, enum insn_type *type,
+			   unsigned long *immediate,
+			   struct list_head *ops_list);
+int arm_decode_system_regs(u32 instr, enum insn_type *type,
+			   unsigned long *immediate,
+			   struct list_head *ops_list);
 #endif /* _ARM_INSN_DECODE_H */
-- 
2.21.0


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

* [RFC v5 25/57] objtool: arm64: Decode calls to higher EL
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (23 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 24/57] objtool: arm64: Decode system instructions not affecting the flow Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 26/57] objtool: arm64: Decode brk instruction Julien Thierry
                   ` (34 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

Decode instructions that volontarily trigger exceptions to a higher
exception level.

It is assumed that the higher exception level should service the request
in a sane maner, returning to the caller exception level without
altering its context too much (e.g. not modifying the PC, the stack
pointer or the frame pointer).

Suggested-by: Raphael Gault <raphael.gault@arm.com>
Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/arch/arm64/decode.c             | 45 +++++++++++++++++++
 .../objtool/arch/arm64/include/insn_decode.h  |  2 +
 2 files changed, 47 insertions(+)

diff --git a/tools/objtool/arch/arm64/decode.c b/tools/objtool/arch/arm64/decode.c
index c38d73fb57e1..aa00de725686 100644
--- a/tools/objtool/arch/arm64/decode.c
+++ b/tools/objtool/arch/arm64/decode.c
@@ -419,6 +419,11 @@ static struct aarch64_insn_decoder br_sys_decoder[] = {
 		.value = 0b1100100010000000000000,
 		.decode_func = arm_decode_system_regs,
 	},
+	{
+		.mask = 0b1111100000000000000000,
+		.value = 0b1100000000000000000000,
+		.decode_func = arm_decode_except_gen,
+	},
 };
 
 int arm_decode_br_sys(u32 instr, enum insn_type *type,
@@ -486,3 +491,43 @@ int arm_decode_system_regs(u32 instr, enum insn_type *type,
 	*type = INSN_OTHER;
 	return 0;
 }
+
+int arm_decode_except_gen(u32 instr, enum insn_type *type,
+			  unsigned long *immediate, struct list_head *ops_list)
+{
+	u32 imm16 = 0;
+	unsigned char opc = 0, op2 = 0, LL = 0, decode_field = 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;
+
+#define INSN_SVC	0b00000001
+#define INSN_HVC	0b00000010
+#define INSN_SMC	0b00000011
+
+	switch (decode_field) {
+	case INSN_SVC:
+	case INSN_HVC:
+	case INSN_SMC:
+		/*
+		 * We consider that the context will be restored correctly
+		 * with an unchanged sp and the same general registers
+		 */
+		*type = INSN_NOP;
+		return 0;
+	default:
+		return arm_decode_unknown(instr, type, immediate, ops_list);
+	}
+
+#undef INSN_SVC
+#undef INSN_HVC
+#undef INSN_SMC
+#undef INSN_BRK
+#undef INSN_HLT
+#undef INSN_DCPS1
+#undef INSN_DCPS2
+#undef INSN_DCPS3
+}
diff --git a/tools/objtool/arch/arm64/include/insn_decode.h b/tools/objtool/arch/arm64/include/insn_decode.h
index 777a62f1a141..a55dcbfcfed2 100644
--- a/tools/objtool/arch/arm64/include/insn_decode.h
+++ b/tools/objtool/arch/arm64/include/insn_decode.h
@@ -70,4 +70,6 @@ int arm_decode_system_insn(u32 instr, enum insn_type *type,
 int arm_decode_system_regs(u32 instr, enum insn_type *type,
 			   unsigned long *immediate,
 			   struct list_head *ops_list);
+int arm_decode_except_gen(u32 instr, enum insn_type *type,
+			  unsigned long *immediate, struct list_head *ops_list);
 #endif /* _ARM_INSN_DECODE_H */
-- 
2.21.0


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

* [RFC v5 26/57] objtool: arm64: Decode brk instruction
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (24 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 25/57] objtool: arm64: Decode calls to higher EL Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 27/57] objtool: arm64: Decode instruction triggering context switch Julien Thierry
                   ` (33 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

Add decoding brk instructions. Associate known immediate values with
their kernel/compiler semantics.

Suggested-by: Raphael Gault <raphael.gault@arm.com>
Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/arch/arm64/decode.c | 33 +++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/tools/objtool/arch/arm64/decode.c b/tools/objtool/arch/arm64/decode.c
index aa00de725686..1609750cc4b9 100644
--- a/tools/objtool/arch/arm64/decode.c
+++ b/tools/objtool/arch/arm64/decode.c
@@ -507,6 +507,7 @@ int arm_decode_except_gen(u32 instr, enum insn_type *type,
 #define INSN_SVC	0b00000001
 #define INSN_HVC	0b00000010
 #define INSN_SMC	0b00000011
+#define INSN_BRK	0b00100000
 
 	switch (decode_field) {
 	case INSN_SVC:
@@ -518,6 +519,38 @@ int arm_decode_except_gen(u32 instr, enum insn_type *type,
 		 */
 		*type = INSN_NOP;
 		return 0;
+	case INSN_BRK:
+		/* Based on arch/arm64/include/asm/brk-imm.h */
+		switch (imm16) {
+		case 0x004: /* KPROBES_BRK_IMM */
+		case 0x005: /* UPROBES_BRK_IMM */
+		case 0x400: /* KGDB_DYN_DBG_BRK_IMM */
+		case 0x401: /* KGDB_COMPILED_DBG_BRK_IMM */
+			*type = INSN_OTHER;
+			break;
+		case 0x800: /* BUG_BRK_IMM */
+			/*
+			 * brk #0x800 is generated by the BUG()/WARN() linux API
+			 * and is thus a particular case. Since those are not
+			 * necessarily compiled in, the surrounding code should
+			 * work properly without it. We thus consider it as a
+			 * nop.
+			 */
+			*type = INSN_NOP;
+			break;
+		case 0x3e8:
+			/*
+			 * Similar to the use of "ud2" on x86, GCC inserts
+			 * "brk #0x38e" instructions for certain divide-by-zero
+			 * cases.
+			 */
+			*type = INSN_BUG;
+			break;
+		default:
+			*type = INSN_CONTEXT_SWITCH;
+			break;
+		}
+		return 0;
 	default:
 		return arm_decode_unknown(instr, type, immediate, ops_list);
 	}
-- 
2.21.0


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

* [RFC v5 27/57] objtool: arm64: Decode instruction triggering context switch
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (25 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 26/57] objtool: arm64: Decode brk instruction Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 28/57] objtool: arm64: Decode branch instructions with PC relative immediates Julien Thierry
                   ` (32 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

Decode instructions that volutarily trigger an exception to change
the context of execution.

Suggested-by: Raphael Gault <raphael.gault@arm.com>
Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/arch/arm64/decode.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/tools/objtool/arch/arm64/decode.c b/tools/objtool/arch/arm64/decode.c
index 1609750cc4b9..5eba83c5d5bc 100644
--- a/tools/objtool/arch/arm64/decode.c
+++ b/tools/objtool/arch/arm64/decode.c
@@ -508,6 +508,10 @@ int arm_decode_except_gen(u32 instr, enum insn_type *type,
 #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:
@@ -551,6 +555,13 @@ int arm_decode_except_gen(u32 instr, enum insn_type *type,
 			break;
 		}
 		return 0;
+	case INSN_HLT:
+	case INSN_DCPS1:
+	case INSN_DCPS2:
+	case INSN_DCPS3:
+		*immediate = imm16;
+		*type = INSN_CONTEXT_SWITCH;
+		return 0;
 	default:
 		return arm_decode_unknown(instr, type, immediate, ops_list);
 	}
-- 
2.21.0


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

* [RFC v5 28/57] objtool: arm64: Decode branch instructions with PC relative immediates
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (26 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 27/57] objtool: arm64: Decode instruction triggering context switch Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 29/57] objtool: arm64: Decode branch to register instruction Julien Thierry
                   ` (31 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

Decode instructions that cause a jump in the execution flow, adding
an immediate value to the current instruction counter.

Suggested-by: Raphael Gault <raphael.gault@arm.com>
Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/arch/arm64/decode.c             | 79 +++++++++++++++++++
 .../objtool/arch/arm64/include/insn_decode.h  | 11 +++
 2 files changed, 90 insertions(+)

diff --git a/tools/objtool/arch/arm64/decode.c b/tools/objtool/arch/arm64/decode.c
index 5eba83c5d5bc..7986ded8b622 100644
--- a/tools/objtool/arch/arm64/decode.c
+++ b/tools/objtool/arch/arm64/decode.c
@@ -424,6 +424,26 @@ static struct aarch64_insn_decoder br_sys_decoder[] = {
 		.value = 0b1100000000000000000000,
 		.decode_func = arm_decode_except_gen,
 	},
+	{
+		.mask = 0b1111000000000000000000,
+		.value = 0b0100000000000000000000,
+		.decode_func = arm_decode_br_cond_imm,
+	},
+	{
+		.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, enum insn_type *type,
@@ -575,3 +595,62 @@ int arm_decode_except_gen(u32 instr, enum insn_type *type,
 #undef INSN_DCPS2
 #undef INSN_DCPS3
 }
+
+int arm_decode_br_cond_imm(u32 instr, enum insn_type *type,
+			   unsigned long *immediate, struct list_head *ops_list)
+{
+	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, ops_list);
+
+	*type = INSN_JUMP_CONDITIONAL;
+
+	return 0;
+}
+
+int arm_decode_br_uncond_imm(u32 instr, enum insn_type *type,
+			     unsigned long *immediate,
+			     struct list_head *ops_list)
+{
+	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, enum insn_type *type,
+			   unsigned long *immediate, struct list_head *ops_list)
+{
+	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, enum insn_type *type,
+			  unsigned long *immediate, struct list_head *ops_list)
+{
+	u32 imm14 = (instr >> 5) & ONES(14);
+
+	*immediate = SIGN_EXTEND(imm14 << 2, 16);
+	*type = INSN_JUMP_CONDITIONAL;
+	return 0;
+}
diff --git a/tools/objtool/arch/arm64/include/insn_decode.h b/tools/objtool/arch/arm64/include/insn_decode.h
index a55dcbfcfed2..ceb80a58c548 100644
--- a/tools/objtool/arch/arm64/include/insn_decode.h
+++ b/tools/objtool/arch/arm64/include/insn_decode.h
@@ -72,4 +72,15 @@ int arm_decode_system_regs(u32 instr, enum insn_type *type,
 			   struct list_head *ops_list);
 int arm_decode_except_gen(u32 instr, enum insn_type *type,
 			  unsigned long *immediate, struct list_head *ops_list);
+int arm_decode_br_uncond_imm(u32 instr, enum insn_type *type,
+			     unsigned long *immediate,
+			     struct list_head *ops_list);
+int arm_decode_br_comp_imm(u32 instr, enum insn_type *type,
+			   unsigned long *immediate,
+			   struct list_head *ops_list);
+int arm_decode_br_tst_imm(u32 instr, enum insn_type *type,
+			  unsigned long *immediate, struct list_head *ops_list);
+int arm_decode_br_cond_imm(u32 instr, enum insn_type *type,
+			   unsigned long *immediate,
+			   struct list_head *ops_list);
 #endif /* _ARM_INSN_DECODE_H */
-- 
2.21.0


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

* [RFC v5 29/57] objtool: arm64: Decode branch to register instruction
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (27 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 28/57] objtool: arm64: Decode branch instructions with PC relative immediates Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 30/57] objtool: arm64: Decode basic load/stores Julien Thierry
                   ` (30 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

Decode instructions producing jumps in the execution flow, taking the
value of their operand register as the target address.

Return instructions are just branch to register instruction with
the link register (x31) as implicit operand.

Suggested-by: Raphael Gault <raphael.gault@arm.com>
Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/arch/arm64/decode.c             | 150 ++++++++++++++++++
 .../objtool/arch/arm64/include/insn_decode.h  |   3 +
 2 files changed, 153 insertions(+)

diff --git a/tools/objtool/arch/arm64/decode.c b/tools/objtool/arch/arm64/decode.c
index 7986ded8b622..bf9334451b40 100644
--- a/tools/objtool/arch/arm64/decode.c
+++ b/tools/objtool/arch/arm64/decode.c
@@ -444,6 +444,11 @@ static struct aarch64_insn_decoder br_sys_decoder[] = {
 		.value = 0b0011000000000000000000,
 		.decode_func = arm_decode_br_tst_imm,
 	},
+	{
+		.mask = 0b1111000000000000000000,
+		.value = 0b1101000000000000000000,
+		.decode_func = arm_decode_br_uncond_reg,
+	},
 };
 
 int arm_decode_br_sys(u32 instr, enum insn_type *type,
@@ -654,3 +659,148 @@ int arm_decode_br_tst_imm(u32 instr, enum insn_type *type,
 	*type = INSN_JUMP_CONDITIONAL;
 	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, enum insn_type *type,
+			     unsigned long *immediate,
+			     struct list_head *ops_list)
+{
+	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, ops_list);
+	return 0;
+}
+
+#undef INSN_DRPS_FIELD
+#undef INSN_DRPS_MASK
diff --git a/tools/objtool/arch/arm64/include/insn_decode.h b/tools/objtool/arch/arm64/include/insn_decode.h
index ceb80a58c548..6e600f408bea 100644
--- a/tools/objtool/arch/arm64/include/insn_decode.h
+++ b/tools/objtool/arch/arm64/include/insn_decode.h
@@ -83,4 +83,7 @@ int arm_decode_br_tst_imm(u32 instr, enum insn_type *type,
 int arm_decode_br_cond_imm(u32 instr, enum insn_type *type,
 			   unsigned long *immediate,
 			   struct list_head *ops_list);
+int arm_decode_br_uncond_reg(u32 instr, enum insn_type *type,
+			     unsigned long *immediate,
+			     struct list_head *ops_list);
 #endif /* _ARM_INSN_DECODE_H */
-- 
2.21.0


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

* [RFC v5 30/57] objtool: arm64: Decode basic load/stores
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (28 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 29/57] objtool: arm64: Decode branch to register instruction Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 31/57] objtool: arm64: Decode load/store with register offset Julien Thierry
                   ` (29 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

Decode load/store instructions for single register, using an immediate
offset for the target address.

Suggested-by: Raphael Gault <raphael.gault@arm.com>
Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/arch/arm64/decode.c             | 396 ++++++++++++++++++
 .../objtool/arch/arm64/include/insn_decode.h  |  23 +
 2 files changed, 419 insertions(+)

diff --git a/tools/objtool/arch/arm64/decode.c b/tools/objtool/arch/arm64/decode.c
index bf9334451b40..7064302416f4 100644
--- a/tools/objtool/arch/arm64/decode.c
+++ b/tools/objtool/arch/arm64/decode.c
@@ -86,8 +86,12 @@ static arm_decode_class aarch64_insn_class_decode_table[NR_INSN_CLASS] = {
 	[INSN_RESERVED]			= arm_decode_unknown,
 	[INSN_UNKNOWN]			= arm_decode_unknown,
 	[INSN_UNALLOC]			= arm_decode_unknown,
+	[INSN_LD_ST_4]			= arm_decode_ld_st,
+	[INSN_LD_ST_6]			= arm_decode_ld_st,
 	[0b1000 ... INSN_DP_IMM]	= arm_decode_dp_imm,
 	[0b1010 ... INSN_SYS_BRANCH]	= arm_decode_br_sys,
+	[INSN_LD_ST_C]			= arm_decode_ld_st,
+	[INSN_LD_ST_E]			= arm_decode_ld_st,
 };
 
 /*
@@ -804,3 +808,395 @@ int arm_decode_br_uncond_reg(u32 instr, enum insn_type *type,
 
 #undef INSN_DRPS_FIELD
 #undef INSN_DRPS_MASK
+
+static struct aarch64_insn_decoder ld_st_decoder[] = {
+	{
+		.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 = 0b001101000000000,
+		.value = 0b001101000000000,
+		.decode_func = arm_decode_ld_st_regs_unsigned,
+	},
+};
+
+int arm_decode_ld_st(u32 instr, enum insn_type *type,
+		     unsigned long *immediate, struct list_head *ops_list)
+{
+	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,
+							    ops_list);
+		}
+	}
+	return arm_decode_unknown(instr, type, immediate, ops_list);
+}
+
+int arm_decode_ld_st_regs_unsc_imm(u32 instr, enum insn_type *type,
+				   unsigned long *immediate,
+				   struct list_head *ops_list)
+{
+	u32 imm9 = 0;
+	unsigned char size = 0, V = 0, opc = 0, rn = 0, rt = 0;
+	unsigned char decode_field = 0;
+	struct stack_op *op;
+
+	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, ops_list);
+	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 (!stack_related_reg(rn)) {
+			*type = INSN_OTHER;
+			return 0;
+		}
+
+		op = calloc(1, sizeof(*op));
+		list_add_tail(&op->list, ops_list);
+
+		op->src.type = OP_SRC_REG_INDIRECT;
+		op->src.reg = rn;
+		op->src.offset = SIGN_EXTEND(imm9, 9);
+		op->dest.type = OP_DEST_REG;
+		op->dest.reg = rt;
+		op->dest.offset = 0;
+		break;
+	default:
+		if (!stack_related_reg(rn)) {
+			*type = INSN_OTHER;
+			return 0;
+		}
+
+		op = calloc(1, sizeof(*op));
+		list_add_tail(&op->list, ops_list);
+
+		op->dest.type = OP_DEST_REG_INDIRECT;
+		op->dest.reg = rn;
+		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, enum insn_type *type,
+				   unsigned long *immediate,
+				   struct list_head *ops_list)
+{
+	unsigned char size = 0, V = 0, opc = 0, rn = 0, rt = 0;
+	unsigned char decode_field = 0;
+	struct stack_op *op;
+	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, ops_list);
+		}
+	}
+
+	imm12 = (instr >> 10) & ONES(12);
+	rn = (instr >> 5) & ONES(5);
+	rt = instr & ONES(5);
+
+	if (!stack_related_reg(rn) || decode_field == 26) {
+		*type = INSN_OTHER;
+		return 0;
+	}
+
+	*type = INSN_STACK;
+
+	op = calloc(1, sizeof(*op));
+	list_add_tail(&op->list, ops_list);
+	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 = rn;
+		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 = rn;
+		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, enum insn_type *type,
+			      unsigned long *immediate,
+			      struct list_head *ops_list)
+{
+	unsigned char size = 0, V = 0, opc = 0;
+	unsigned char decode_field = 0;
+	struct stack_op *op;
+	struct stack_op *post_inc;
+	int base_reg;
+	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, ops_list);
+
+	ret = arm_decode_ld_st_regs_unsigned(instr, type, immediate, ops_list);
+	if (ret < 0 || *type == INSN_OTHER)
+		return ret;
+
+	op = list_first_entry(ops_list, typeof(*op), list);
+	if (op->dest.type == OP_DEST_REG_INDIRECT) {
+		base_reg = op->dest.reg;
+		op->dest.offset = 0;
+	} else if (op->src.type == OP_SRC_REG_INDIRECT) {
+		base_reg = op->src.reg;
+		op->src.offset = 0;
+	} else {
+		WARN("Cannot find stack op base");
+		return -1;
+	}
+
+	post_inc = malloc(sizeof(*post_inc));
+	post_inc->dest.type = OP_DEST_REG;
+	post_inc->dest.reg = base_reg;
+	post_inc->src.reg = base_reg;
+	post_inc->src.type = OP_SRC_ADD;
+	post_inc->src.offset = SIGN_EXTEND(imm9, 9);
+
+	list_add_tail(&post_inc->list, ops_list);
+
+	return 0;
+}
+
+int arm_decode_ld_st_imm_pre(u32 instr, enum insn_type *type,
+			     unsigned long *immediate,
+			     struct list_head *ops_list)
+{
+	unsigned char size = 0, V = 0, opc = 0;
+	unsigned char decode_field = 0;
+	struct stack_op *op;
+	struct stack_op *pre_inc;
+	int base_reg;
+	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, ops_list);
+
+	ret = arm_decode_ld_st_regs_unsigned(instr, type, immediate, ops_list);
+	if (ret < 0 || *type == INSN_OTHER)
+		return ret;
+
+	op = list_first_entry(ops_list, typeof(*op), list);
+	if (op->dest.type == OP_DEST_REG_INDIRECT) {
+		base_reg = op->dest.reg;
+		op->dest.offset = 0;
+	} else if (op->src.type == OP_SRC_REG_INDIRECT) {
+		base_reg = op->src.reg;
+		op->src.offset = 0;
+	} else {
+		WARN("Cannot find stack op base");
+		return -1;
+	}
+
+	pre_inc = malloc(sizeof(*pre_inc));
+	pre_inc->dest.type = OP_DEST_REG;
+	pre_inc->dest.reg = base_reg;
+	pre_inc->src.reg = base_reg;
+	pre_inc->src.type = OP_SRC_ADD;
+	pre_inc->src.offset = SIGN_EXTEND(imm9, 9);
+
+	list_add(&pre_inc->list, ops_list);
+
+	return 0;
+}
+
+#define LD_UNPR_UNALLOC_1 0b10011
+#define LD_UNPR_UNALLOC_2 0b11010
+int arm_decode_ld_st_imm_unpriv(u32 instr, enum insn_type *type,
+				unsigned long *immediate,
+				struct list_head *ops_list)
+{
+	unsigned char size = 0, V = 0, opc = 0, rn = 0, rt = 0;
+	unsigned char decode_field = 0;
+	struct stack_op *op;
+	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, ops_list);
+	}
+#undef LD_UNPR_UNALLOC_1
+#undef LD_UNPR_UNALLOC_2
+
+	if (!stack_related_reg(rn)) {
+		*type = INSN_OTHER;
+		return 0;
+	}
+	*type = INSN_STACK;
+	op = calloc(1, sizeof(*op));
+	list_add_tail(&op->list, ops_list);
+
+	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 = rn;
+		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 = rn;
+		op->dest.offset = SIGN_EXTEND(imm9, 9);
+		op->src.type = OP_DEST_REG;
+		op->src.reg = rt;
+		op->src.offset = 0;
+		break;
+	}
+	return 0;
+}
diff --git a/tools/objtool/arch/arm64/include/insn_decode.h b/tools/objtool/arch/arm64/include/insn_decode.h
index 6e600f408bea..1e031b12cf69 100644
--- a/tools/objtool/arch/arm64/include/insn_decode.h
+++ b/tools/objtool/arch/arm64/include/insn_decode.h
@@ -10,6 +10,10 @@
 #define INSN_UNALLOC	0b0011
 #define INSN_DP_IMM	0b1001	//0x100x
 #define INSN_SYS_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 NR_INSN_CLASS	16
 #define INSN_CLASS(opcode)	(((opcode) >> 25) & (NR_INSN_CLASS - 1))
@@ -37,6 +41,8 @@ int arm_decode_dp_imm(u32 instr, enum insn_type *type,
 		      unsigned long *immediate, struct list_head *ops_list);
 int arm_decode_br_sys(u32 instr, enum insn_type *type,
 		      unsigned long *immediate, struct list_head *ops_list);
+int arm_decode_ld_st(u32 instr, enum insn_type *type,
+		     unsigned long *immediate, struct list_head *ops_list);
 int arm_decode_unknown(u32 instr, enum insn_type *type,
 		       unsigned long *immediate, struct list_head *ops_list);
 
@@ -86,4 +92,21 @@ int arm_decode_br_cond_imm(u32 instr, enum insn_type *type,
 int arm_decode_br_uncond_reg(u32 instr, enum insn_type *type,
 			     unsigned long *immediate,
 			     struct list_head *ops_list);
+
+/* arm64 load/store instructions */
+int arm_decode_ld_st_regs_unsc_imm(u32 instr, enum insn_type *type,
+				   unsigned long *immediate,
+				   struct list_head *ops_list);
+int arm_decode_ld_st_imm_post(u32 instr, enum insn_type *type,
+			      unsigned long *immediate,
+			      struct list_head *ops_list);
+int arm_decode_ld_st_imm_unpriv(u32 instr, enum insn_type *type,
+				unsigned long *immediate,
+				struct list_head *ops_list);
+int arm_decode_ld_st_imm_pre(u32 instr, enum insn_type *type,
+			     unsigned long *immediate,
+			     struct list_head *ops_list);
+int arm_decode_ld_st_regs_unsigned(u32 instr, enum insn_type *type,
+				   unsigned long *immediate,
+				   struct list_head *ops_list);
 #endif /* _ARM_INSN_DECODE_H */
-- 
2.21.0


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

* [RFC v5 31/57] objtool: arm64: Decode load/store with register offset
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (29 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 30/57] objtool: arm64: Decode basic load/stores Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 32/57] objtool: arm64: Decode load/store register pair instructions Julien Thierry
                   ` (28 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

Decode load/store instruction using the value of a register as offset
for the target address.

Since objtool can't keep track of the possible values of this offset, it
is not possible to take this instructions into account for stack frame
validation. Luckily, the compiler does not tend to generate these
instructions for stack/frame pointer manipulation.

Suggested-by: Raphael Gault <raphael.gault@arm.com>
Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/arch/arm64/decode.c             | 34 +++++++++++++++++++
 .../objtool/arch/arm64/include/insn_decode.h  |  3 ++
 2 files changed, 37 insertions(+)

diff --git a/tools/objtool/arch/arm64/decode.c b/tools/objtool/arch/arm64/decode.c
index 7064302416f4..00d5d627af08 100644
--- a/tools/objtool/arch/arm64/decode.c
+++ b/tools/objtool/arch/arm64/decode.c
@@ -830,6 +830,11 @@ static struct aarch64_insn_decoder ld_st_decoder[] = {
 		.value = 0b001100000000011,
 		.decode_func = arm_decode_ld_st_imm_pre,
 	},
+	{
+		.mask = 0b001101010000011,
+		.value = 0b001100010000010,
+		.decode_func = arm_decode_ld_st_regs_off,
+	},
 	{
 		.mask = 0b001101000000000,
 		.value = 0b001101000000000,
@@ -1200,3 +1205,32 @@ int arm_decode_ld_st_imm_unpriv(u32 instr, enum insn_type *type,
 	}
 	return 0;
 }
+
+int arm_decode_ld_st_regs_off(u32 instr, enum insn_type *type,
+			      unsigned long *immediate,
+			      struct list_head *ops_list)
+{
+	unsigned char size = 0, V = 0, opc = 0, option = 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, ops_list);
+	}
+#undef LD_ROFF_UNALLOC_1
+#undef LD_ROFF_UNALLOC_2
+#undef LD_ROFF_UNALLOC_3
+
+	return 0;
+}
diff --git a/tools/objtool/arch/arm64/include/insn_decode.h b/tools/objtool/arch/arm64/include/insn_decode.h
index 1e031b12cf69..9043ca6f6708 100644
--- a/tools/objtool/arch/arm64/include/insn_decode.h
+++ b/tools/objtool/arch/arm64/include/insn_decode.h
@@ -106,6 +106,9 @@ int arm_decode_ld_st_imm_unpriv(u32 instr, enum insn_type *type,
 int arm_decode_ld_st_imm_pre(u32 instr, enum insn_type *type,
 			     unsigned long *immediate,
 			     struct list_head *ops_list);
+int arm_decode_ld_st_regs_off(u32 instr, enum insn_type *type,
+			      unsigned long *immediate,
+			      struct list_head *ops_list);
 int arm_decode_ld_st_regs_unsigned(u32 instr, enum insn_type *type,
 				   unsigned long *immediate,
 				   struct list_head *ops_list);
-- 
2.21.0


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

* [RFC v5 32/57] objtool: arm64: Decode load/store register pair instructions
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (30 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 31/57] objtool: arm64: Decode load/store with register offset Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 33/57] objtool: arm64: Decode FP/SIMD load/store instructions Julien Thierry
                   ` (27 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

Decode load/store instruction to a pair of registers. Split the
instruction into two stack operations, one for each register.

Suggested-by: Raphael Gault <raphael.gault@arm.com>
Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/arch/arm64/decode.c             | 220 ++++++++++++++++++
 .../objtool/arch/arm64/include/insn_decode.h  |  12 +
 2 files changed, 232 insertions(+)

diff --git a/tools/objtool/arch/arm64/decode.c b/tools/objtool/arch/arm64/decode.c
index 00d5d627af08..2aaac4e3786c 100644
--- a/tools/objtool/arch/arm64/decode.c
+++ b/tools/objtool/arch/arm64/decode.c
@@ -810,6 +810,26 @@ int arm_decode_br_uncond_reg(u32 instr, enum insn_type *type,
 #undef INSN_DRPS_MASK
 
 static struct aarch64_insn_decoder ld_st_decoder[] = {
+	{
+		.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,
@@ -1234,3 +1254,203 @@ int arm_decode_ld_st_regs_off(u32 instr, enum insn_type *type,
 
 	return 0;
 }
+
+int arm_decode_ld_st_noalloc_pair_off(u32 instr, enum insn_type *type,
+				      unsigned long *immediate,
+				      struct list_head *ops_list)
+{
+	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, ops_list);
+	}
+	return arm_decode_ld_st_regs_pair_off(instr, type, immediate, ops_list);
+}
+
+int arm_decode_ld_st_regs_pair_off(u32 instr, enum insn_type *type,
+				   unsigned long *immediate,
+				   struct list_head *ops_list)
+{
+	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;
+	struct stack_op *op;
+	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, ops_list);
+
+	*immediate = (SIGN_EXTEND(imm7, 7)) << scale;
+
+	if (!stack_related_reg(rn)) {
+		*type = INSN_OTHER;
+		return 0;
+	}
+
+	*type = INSN_STACK;
+
+	op = calloc(1, sizeof(*op));
+	list_add_tail(&op->list, ops_list);
+	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 = rn;
+		op->src.offset = *immediate;
+		op->dest.type = OP_DEST_REG;
+		op->dest.reg = rt;
+		op->dest.offset = 0;
+		{
+			struct stack_op *extra;
+
+			extra = malloc(sizeof(*extra));
+			extra->src.type = OP_SRC_REG_INDIRECT;
+			extra->src.reg = rn;
+			extra->src.offset = (int)*immediate + 8;
+			extra->dest.type = OP_DEST_REG;
+			extra->dest.reg = rt2;
+			extra->dest.offset = 0;
+
+			list_add_tail(&extra->list, ops_list);
+		}
+		break;
+	default:
+		op->dest.type = OP_DEST_REG_INDIRECT;
+		op->dest.reg = rn;
+		op->dest.offset = (int)*immediate + 8;
+		op->src.type = OP_SRC_REG;
+		op->src.reg = rt2;
+		op->src.offset = 0;
+		{
+			struct stack_op *extra;
+
+			extra = malloc(sizeof(*extra));
+			extra->dest.type = OP_DEST_REG_INDIRECT;
+			extra->dest.reg = rn;
+			extra->dest.offset = *immediate;
+			extra->src.type = OP_SRC_REG;
+			extra->src.reg = rt;
+			extra->src.offset = 0;
+
+			list_add_tail(&extra->list, ops_list);
+		}
+		/* store */
+	}
+	return 0;
+}
+
+int arm_decode_ld_st_regs_pair_post(u32 instr, enum insn_type *type,
+				    unsigned long *immediate,
+				    struct list_head *ops_list)
+{
+	int ret = 0;
+	unsigned int base_reg;
+	bool base_is_src;
+	struct stack_op *op;
+	struct stack_op *post_inc;
+
+	ret = arm_decode_ld_st_regs_pair_off(instr, type, immediate, ops_list);
+	if (ret < 0 || *type == INSN_OTHER)
+		return ret;
+
+	op = list_first_entry(ops_list, typeof(*op), list);
+	if (op->dest.type == OP_DEST_REG_INDIRECT) {
+		base_reg = op->dest.reg;
+		base_is_src = false;
+	} else if (op->src.type == OP_SRC_REG_INDIRECT) {
+		base_reg = op->src.reg;
+		base_is_src = true;
+	} else {
+		WARN("Unexpected base type");
+		return -1;
+	}
+
+	post_inc = malloc(sizeof(*post_inc));
+	post_inc->dest.type = OP_DEST_REG;
+	post_inc->dest.reg = base_reg;
+	post_inc->src.reg = base_reg;
+	post_inc->src.type = OP_SRC_ADD;
+	post_inc->src.offset = (int)*immediate;
+
+	/* Adapt offsets */
+	list_for_each_entry(op, ops_list, list) {
+		if (!base_is_src)
+			op->dest.offset -= post_inc->src.offset;
+		else
+			op->src.offset -= post_inc->src.offset;
+	}
+	list_add_tail(&post_inc->list, ops_list);
+
+	return ret;
+}
+
+int arm_decode_ld_st_regs_pair_pre(u32 instr, enum insn_type *type,
+				   unsigned long *immediate,
+				   struct list_head *ops_list)
+{
+	int ret = 0;
+	unsigned int base_reg;
+	bool base_is_src;
+	struct stack_op *op;
+	struct stack_op *pre_inc;
+
+	ret = arm_decode_ld_st_regs_pair_off(instr, type, immediate, ops_list);
+	if (ret < 0 || *type == INSN_OTHER)
+		return ret;
+
+	op = list_first_entry(ops_list, typeof(*op), list);
+	if (op->dest.type == OP_DEST_REG_INDIRECT) {
+		base_reg = op->dest.reg;
+		base_is_src = false;
+	} else if (op->src.type == OP_SRC_REG_INDIRECT) {
+		base_reg = op->src.reg;
+		base_is_src = true;
+	} else {
+		WARN("Unexpected base type");
+		return -1;
+	}
+
+	pre_inc = malloc(sizeof(*pre_inc));
+	pre_inc->dest.type = OP_DEST_REG;
+	pre_inc->dest.reg = base_reg;
+	pre_inc->src.type = OP_SRC_ADD;
+	pre_inc->src.reg = base_reg;
+	pre_inc->src.offset = (int)*immediate;
+
+	/* Adapt offsets */
+	list_for_each_entry(op, ops_list, list) {
+		if (!base_is_src)
+			op->dest.offset -= pre_inc->src.offset;
+		else
+			op->src.offset -= pre_inc->src.offset;
+	}
+	list_add(&pre_inc->list, ops_list);
+
+	return 0;
+}
diff --git a/tools/objtool/arch/arm64/include/insn_decode.h b/tools/objtool/arch/arm64/include/insn_decode.h
index 9043ca6f6708..caeb40942b18 100644
--- a/tools/objtool/arch/arm64/include/insn_decode.h
+++ b/tools/objtool/arch/arm64/include/insn_decode.h
@@ -94,6 +94,18 @@ int arm_decode_br_uncond_reg(u32 instr, enum insn_type *type,
 			     struct list_head *ops_list);
 
 /* arm64 load/store instructions */
+int arm_decode_ld_st_noalloc_pair_off(u32 instr, enum insn_type *type,
+				      unsigned long *immediate,
+				      struct list_head *ops_list);
+int arm_decode_ld_st_regs_pair_post(u32 instr, enum insn_type *type,
+				    unsigned long *immediate,
+				    struct list_head *ops_list);
+int arm_decode_ld_st_regs_pair_off(u32 instr, enum insn_type *type,
+				   unsigned long *immediate,
+				   struct list_head *ops_list);
+int arm_decode_ld_st_regs_pair_pre(u32 instr, enum insn_type *type,
+				   unsigned long *immediate,
+				   struct list_head *ops_list);
 int arm_decode_ld_st_regs_unsc_imm(u32 instr, enum insn_type *type,
 				   unsigned long *immediate,
 				   struct list_head *ops_list);
-- 
2.21.0


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

* [RFC v5 33/57] objtool: arm64: Decode FP/SIMD load/store instructions
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (31 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 32/57] objtool: arm64: Decode load/store register pair instructions Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 34/57] objtool: arm64: Decode load/store exclusive Julien Thierry
                   ` (26 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

Decode load/store instruction acting on floating point and SIMD
registers.

Suggested-by: Raphael Gault <raphael.gault@arm.com>
Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/arch/arm64/decode.c             | 301 ++++++++++++++++++
 .../objtool/arch/arm64/include/insn_decode.h  |  12 +
 2 files changed, 313 insertions(+)

diff --git a/tools/objtool/arch/arm64/decode.c b/tools/objtool/arch/arm64/decode.c
index 2aaac4e3786c..7d480efe0bc2 100644
--- a/tools/objtool/arch/arm64/decode.c
+++ b/tools/objtool/arch/arm64/decode.c
@@ -810,6 +810,26 @@ int arm_decode_br_uncond_reg(u32 instr, enum insn_type *type,
 #undef INSN_DRPS_MASK
 
 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 = 0b001101100000000,
 		.value = 0b001000000000000,
@@ -889,6 +909,287 @@ int arm_decode_ld_st(u32 instr, enum insn_type *type,
 	return arm_decode_unknown(instr, type, immediate, ops_list);
 }
 
+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, enum insn_type *type,
+			     unsigned long *immediate,
+			     struct list_head *ops_list)
+{
+	unsigned char L = 0, opcode = 0, rn = 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);
+	*type = INSN_OTHER;
+
+	for (i = 0; i < ARRAY_SIZE(adv_simd_mult_fields); i++) {
+		if ((decode_field & 0b11111) == adv_simd_mult_fields[i]) {
+			if (!stack_related_reg(rn))
+				return 0;
+		}
+	}
+
+	return arm_decode_unknown(instr, type, immediate, ops_list);
+}
+
+int arm_decode_adv_simd_mult_post(u32 instr, enum insn_type *type,
+				  unsigned long *immediate,
+				  struct list_head *ops_list)
+{
+	/* same opcode as for the no offset variant */
+	int ret = 0;
+
+	ret = arm_decode_adv_simd_mult(instr, type, immediate, ops_list);
+
+	/* TODO: Create stack_op for post increment with immediate */
+	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, enum insn_type *type,
+			       unsigned long *immediate,
+			       struct list_head *ops_list)
+{
+	unsigned char L = 0, R = 0, S = 0, opcode = 0, size = 0;
+	unsigned char rn = 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 (!stack_related_reg(rn))
+				return 0;
+		}
+	}
+
+	return arm_decode_unknown(instr, type, immediate, ops_list);
+}
+
+int arm_decode_adv_simd_single_post(u32 instr, enum insn_type *type,
+				    unsigned long *immediate,
+				    struct list_head *ops_list)
+{
+	/* same opcode as for the no offset variant */
+	int ret = 0;
+
+	ret = arm_decode_adv_simd_single(instr, type, immediate, ops_list);
+
+	/* TODO: Create stack_op for post increment with immediate */
+	return ret;
+}
+
 int arm_decode_ld_st_regs_unsc_imm(u32 instr, enum insn_type *type,
 				   unsigned long *immediate,
 				   struct list_head *ops_list)
diff --git a/tools/objtool/arch/arm64/include/insn_decode.h b/tools/objtool/arch/arm64/include/insn_decode.h
index caeb40942b18..7fd333f88612 100644
--- a/tools/objtool/arch/arm64/include/insn_decode.h
+++ b/tools/objtool/arch/arm64/include/insn_decode.h
@@ -94,6 +94,18 @@ int arm_decode_br_uncond_reg(u32 instr, enum insn_type *type,
 			     struct list_head *ops_list);
 
 /* arm64 load/store instructions */
+int arm_decode_adv_simd_mult(u32 instr, enum insn_type *type,
+			     unsigned long *immediate,
+			     struct list_head *ops_list);
+int arm_decode_adv_simd_mult_post(u32 instr, enum insn_type *type,
+				  unsigned long *immediate,
+				  struct list_head *ops_list);
+int arm_decode_adv_simd_single(u32 instr, enum insn_type *type,
+			       unsigned long *immediate,
+			       struct list_head *ops_list);
+int arm_decode_adv_simd_single_post(u32 instr, enum insn_type *type,
+				    unsigned long *immediate,
+				    struct list_head *ops_list);
 int arm_decode_ld_st_noalloc_pair_off(u32 instr, enum insn_type *type,
 				      unsigned long *immediate,
 				      struct list_head *ops_list);
-- 
2.21.0


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

* [RFC v5 34/57] objtool: arm64: Decode load/store exclusive
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (32 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 33/57] objtool: arm64: Decode FP/SIMD load/store instructions Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 35/57] objtool: arm64: Decode atomic load/store Julien Thierry
                   ` (25 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

Decode load/store exclusive instructions. From objtool's point
of view there aren't particular semantics to these operations.

Suggested-by: Raphael Gault <raphael.gault@arm.com>
Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/arch/arm64/decode.c             | 140 ++++++++++++++++++
 .../objtool/arch/arm64/include/insn_decode.h  |   3 +
 2 files changed, 143 insertions(+)

diff --git a/tools/objtool/arch/arm64/decode.c b/tools/objtool/arch/arm64/decode.c
index 7d480efe0bc2..e3f77d68b282 100644
--- a/tools/objtool/arch/arm64/decode.c
+++ b/tools/objtool/arch/arm64/decode.c
@@ -830,6 +830,11 @@ static struct aarch64_insn_decoder ld_st_decoder[] = {
 		.value = 0b000011100000000,
 		.decode_func = arm_decode_adv_simd_single_post,
 	},
+	{
+		.mask = 0b001111000000000,
+		.value = 0b000000000000000,
+		.decode_func = arm_decode_ld_st_exclusive,
+	},
 	{
 		.mask = 0b001101100000000,
 		.value = 0b001000000000000,
@@ -1190,6 +1195,141 @@ int arm_decode_adv_simd_single_post(u32 instr, enum insn_type *type,
 	return ret;
 }
 
+#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, enum insn_type *type,
+			       unsigned long *immediate,
+			       struct list_head *ops_list)
+{
+	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;
+	struct stack_op *op;
+	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,
+						  ops_list);
+	}
+
+	if (!stack_related_reg(rn)) {
+		*type = INSN_OTHER;
+		return 0;
+	}
+
+	*type = INSN_STACK;
+	op = calloc(1, sizeof(*op));
+	list_add_tail(&op->list, ops_list);
+
+	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 = rn;
+			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 = rn;
+	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_ld_st_regs_unsc_imm(u32 instr, enum insn_type *type,
 				   unsigned long *immediate,
 				   struct list_head *ops_list)
diff --git a/tools/objtool/arch/arm64/include/insn_decode.h b/tools/objtool/arch/arm64/include/insn_decode.h
index 7fd333f88612..61152b4aa42a 100644
--- a/tools/objtool/arch/arm64/include/insn_decode.h
+++ b/tools/objtool/arch/arm64/include/insn_decode.h
@@ -136,4 +136,7 @@ int arm_decode_ld_st_regs_off(u32 instr, enum insn_type *type,
 int arm_decode_ld_st_regs_unsigned(u32 instr, enum insn_type *type,
 				   unsigned long *immediate,
 				   struct list_head *ops_list);
+int arm_decode_ld_st_exclusive(u32 instr, enum insn_type *type,
+			       unsigned long *immediate,
+			       struct list_head *ops_list);
 #endif /* _ARM_INSN_DECODE_H */
-- 
2.21.0


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

* [RFC v5 35/57] objtool: arm64: Decode atomic load/store
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (33 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 34/57] objtool: arm64: Decode load/store exclusive Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 36/57] objtool: arm64: Decode pointer auth load instructions Julien Thierry
                   ` (24 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

Decode v8.1 atomic load/store instructions.

Suggested-by: Raphael Gault <raphael.gault@arm.com>
Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/arch/arm64/decode.c             | 86 +++++++++++++++++++
 .../objtool/arch/arm64/include/insn_decode.h  |  2 +
 2 files changed, 88 insertions(+)

diff --git a/tools/objtool/arch/arm64/decode.c b/tools/objtool/arch/arm64/decode.c
index e3f77d68b282..1897f62987fa 100644
--- a/tools/objtool/arch/arm64/decode.c
+++ b/tools/objtool/arch/arm64/decode.c
@@ -875,6 +875,11 @@ static struct aarch64_insn_decoder ld_st_decoder[] = {
 		.value = 0b001100000000011,
 		.decode_func = arm_decode_ld_st_imm_pre,
 	},
+	{
+		.mask = 0b001101010000011,
+		.value = 0b001100010000000,
+		.decode_func = arm_decode_atomic,
+	},
 	{
 		.mask = 0b001101010000011,
 		.value = 0b001100010000010,
@@ -1667,6 +1672,87 @@ int arm_decode_ld_st_imm_unpriv(u32 instr, enum insn_type *type,
 	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, enum insn_type *type,
+		      unsigned long *immediate,
+		      struct list_head *ops_list)
+{
+	unsigned char V = 0, A = 0, R = 0, o3 = 0, opc = 0;
+	unsigned char rn = 0, rt = 0;
+	unsigned char decode_field = 0;
+	struct stack_op *op;
+	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,
+						  ops_list);
+		}
+	}
+
+	rn = (instr >> 5) & ONES(5);
+	rt = instr & ONES(5);
+
+	if (!stack_related_reg(rn)) {
+		*type = INSN_OTHER;
+		return 0;
+	}
+	*type = INSN_STACK;
+
+	op = calloc(1, sizeof(*op));
+	list_add_tail(&op->list, ops_list);
+
+	op->src.reg = rn;
+	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, enum insn_type *type,
 			      unsigned long *immediate,
 			      struct list_head *ops_list)
diff --git a/tools/objtool/arch/arm64/include/insn_decode.h b/tools/objtool/arch/arm64/include/insn_decode.h
index 61152b4aa42a..89488c5df5e9 100644
--- a/tools/objtool/arch/arm64/include/insn_decode.h
+++ b/tools/objtool/arch/arm64/include/insn_decode.h
@@ -130,6 +130,8 @@ int arm_decode_ld_st_imm_unpriv(u32 instr, enum insn_type *type,
 int arm_decode_ld_st_imm_pre(u32 instr, enum insn_type *type,
 			     unsigned long *immediate,
 			     struct list_head *ops_list);
+int arm_decode_atomic(u32 instr, enum insn_type *type,
+		      unsigned long *immediate, struct list_head *ops_list);
 int arm_decode_ld_st_regs_off(u32 instr, enum insn_type *type,
 			      unsigned long *immediate,
 			      struct list_head *ops_list);
-- 
2.21.0


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

* [RFC v5 36/57] objtool: arm64: Decode pointer auth load instructions
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (34 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 35/57] objtool: arm64: Decode atomic load/store Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 37/57] objtool: arm64: Decode load acquire/store release Julien Thierry
                   ` (23 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

Decode load/store instruction provided by the v8.3 pointer
authentication architecture extension.

Suggested-by: Raphael Gault <raphael.gault@arm.com>
Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/arch/arm64/decode.c             | 51 +++++++++++++++++++
 .../objtool/arch/arm64/include/insn_decode.h  |  3 ++
 2 files changed, 54 insertions(+)

diff --git a/tools/objtool/arch/arm64/decode.c b/tools/objtool/arch/arm64/decode.c
index 1897f62987fa..0bbbacd74e48 100644
--- a/tools/objtool/arch/arm64/decode.c
+++ b/tools/objtool/arch/arm64/decode.c
@@ -885,6 +885,11 @@ static struct aarch64_insn_decoder ld_st_decoder[] = {
 		.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,
@@ -1981,3 +1986,49 @@ int arm_decode_ld_st_regs_pair_pre(u32 instr, enum insn_type *type,
 
 	return 0;
 }
+
+int arm_decode_ld_st_regs_pac(u32 instr, enum insn_type *type,
+			      unsigned long *immediate,
+			      struct list_head *ops_list)
+{
+	unsigned char size = 0, V = 0, W = 0, S = 0;
+	unsigned char rn = 0, rt = 0;
+	struct stack_op *op;
+	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, ops_list);
+
+	rn = (instr >> 5) & ONES(5);
+
+	if (!stack_related_reg(rn)) {
+		*type = INSN_OTHER;
+		return 0;
+	}
+
+	S = EXTRACT_BIT(instr, 22);
+	s10 = (S << 9) | imm9;
+
+	*type = INSN_STACK;
+
+	op = calloc(1, sizeof(*op));
+	list_add_tail(&op->list, ops_list);
+
+	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 = rn;
+	} else {
+		op->src.type = OP_SRC_REG_INDIRECT;
+		op->src.reg = rn;
+	}
+
+	return 0;
+}
diff --git a/tools/objtool/arch/arm64/include/insn_decode.h b/tools/objtool/arch/arm64/include/insn_decode.h
index 89488c5df5e9..d819d2e795a3 100644
--- a/tools/objtool/arch/arm64/include/insn_decode.h
+++ b/tools/objtool/arch/arm64/include/insn_decode.h
@@ -135,6 +135,9 @@ int arm_decode_atomic(u32 instr, enum insn_type *type,
 int arm_decode_ld_st_regs_off(u32 instr, enum insn_type *type,
 			      unsigned long *immediate,
 			      struct list_head *ops_list);
+int arm_decode_ld_st_regs_pac(u32 instr, enum insn_type *type,
+			      unsigned long *immediate,
+			      struct list_head *ops_list);
 int arm_decode_ld_st_regs_unsigned(u32 instr, enum insn_type *type,
 				   unsigned long *immediate,
 				   struct list_head *ops_list);
-- 
2.21.0


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

* [RFC v5 37/57] objtool: arm64: Decode load acquire/store release
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (35 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 36/57] objtool: arm64: Decode pointer auth load instructions Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 38/57] objtool: arm64: Decode load/store with memory tag Julien Thierry
                   ` (22 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

Decode load/store instructions provided by the v8.4 RCPC architecture
extension.

Suggested-by: Raphael Gault <raphael.gault@arm.com>
Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/arch/arm64/decode.c             | 68 +++++++++++++++++++
 .../objtool/arch/arm64/include/insn_decode.h  |  3 +
 2 files changed, 71 insertions(+)

diff --git a/tools/objtool/arch/arm64/decode.c b/tools/objtool/arch/arm64/decode.c
index 0bbbacd74e48..becc563345dd 100644
--- a/tools/objtool/arch/arm64/decode.c
+++ b/tools/objtool/arch/arm64/decode.c
@@ -835,6 +835,11 @@ static struct aarch64_insn_decoder ld_st_decoder[] = {
 		.value = 0b000000000000000,
 		.decode_func = arm_decode_ld_st_exclusive,
 	},
+	{
+		.mask = 0b001111010000011,
+		.value = 0b000101000000000,
+		.decode_func = arm_decode_ldapr_stlr_unsc_imm,
+	},
 	{
 		.mask = 0b001101100000000,
 		.value = 0b001000000000000,
@@ -2032,3 +2037,66 @@ int arm_decode_ld_st_regs_pac(u32 instr, enum insn_type *type,
 
 	return 0;
 }
+
+int arm_decode_ldapr_stlr_unsc_imm(u32 instr, enum insn_type *type,
+				   unsigned long *immediate,
+				   struct list_head *ops_list)
+{
+	u32 imm9 = 0;
+	unsigned char size = 0, opc = 0, rn = 0, rt = 0, decode_field = 0;
+	struct stack_op *op;
+
+	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, ops_list);
+	}
+
+	if (!stack_related_reg(rn)) {
+		*type = INSN_OTHER;
+		return 0;
+	}
+	*type = INSN_STACK;
+	*immediate = imm9;
+
+	op = calloc(1, sizeof(*op));
+	list_add_tail(&op->list, ops_list);
+
+	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 = rn;
+		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 = rn;
+		op->dest.offset = SIGN_EXTEND(imm9, 9);
+		op->src.type = OP_SRC_REG;
+		op->src.reg = rt;
+		op->src.offset = 0;
+		break;
+	}
+
+	return 0;
+}
diff --git a/tools/objtool/arch/arm64/include/insn_decode.h b/tools/objtool/arch/arm64/include/insn_decode.h
index d819d2e795a3..1721d9c487d0 100644
--- a/tools/objtool/arch/arm64/include/insn_decode.h
+++ b/tools/objtool/arch/arm64/include/insn_decode.h
@@ -106,6 +106,9 @@ int arm_decode_adv_simd_single(u32 instr, enum insn_type *type,
 int arm_decode_adv_simd_single_post(u32 instr, enum insn_type *type,
 				    unsigned long *immediate,
 				    struct list_head *ops_list);
+int arm_decode_ldapr_stlr_unsc_imm(u32 instr, enum insn_type *type,
+				   unsigned long *immediate,
+				   struct list_head *ops_list);
 int arm_decode_ld_st_noalloc_pair_off(u32 instr, enum insn_type *type,
 				      unsigned long *immediate,
 				      struct list_head *ops_list);
-- 
2.21.0


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

* [RFC v5 38/57] objtool: arm64: Decode load/store with memory tag
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (36 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 37/57] objtool: arm64: Decode load acquire/store release Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 39/57] objtool: arm64: Decode load literal Julien Thierry
                   ` (21 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

Decode load/store instructions provided by the v8.5 memorty tagging
architecture extension.

Suggested-by: Raphael Gault <raphael.gault@arm.com>
Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/arch/arm64/decode.c             | 87 +++++++++++++++++++
 .../objtool/arch/arm64/include/insn_decode.h  |  3 +
 2 files changed, 90 insertions(+)

diff --git a/tools/objtool/arch/arm64/decode.c b/tools/objtool/arch/arm64/decode.c
index becc563345dd..bc4c62401012 100644
--- a/tools/objtool/arch/arm64/decode.c
+++ b/tools/objtool/arch/arm64/decode.c
@@ -830,6 +830,11 @@ static struct aarch64_insn_decoder ld_st_decoder[] = {
 		.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,
@@ -2100,3 +2105,85 @@ int arm_decode_ldapr_stlr_unsc_imm(u32 instr, enum insn_type *type,
 
 	return 0;
 }
+
+int arm_decode_ld_st_mem_tags(u32 instr, enum insn_type *type,
+			      unsigned long *immediate,
+			      struct list_head *ops_list)
+{
+	u32 imm9 = 0;
+	unsigned char opc = 0, op2 = 0, rn = 0, rt = 0, decode_field = 0;
+	struct stack_op *op;
+
+	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, ops_list);
+	}
+
+	if (!stack_related_reg(rn)) {
+		*type = INSN_OTHER;
+		return 0;
+	}
+	*type = INSN_STACK;
+	*immediate = imm9;
+
+	op = calloc(1, sizeof(*op));
+	list_add_tail(&op->list, ops_list);
+
+	/*
+	 * 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 = rn;
+		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 = rn;
+		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 = rn;
+		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;
+}
diff --git a/tools/objtool/arch/arm64/include/insn_decode.h b/tools/objtool/arch/arm64/include/insn_decode.h
index 1721d9c487d0..e6a62691b487 100644
--- a/tools/objtool/arch/arm64/include/insn_decode.h
+++ b/tools/objtool/arch/arm64/include/insn_decode.h
@@ -106,6 +106,9 @@ int arm_decode_adv_simd_single(u32 instr, enum insn_type *type,
 int arm_decode_adv_simd_single_post(u32 instr, enum insn_type *type,
 				    unsigned long *immediate,
 				    struct list_head *ops_list);
+int arm_decode_ld_st_mem_tags(u32 instr, enum insn_type *type,
+			      unsigned long *immediate,
+			      struct list_head *ops_list);
 int arm_decode_ldapr_stlr_unsc_imm(u32 instr, enum insn_type *type,
 				   unsigned long *immediate,
 				   struct list_head *ops_list);
-- 
2.21.0


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

* [RFC v5 39/57] objtool: arm64: Decode load literal
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (37 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 38/57] objtool: arm64: Decode load/store with memory tag Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 40/57] objtool: arm64: Decode register data processing instructions Julien Thierry
                   ` (20 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

Decode load literal instruction.

Aarch64 load literal is a pseudo-instruction (part of the instruction
set) that allows to load literal values may cannot be encoded within
a single instruction. The GNU assembler implementation of the pseudo
instruction generates constant data within the same section as the
pseudo-instruction itself.

That data could very well be a valid opcode (e.g. jump, return,
stack operation, etc) which confuses objtool.

Mark the "instructions" corresponding to load literal offsets as
invalid as they should never be reach by the execution flow.

Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/arch.h                          |  3 +
 tools/objtool/arch/arm64/decode.c             | 88 +++++++++++++++++++
 .../objtool/arch/arm64/include/insn_decode.h  |  3 +
 tools/objtool/arch/x86/decode.c               |  5 ++
 tools/objtool/check.c                         |  3 +
 5 files changed, 102 insertions(+)

diff --git a/tools/objtool/arch.h b/tools/objtool/arch.h
index 0336efecb9d9..829d6d73aec6 100644
--- a/tools/objtool/arch.h
+++ b/tools/objtool/arch.h
@@ -68,6 +68,7 @@ struct stack_op {
 	struct list_head list;
 };
 
+struct objtool_file;
 struct instruction;
 
 void arch_initial_func_cfi_state(struct cfi_state *state);
@@ -78,6 +79,8 @@ int arch_decode_instruction(struct elf *elf, struct section *sec,
 			    unsigned long *immediate,
 			    struct list_head *ops_list);
 
+int arch_post_process_file(struct objtool_file *file);
+
 bool arch_callee_saved_reg(unsigned char reg);
 
 unsigned long arch_jump_destination(struct instruction *insn);
diff --git a/tools/objtool/arch/arm64/decode.c b/tools/objtool/arch/arm64/decode.c
index bc4c62401012..aed8ba0f812e 100644
--- a/tools/objtool/arch/arm64/decode.c
+++ b/tools/objtool/arch/arm64/decode.c
@@ -18,6 +18,47 @@ static bool stack_related_reg(int reg)
 	return reg == CFI_SP || reg == CFI_BP;
 }
 
+struct insn_loc {
+	struct section *sec;
+	unsigned long offset;
+	struct hlist_node hnode;
+};
+
+DEFINE_HASHTABLE(text_constants, 16);
+
+int arch_post_process_file(struct objtool_file *file)
+{
+	struct hlist_node *tmp;
+	struct insn_loc *loc;
+	unsigned int bkt;
+	int res = 0;
+
+	/*
+	 * Data placed in code sections could turn out to be a valid aarch64
+	 * opcode.
+	 * If that is the case, change the insn type to invalid as it should
+	 * never be reached by the execution flow.
+	 */
+	hash_for_each_safe(text_constants, bkt, tmp, loc, hnode) {
+		struct instruction *insn;
+
+		insn = find_insn(file, loc->sec, loc->offset);
+		if (insn) {
+			insn->type = INSN_INVALID;
+		} else {
+			WARN("failed to find constant at %s+0x%lx",
+			     loc->sec->name, loc->offset);
+			res = -1;
+		}
+		hash_del(&loc->hnode);
+		free(loc);
+	}
+
+	return res;
+}
+
+static struct insn_loc current_location;
+
 bool arch_callee_saved_reg(unsigned char reg)
 {
 	switch (reg) {
@@ -127,6 +168,8 @@ int arch_decode_instruction(struct elf *elf, struct section *sec,
 	//retrieve instruction (from sec->data->offset)
 	insn = *(u32 *)(sec->data->d_buf + offset);
 
+	current_location.sec = sec;
+	current_location.offset = offset;
 	//dispatch according to encoding classes
 	decode_fun = aarch64_insn_class_decode_table[INSN_CLASS(insn)];
 	if (decode_fun)
@@ -136,6 +179,9 @@ int arch_decode_instruction(struct elf *elf, struct section *sec,
 
 	if (res)
 		WARN_FUNC("Unsupported instruction", sec, offset);
+
+	memset(&current_location, 0, sizeof(current_location));
+
 	return res;
 }
 
@@ -845,6 +891,11 @@ static struct aarch64_insn_decoder ld_st_decoder[] = {
 		.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,
@@ -1350,6 +1401,43 @@ int arm_decode_ld_st_exclusive(u32 instr, enum insn_type *type,
 #undef LDLAR_64
 #undef LDAR_64
 
+int arm_decode_ld_regs_literal(u32 instr, enum insn_type *type,
+			       unsigned long *immediate,
+			       struct list_head *ops_list)
+{
+	unsigned char opc = 0, V = 0;
+	long pc_offset;
+	struct insn_loc *loc;
+
+	opc = (instr >> 30) & ONES(2);
+	V = EXTRACT_BIT(instr, 26);
+
+	if (((opc << 1) | V) == 0x7)
+		return arm_decode_unknown(instr, type, immediate, ops_list);
+
+	pc_offset = instr & GENMASK(23, 5);
+
+	/* Sign extend and multiply by 4 */
+	pc_offset = (pc_offset << (64 - 23));
+	pc_offset = ((pc_offset >> (64 - 23)) >> 5) << 2;
+
+	loc = malloc(sizeof(*loc));
+	loc->sec = current_location.sec;
+	loc->offset = current_location.offset + pc_offset;
+	hash_add(text_constants, &loc->hnode, loc->offset);
+
+	/* 64-bit literal */
+	if (opc & 1) {
+		loc = malloc(sizeof(*loc));
+		loc->sec = current_location.sec;
+		loc->offset = current_location.offset + pc_offset + 4;
+		hash_add(text_constants, &loc->hnode, loc->offset);
+	}
+
+	*type = INSN_OTHER;
+	return 0;
+}
+
 int arm_decode_ld_st_regs_unsc_imm(u32 instr, enum insn_type *type,
 				   unsigned long *immediate,
 				   struct list_head *ops_list)
diff --git a/tools/objtool/arch/arm64/include/insn_decode.h b/tools/objtool/arch/arm64/include/insn_decode.h
index e6a62691b487..3ec4c69547ac 100644
--- a/tools/objtool/arch/arm64/include/insn_decode.h
+++ b/tools/objtool/arch/arm64/include/insn_decode.h
@@ -112,6 +112,9 @@ int arm_decode_ld_st_mem_tags(u32 instr, enum insn_type *type,
 int arm_decode_ldapr_stlr_unsc_imm(u32 instr, enum insn_type *type,
 				   unsigned long *immediate,
 				   struct list_head *ops_list);
+int arm_decode_ld_regs_literal(u32 instr, enum insn_type *type,
+			       unsigned long *immediate,
+			       struct list_head *ops_list);
 int arm_decode_ld_st_noalloc_pair_off(u32 instr, enum insn_type *type,
 				      unsigned long *immediate,
 				      struct list_head *ops_list);
diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c
index 650e5d021486..57a5f817a63c 100644
--- a/tools/objtool/arch/x86/decode.c
+++ b/tools/objtool/arch/x86/decode.c
@@ -497,6 +497,11 @@ int arch_decode_instruction(struct elf *elf, struct section *sec,
 	return 0;
 }
 
+int arch_post_process_file(struct objtool_file *file)
+{
+	return 0;
+}
+
 void arch_initial_func_cfi_state(struct cfi_state *state)
 {
 	int i;
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 52a8e64e15ca..e0c6bda261c8 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -279,6 +279,9 @@ static int decode_instructions(struct objtool_file *file)
 		}
 	}
 
+	if (arch_post_process_file(file))
+		return -1;
+
 	return 0;
 
 err:
-- 
2.21.0


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

* [RFC v5 40/57] objtool: arm64: Decode register data processing instructions
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (38 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 39/57] objtool: arm64: Decode load literal Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 41/57] objtool: arm64: Decode FP/SIMD " Julien Thierry
                   ` (19 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

Decode data processing instructions with more than one register as
input operand.
Due to these multiple register inputs, objtool cannot rely on those
instructions to track the CFA state. Luckily, the compiler does not tend
to generate these instructions to modify the stack or frame pointer.

Suggested-by: Raphael Gault <raphael.gault@arm.com>
Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/arch/arm64/decode.c             | 471 ++++++++++++++++++
 .../objtool/arch/arm64/include/insn_decode.h  |  42 ++
 2 files changed, 513 insertions(+)

diff --git a/tools/objtool/arch/arm64/decode.c b/tools/objtool/arch/arm64/decode.c
index aed8ba0f812e..bb1ba3b0997f 100644
--- a/tools/objtool/arch/arm64/decode.c
+++ b/tools/objtool/arch/arm64/decode.c
@@ -128,10 +128,12 @@ static arm_decode_class aarch64_insn_class_decode_table[NR_INSN_CLASS] = {
 	[INSN_UNKNOWN]			= arm_decode_unknown,
 	[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,
 	[0b1000 ... INSN_DP_IMM]	= arm_decode_dp_imm,
 	[0b1010 ... INSN_SYS_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,
 };
 
@@ -2275,3 +2277,472 @@ int arm_decode_ld_st_mem_tags(u32 instr, enum insn_type *type,
 
 	return -1;
 }
+
+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, enum insn_type *type,
+		      unsigned long *immediate, struct list_head *ops_list)
+{
+	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, ops_list);
+		}
+	}
+	return arm_decode_unknown(instr, type, immediate, ops_list);
+}
+
+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,
+	},
+};
+
+int arm_decode_dp_reg_2src(u32 instr, enum insn_type *type,
+			   unsigned long *immediate, struct list_head *ops_list)
+{
+	unsigned char sf = 0, S = 0, opcode = 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,
+						  ops_list);
+		}
+	}
+
+	*type = INSN_OTHER;
+	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, enum insn_type *type,
+			   unsigned long *immediate, struct list_head *ops_list)
+{
+	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,
+						  ops_list);
+		}
+	}
+	*type = INSN_OTHER;
+	return 0;
+}
+
+int arm_decode_dp_reg_logi(u32 instr, enum insn_type *type,
+			   unsigned long *immediate, struct list_head *ops_list)
+{
+	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, ops_list);
+
+	*type = INSN_OTHER;
+	return 0;
+}
+
+int arm_decode_dp_reg_adds(u32 instr, enum insn_type *type,
+			   unsigned long *immediate, struct list_head *ops_list)
+{
+	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, ops_list);
+
+	*type = INSN_OTHER;
+	return 0;
+}
+
+int arm_decode_dp_reg_adde(u32 instr, enum insn_type *type,
+			   unsigned long *immediate, struct list_head *ops_list)
+{
+	unsigned char opt = 0, imm3 = 0;
+
+	opt = (instr >> 22) & ONES(2);
+	imm3 = (instr >> 10) & ONES(3);
+
+	if (opt != 0 || imm3 >= 0b101)
+		return arm_decode_unknown(instr, type, immediate, ops_list);
+
+	*type = INSN_OTHER;
+	return 0;
+}
+
+int arm_decode_dp_reg_addc(u32 instr, enum insn_type *type,
+			   unsigned long *immediate, struct list_head *ops_list)
+{
+	*type = INSN_OTHER;
+	return 0;
+}
+
+int arm_decode_dp_reg_rota(u32 instr, enum insn_type *type,
+			   unsigned long *immediate, struct list_head *ops_list)
+{
+	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, ops_list);
+
+	*type = INSN_OTHER;
+	return 0;
+}
+
+int arm_decode_dp_reg_eval(u32 instr, enum insn_type *type,
+			   unsigned long *immediate, struct list_head *ops_list)
+{
+	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, ops_list);
+	}
+
+	*type = INSN_OTHER;
+	return 0;
+#undef DP_EVAL_SETF_1
+#undef DP_EVAL_SETF_2
+}
+
+int arm_decode_dp_reg_cmpr(u32 instr, enum insn_type *type,
+			   unsigned long *immediate, struct list_head *ops_list)
+{
+	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, ops_list);
+
+	*type = INSN_OTHER;
+	return 0;
+}
+
+int arm_decode_dp_reg_csel(u32 instr, enum insn_type *type,
+			   unsigned long *immediate, struct list_head *ops_list)
+{
+	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, ops_list);
+
+	*type = INSN_OTHER;
+	return 0;
+}
+
+int arm_decode_dp_reg_cmpi(u32 instr, enum insn_type *type,
+			   unsigned long *immediate, struct list_head *ops_list)
+{
+	return arm_decode_dp_reg_cmpr(instr, type, immediate, ops_list);
+}
+
+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, enum insn_type *type,
+			   unsigned long *immediate, struct list_head *ops_list)
+{
+	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_decoder); i++) {
+		if ((decode_field & dp_reg_3src_decoder[i].mask) ==
+		    dp_reg_3src_decoder[i].value) {
+			return arm_decode_unknown(instr, type, immediate,
+						  ops_list);
+		}
+	}
+
+	*type = INSN_OTHER;
+	return 0;
+}
diff --git a/tools/objtool/arch/arm64/include/insn_decode.h b/tools/objtool/arch/arm64/include/insn_decode.h
index 3ec4c69547ac..8fb2f2b7564f 100644
--- a/tools/objtool/arch/arm64/include/insn_decode.h
+++ b/tools/objtool/arch/arm64/include/insn_decode.h
@@ -14,6 +14,8 @@
 #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 NR_INSN_CLASS	16
 #define INSN_CLASS(opcode)	(((opcode) >> 25) & (NR_INSN_CLASS - 1))
@@ -39,6 +41,8 @@ struct aarch64_insn_decoder {
 /* arm64 instruction classes */
 int arm_decode_dp_imm(u32 instr, enum insn_type *type,
 		      unsigned long *immediate, struct list_head *ops_list);
+int arm_decode_dp_reg(u32 instr, enum insn_type *type,
+		      unsigned long *immediate, struct list_head *ops_list);
 int arm_decode_br_sys(u32 instr, enum insn_type *type,
 		      unsigned long *immediate, struct list_head *ops_list);
 int arm_decode_ld_st(u32 instr, enum insn_type *type,
@@ -153,4 +157,42 @@ int arm_decode_ld_st_regs_unsigned(u32 instr, enum insn_type *type,
 int arm_decode_ld_st_exclusive(u32 instr, enum insn_type *type,
 			       unsigned long *immediate,
 			       struct list_head *ops_list);
+
+/* arm64 data processing -- registers instructions */
+int arm_decode_dp_reg_1src(u32 instr, enum insn_type *type,
+			   unsigned long *immediate,
+			   struct list_head *ops_list);
+int arm_decode_dp_reg_2src(u32 instr, enum insn_type *type,
+			   unsigned long *immediate,
+			   struct list_head *ops_list);
+int arm_decode_dp_reg_3src(u32 instr, enum insn_type *type,
+			   unsigned long *immediate,
+			   struct list_head *ops_list);
+int arm_decode_dp_reg_adde(u32 instr, enum insn_type *type,
+			   unsigned long *immediate,
+			   struct list_head *ops_list);
+int arm_decode_dp_reg_cmpi(u32 instr, enum insn_type *type,
+			   unsigned long *immediate,
+			   struct list_head *ops_list);
+int arm_decode_dp_reg_eval(u32 instr, enum insn_type *type,
+			   unsigned long *immediate,
+			   struct list_head *ops_list);
+int arm_decode_dp_reg_cmpr(u32 instr, enum insn_type *type,
+			   unsigned long *immediate,
+			   struct list_head *ops_list);
+int arm_decode_dp_reg_rota(u32 instr, enum insn_type *type,
+			   unsigned long *immediate,
+			   struct list_head *ops_list);
+int arm_decode_dp_reg_csel(u32 instr, enum insn_type *type,
+			   unsigned long *immediate,
+			   struct list_head *ops_list);
+int arm_decode_dp_reg_addc(u32 instr, enum insn_type *type,
+			   unsigned long *immediate,
+			   struct list_head *ops_list);
+int arm_decode_dp_reg_adds(u32 instr, enum insn_type *type,
+			   unsigned long *immediate,
+			   struct list_head *ops_list);
+int arm_decode_dp_reg_logi(u32 instr, enum insn_type *type,
+			   unsigned long *immediate,
+			   struct list_head *ops_list);
 #endif /* _ARM_INSN_DECODE_H */
-- 
2.21.0


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

* [RFC v5 41/57] objtool: arm64: Decode FP/SIMD data processing instructions
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (39 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 40/57] objtool: arm64: Decode register data processing instructions Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 42/57] objtool: arm64: Decode SVE instructions Julien Thierry
                   ` (18 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

FP/SIMD data processing instructions cannot modify the stack or frame
pointer.

Simply acknowledge the corresponding opcodes are valid.

Suggested-by: Raphael Gault <raphael.gault@arm.com>
Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/arch/arm64/decode.c              | 9 +++++++++
 tools/objtool/arch/arm64/include/insn_decode.h | 4 ++++
 2 files changed, 13 insertions(+)

diff --git a/tools/objtool/arch/arm64/decode.c b/tools/objtool/arch/arm64/decode.c
index bb1ba3b0997f..d35c2b58d309 100644
--- a/tools/objtool/arch/arm64/decode.c
+++ b/tools/objtool/arch/arm64/decode.c
@@ -130,11 +130,13 @@ static arm_decode_class aarch64_insn_class_decode_table[NR_INSN_CLASS] = {
 	[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_SYS_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,
 };
 
 /*
@@ -2746,3 +2748,10 @@ int arm_decode_dp_reg_3src(u32 instr, enum insn_type *type,
 	*type = INSN_OTHER;
 	return 0;
 }
+
+int arm_decode_dp_simd(u32 instr, enum insn_type *type,
+		       unsigned long *immediate, struct list_head *ops_list)
+{
+	*type = INSN_OTHER;
+	return 0;
+}
diff --git a/tools/objtool/arch/arm64/include/insn_decode.h b/tools/objtool/arch/arm64/include/insn_decode.h
index 8fb2f2b7564f..2bff4d7da007 100644
--- a/tools/objtool/arch/arm64/include/insn_decode.h
+++ b/tools/objtool/arch/arm64/include/insn_decode.h
@@ -16,6 +16,8 @@
 #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 NR_INSN_CLASS	16
 #define INSN_CLASS(opcode)	(((opcode) >> 25) & (NR_INSN_CLASS - 1))
@@ -47,6 +49,8 @@ int arm_decode_br_sys(u32 instr, enum insn_type *type,
 		      unsigned long *immediate, struct list_head *ops_list);
 int arm_decode_ld_st(u32 instr, enum insn_type *type,
 		     unsigned long *immediate, struct list_head *ops_list);
+int arm_decode_dp_simd(u32 instr, enum insn_type *type,
+		       unsigned long *immediate, struct list_head *ops_list);
 int arm_decode_unknown(u32 instr, enum insn_type *type,
 		       unsigned long *immediate, struct list_head *ops_list);
 
-- 
2.21.0


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

* [RFC v5 42/57] objtool: arm64: Decode SVE instructions
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (40 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 41/57] objtool: arm64: Decode FP/SIMD " Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 43/57] gcc-plugins: objtool: Add plugin to detect switch table on arm64 Julien Thierry
                   ` (17 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

Decode instructions from the SVE architecture extension.

These instructions do not modify the stack or frame pointer. Simply
acknowledge the corresponding opcodes are valid.

Suggested-by: Raphael Gault <raphael.gault@arm.com>
Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/arch/arm64/decode.c             | 109 ++++++++++++++++++
 .../objtool/arch/arm64/include/insn_decode.h  |   4 +
 2 files changed, 113 insertions(+)

diff --git a/tools/objtool/arch/arm64/decode.c b/tools/objtool/arch/arm64/decode.c
index d35c2b58d309..5a5f82b5cb81 100644
--- a/tools/objtool/arch/arm64/decode.c
+++ b/tools/objtool/arch/arm64/decode.c
@@ -126,6 +126,7 @@ static int is_arm64(struct elf *elf)
 static arm_decode_class aarch64_insn_class_decode_table[NR_INSN_CLASS] = {
 	[INSN_RESERVED]			= arm_decode_unknown,
 	[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,
@@ -2755,3 +2756,111 @@ int arm_decode_dp_simd(u32 instr, enum insn_type *type,
 	*type = INSN_OTHER;
 	return 0;
 }
+
+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,
+	},
+};
+
+int arm_decode_sve_encoding(u32 instr, enum insn_type *type,
+			    unsigned long *immediate,
+			    struct list_head *ops_list)
+{
+	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,
+						  ops_list);
+	}
+
+	*type = INSN_OTHER;
+
+	return 0;
+}
diff --git a/tools/objtool/arch/arm64/include/insn_decode.h b/tools/objtool/arch/arm64/include/insn_decode.h
index 2bff4d7da007..89cff8791c0b 100644
--- a/tools/objtool/arch/arm64/include/insn_decode.h
+++ b/tools/objtool/arch/arm64/include/insn_decode.h
@@ -7,6 +7,7 @@
 
 #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_SYS_BRANCH	0b1011	//0x101x
@@ -41,6 +42,9 @@ struct aarch64_insn_decoder {
 };
 
 /* arm64 instruction classes */
+int arm_decode_sve_encoding(u32 instr, enum insn_type *type,
+			    unsigned long *immediate,
+			    struct list_head *ops_list);
 int arm_decode_dp_imm(u32 instr, enum insn_type *type,
 		      unsigned long *immediate, struct list_head *ops_list);
 int arm_decode_dp_reg(u32 instr, enum insn_type *type,
-- 
2.21.0


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

* [RFC v5 43/57] gcc-plugins: objtool: Add plugin to detect switch table on arm64
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (41 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 42/57] objtool: arm64: Decode SVE instructions Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 44/57] objtool: arm64: Implement functions to add switch tables alternatives Julien Thierry
                   ` (16 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will,
	Julien Thierry, Masahiro Yamada, Michal Marek, Kees Cook,
	Emese Revfy, linux-kbuild, kernel-hardening

From: Raphael Gault <raphael.gault@arm.com>

This plugins comes into play before the final 2 RTL passes of GCC and
detects switch-tables that are to be outputed in the ELF and writes
information in an ".discard.switch_table_info" section which will be
used by objtool.

Signed-off-by: Raphael Gault <raphael.gault@arm.com>
[J.T.: Change section name to store switch table information,
       Make plugin Kconfig be selected rather than opt-in by user,
       Add a relocation in the switch_table_info that points to
       the jump operation itself]
Signed-off-by: Julien Thierry <jthierry@redhat.com>
Cc: Masahiro Yamada <masahiroy@kernel.org>
Cc: Michal Marek <michal.lkml@markovi.net>
Cc: Kees Cook <keescook@chromium.org>
Cc: Emese Revfy <re.emese@gmail.com>
Cc: linux-kbuild@vger.kernel.org
Cc: kernel-hardening@lists.openwall.com
---
 arch/arm64/Kconfig                            |  1 +
 scripts/Makefile.gcc-plugins                  |  2 +
 scripts/gcc-plugins/Kconfig                   |  4 +
 .../arm64_switch_table_detection_plugin.c     | 94 +++++++++++++++++++
 4 files changed, 101 insertions(+)
 create mode 100644 scripts/gcc-plugins/arm64_switch_table_detection_plugin.c

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index b1b4476ddb83..a7b2116d5d13 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -90,6 +90,7 @@ config ARM64
 	select DMA_DIRECT_REMAP
 	select EDAC_SUPPORT
 	select FRAME_POINTER
+	select GCC_PLUGIN_SWITCH_TABLES if STACK_VALIDATION
 	select GENERIC_ALLOCATOR
 	select GENERIC_ARCH_TOPOLOGY
 	select GENERIC_CLOCKEVENTS
diff --git a/scripts/Makefile.gcc-plugins b/scripts/Makefile.gcc-plugins
index 5f7df50cfe7a..a56736df9dc2 100644
--- a/scripts/Makefile.gcc-plugins
+++ b/scripts/Makefile.gcc-plugins
@@ -44,6 +44,8 @@ ifdef CONFIG_GCC_PLUGIN_ARM_SSP_PER_TASK
 endif
 export DISABLE_ARM_SSP_PER_TASK_PLUGIN

+gcc-plugin-$(CONFIG_GCC_PLUGIN_SWITCH_TABLES)	+= arm64_switch_table_detection_plugin.so
+
 # All the plugin CFLAGS are collected here in case a build target needs to
 # filter them out of the KBUILD_CFLAGS.
 GCC_PLUGINS_CFLAGS := $(strip $(addprefix -fplugin=$(objtree)/scripts/gcc-plugins/, $(gcc-plugin-y)) $(gcc-plugin-cflags-y))
diff --git a/scripts/gcc-plugins/Kconfig b/scripts/gcc-plugins/Kconfig
index e3569543bdac..f50047939660 100644
--- a/scripts/gcc-plugins/Kconfig
+++ b/scripts/gcc-plugins/Kconfig
@@ -112,4 +112,8 @@ config GCC_PLUGIN_ARM_SSP_PER_TASK
 	bool
 	depends on GCC_PLUGINS && ARM

+config GCC_PLUGIN_SWITCH_TABLES
+	bool
+	depends on GCC_PLUGINS && ARM64
+
 endif
diff --git a/scripts/gcc-plugins/arm64_switch_table_detection_plugin.c b/scripts/gcc-plugins/arm64_switch_table_detection_plugin.c
new file mode 100644
index 000000000000..9b8b2ec6a3c8
--- /dev/null
+++ b/scripts/gcc-plugins/arm64_switch_table_detection_plugin.c
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <stdio.h>
+#include "gcc-common.h"
+
+__visible int plugin_is_GPL_compatible;
+
+#define GEN_QUAD(rtx)	assemble_integer_with_op(".quad ", rtx)
+
+/*
+ * Create an array of metadata for each jump table found in the rtl.
+ * The metadata contains:
+ * - A pointer to the table of offsets used for the actual branch
+ * - A pointer to first instruction of the group getting expanded into an
+ *   acutal jump
+ * - The number of entries in the table of offsets
+ * - Whether the offsets in the table are signed or not
+ */
+static unsigned int arm64_switchtbl_rtl_execute(void)
+{
+	rtx_insn *insn;
+	rtx_insn *labelp = NULL;
+	rtx_jump_table_data *tablep = NULL;
+	section *swt_sec;
+	section *curr_sec = current_function_section();
+
+	swt_sec = get_section(".discard.switch_table_info",
+			      SECTION_EXCLUDE | SECTION_COMMON, NULL);
+
+	for (insn = get_insns(); insn; insn = NEXT_INSN(insn)) {
+		/*
+		 * Find a tablejump_p INSN (using a dispatch table)
+		 */
+		if (!tablejump_p(insn, &labelp, &tablep))
+			continue;
+
+		if (labelp && tablep) {
+			rtx_code_label *label_to_jump;
+
+			/*
+			 * GCC is a bit touchy about adding the label right
+			 * before the jump rtx_insn as it modifies the
+			 * basic_block created for the jump table.
+			 * Make sure we create the label before the whole
+			 * basic_block of the jump table.
+			 */
+			label_to_jump = gen_label_rtx();
+			SET_LABEL_KIND(label_to_jump, LABEL_NORMAL);
+			emit_label_before(label_to_jump, insn);
+			/* Force label to be kept, apparently LABEL_PRESERVE_P is an rvalue :) */
+			LABEL_PRESERVE_P(label_to_jump) = 1;
+
+			switch_to_section(swt_sec);
+			GEN_QUAD(gen_rtx_LABEL_REF(Pmode, labelp));
+			GEN_QUAD(gen_rtx_LABEL_REF(Pmode, label_to_jump));
+			GEN_QUAD(GEN_INT(GET_NUM_ELEM(tablep->get_labels())));
+			GEN_QUAD(GEN_INT(ADDR_DIFF_VEC_FLAGS(tablep).offset_unsigned));
+			switch_to_section(curr_sec);
+
+			/*
+			 * Scheduler isn't very happy about leaving labels in
+			 * the middle of jump table basic blocks.
+			 */
+			delete_insn(label_to_jump);
+		}
+	}
+	return 0;
+}
+
+#define PASS_NAME arm64_switchtbl_rtl
+
+#define NO_GATE
+#include "gcc-generate-rtl-pass.h"
+
+__visible int plugin_init(struct plugin_name_args *plugin_info,
+			  struct plugin_gcc_version *version)
+{
+	const char * const plugin_name = plugin_info->base_name;
+	int tso = 0;
+	int i;
+
+	if (!plugin_default_version_check(version, &gcc_version)) {
+		error(G_("incompatible gcc/plugin versions"));
+		return 1;
+	}
+
+	PASS_INFO(arm64_switchtbl_rtl, "expand", 1,
+		  PASS_POS_INSERT_AFTER);
+
+	register_callback(plugin_info->base_name, PLUGIN_PASS_MANAGER_SETUP,
+			  NULL, &arm64_switchtbl_rtl_pass_info);
+
+	return 0;
+}
--
2.21.0


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

* [RFC v5 44/57] objtool: arm64: Implement functions to add switch tables alternatives
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (42 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 43/57] gcc-plugins: objtool: Add plugin to detect switch table on arm64 Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-15 16:37   ` Raphael Gault
  2020-01-09 16:02 ` [RFC v5 45/57] objtool: arm64: Enable stack validation for arm64 Julien Thierry
                   ` (15 subsequent siblings)
  59 siblings, 1 reply; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

This patch implements the functions required to identify and add as
alternatives all the possible destinations of the switch table.
This implementation relies on the new plugin introduced previously which
records information about the switch-table in a
.discard.switch_table_information section.

Signed-off-by: Raphael Gault <raphael.gault@arm.com>
[J.T.: Update arch implementation to new prototypes,
       Update switch table information section name,
       Do some clean up,
       Use the offset sign information,
       Use the newly added rela to find the corresponding jump instruction]
Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 tools/objtool/arch/arm64/arch_special.c       | 251 +++++++++++++++++-
 .../objtool/arch/arm64/include/arch_special.h |   2 +
 tools/objtool/check.c                         |   4 +-
 tools/objtool/check.h                         |   2 +
 4 files changed, 255 insertions(+), 4 deletions(-)

diff --git a/tools/objtool/arch/arm64/arch_special.c b/tools/objtool/arch/arm64/arch_special.c
index 5239489c9c57..a15f6697dc74 100644
--- a/tools/objtool/arch/arm64/arch_special.c
+++ b/tools/objtool/arch/arm64/arch_special.c
@@ -1,15 +1,262 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 
+#include <stdlib.h>
+#include <string.h>
+
 #include "../../special.h"
+#include "../../warn.h"
+#include "arch_special.h"
+#include "bit_operations.h"
+#include "insn_decode.h"
+
+/*
+ * The arm64_switch_table_detection_plugin generate an array of elements
+ * described by the following structure.
+ * Each jump table found in the compilation unit is associated with one of
+ * entries of the array.
+ */
+struct switch_table_info {
+	u64 switch_table_ref; // Relocation target referencing the beginning of the jump table
+	u64 dyn_jump_ref; // Relocation target referencing the set of instructions setting up the jump to the table
+	u64 nb_entries;
+	u64 offset_unsigned;
+} __attribute__((__packed__));
+
+static bool insn_is_adr_pcrel(struct instruction *insn)
+{
+	u32 opcode = *(u32 *)(insn->sec->data->d_buf + insn->offset);
+
+	return ((opcode >> 24) & 0x1f) == 0x10;
+}
+
+static s64 next_offset(void *table, u8 entry_size, bool is_signed)
+{
+	if (!is_signed) {
+		switch (entry_size) {
+		case 1:
+			return *(u8 *)(table);
+		case 2:
+			return *(u16 *)(table);
+		default:
+			return *(u32 *)(table);
+		}
+	} else {
+		switch (entry_size) {
+		case 1:
+			return *(s8 *)(table);
+		case 2:
+			return *(s16 *)(table);
+		default:
+			return *(s32 *)(table);
+		}
+	}
+}
+
+static u32 get_table_entry_size(u32 insn)
+{
+	unsigned char size = (insn >> 30) & ONES(2);
+
+	switch (size) {
+	case 0:
+		return 1;
+	case 1:
+		return 2;
+	default:
+		return 4;
+	}
+}
+
+static int add_possible_branch(struct objtool_file *file,
+			       struct instruction *insn,
+			       u32 base, s64 offset)
+{
+	struct instruction *dest_insn;
+	struct alternative *alt;
+
+	offset = base + 4 * offset;
+
+	dest_insn = find_insn(file, insn->sec, offset);
+	if (!dest_insn)
+		return 0;
+
+	alt = calloc(1, sizeof(*alt));
+	if (!alt) {
+		WARN("allocation failure, can't add jump alternative");
+		return -1;
+	}
+
+	alt->insn = dest_insn;
+	alt->skip_orig = true;
+	list_add_tail(&alt->list, &insn->alts);
+	return 0;
+}
+
+static struct switch_table_info *get_swt_info(struct section *swt_info_sec,
+					      struct instruction *insn)
+{
+	u64 *table_ref;
+
+	if (!insn->jump_table) {
+		WARN("no jump table available for %s+0x%lx",
+		     insn->sec->name, insn->offset);
+		return NULL;
+	}
+	table_ref = (void *)(swt_info_sec->data->d_buf +
+			     insn->jump_table->offset);
+	return container_of(table_ref, struct switch_table_info,
+			    switch_table_ref);
+}
+
+static int add_arm64_jump_table_dests(struct objtool_file *file,
+				      struct instruction *insn)
+{
+	struct switch_table_info *swt_info;
+	struct section *objtool_data;
+	struct section *rodata_sec;
+	struct section *branch_sec;
+	struct instruction *pre_jump_insn;
+	u8 *switch_table;
+	u32 entry_size;
+
+	objtool_data = find_section_by_name(file->elf,
+					    ".discard.switch_table_info");
+	if (!objtool_data)
+		return 0;
+
+	/*
+	 * 1. Identify entry for the switch table
+	 * 2. Retrieve branch instruction
+	 * 3. Retrieve base offset
+	 * 3. For all entries in switch table:
+	 *     3.1. Compute new offset
+	 *     3.2. Create alternative instruction
+	 *     3.3. Add alt_instr to insn->alts list
+	 */
+	swt_info = get_swt_info(objtool_data, insn);
+
+	/* retrieving pre jump instruction (ldr) */
+	branch_sec = insn->sec;
+	pre_jump_insn = find_insn(file, branch_sec,
+				  insn->offset - 3 * sizeof(u32));
+	entry_size = get_table_entry_size(*(u32 *)(branch_sec->data->d_buf +
+						   pre_jump_insn->offset));
+
+	/* retrieving switch table content */
+	rodata_sec = find_section_by_name(file->elf, ".rodata");
+	switch_table = (u8 *)(rodata_sec->data->d_buf +
+			      insn->jump_table->addend);
+
+	/*
+	 * iterating over the pre-jumps instruction in order to
+	 * retrieve switch base offset.
+	 */
+	while (pre_jump_insn && pre_jump_insn->offset <= insn->offset) {
+		if (insn_is_adr_pcrel(pre_jump_insn)) {
+			u64 base_offset;
+			int i;
+
+			base_offset = pre_jump_insn->offset +
+				      pre_jump_insn->immediate;
+
+			/*
+			 * Once we have the switch table entry size
+			 * we add every possible destination using
+			 * alternatives of the original branch
+			 * instruction
+			 */
+			for (i = 0; i < swt_info->nb_entries; i++) {
+				s64 table_offset = next_offset(switch_table,
+							       entry_size,
+							       !swt_info->offset_unsigned);
+
+				if (add_possible_branch(file, insn,
+							base_offset,
+							table_offset)) {
+					return -1;
+				}
+				switch_table += entry_size;
+			}
+			break;
+		}
+		pre_jump_insn = next_insn_same_sec(file, pre_jump_insn);
+	}
+
+	return 0;
+}
 
 int arch_add_jump_table_dests(struct objtool_file *file,
 			      struct instruction *insn)
 {
-	return 0;
+	return add_arm64_jump_table_dests(file, insn);
 }
 
+static struct rela *find_swt_info_jump_rela(struct section *swt_info_sec,
+					    u32 index)
+{
+	u32 rela_offset;
+
+	rela_offset = index * sizeof(struct switch_table_info) +
+		      offsetof(struct switch_table_info, dyn_jump_ref);
+	return find_rela_by_dest(swt_info_sec, rela_offset);
+}
+
+static struct rela *find_swt_info_table_rela(struct section *swt_info_sec,
+					     u32 index)
+{
+	u32 rela_offset;
+
+	rela_offset = index * sizeof(struct switch_table_info) +
+		      offsetof(struct switch_table_info, switch_table_ref);
+	return find_rela_by_dest(swt_info_sec, rela_offset);
+}
+
+/*
+ * Aarch64 jump tables are just arrays of offsets (of varying size/signess)
+ * representing the potential destination from a base address loaded by an adr
+ * instruction.
+ *
+ * Aarch64 branches to jump tables are composed of multiple instructions:
+ *
+ *     ldr<?>  x_offset, [x_offsets_table, x_index, ...]
+ *     adr     x_dest_base, <addr>
+ *     add     x_dest, x_target_base, x_offset, ...
+ *     br      x_dest
+ *
+ * The arm64_switch_table_detection_plugin will make the connection between
+ * the instruction setting x_offsets_table (dyn_jump_ref) and the actual
+ * table of offsets (switch_table_ref)
+ */
 struct rela *arch_find_switch_table(struct objtool_file *file,
 				    struct instruction *insn)
 {
-	return NULL;
+	struct section *objtool_data;
+	struct rela *res = NULL;
+	u32 nb_swt_entries = 0;
+	u32 i;
+
+	objtool_data = find_section_by_name(file->elf,
+					    ".discard.switch_table_info");
+	if (objtool_data)
+		nb_swt_entries = objtool_data->sh.sh_size /
+				 sizeof(struct switch_table_info);
+
+	for (i = 0; i < nb_swt_entries; i++) {
+		struct rela *info_rela;
+
+		info_rela = find_swt_info_jump_rela(objtool_data, i);
+		if (info_rela && info_rela->sym->sec == insn->sec &&
+		    info_rela->addend == insn->offset) {
+			if (res) {
+				WARN_FUNC("duplicate objtool_data rela",
+					  info_rela->sec, info_rela->offset);
+				continue;
+			}
+			res = find_swt_info_table_rela(objtool_data, i);
+			if (!res)
+				WARN_FUNC("missing relocation in objtool data",
+					  info_rela->sec, info_rela->offset);
+		}
+	}
+
+	return res;
 }
diff --git a/tools/objtool/arch/arm64/include/arch_special.h b/tools/objtool/arch/arm64/include/arch_special.h
index a82a9b3e51df..b96bcee308cf 100644
--- a/tools/objtool/arch/arm64/include/arch_special.h
+++ b/tools/objtool/arch/arm64/include/arch_special.h
@@ -3,6 +3,8 @@
 #ifndef _ARM64_ARCH_SPECIAL_H
 #define _ARM64_ARCH_SPECIAL_H
 
+#include <linux/types.h>
+
 #define EX_ENTRY_SIZE		8
 #define EX_ORIG_OFFSET		0
 #define EX_NEW_OFFSET		4
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index e0c6bda261c8..80ea5bbd36ab 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -33,8 +33,8 @@ struct instruction *find_insn(struct objtool_file *file,
 	return NULL;
 }
 
-static struct instruction *next_insn_same_sec(struct objtool_file *file,
-					      struct instruction *insn)
+struct instruction *next_insn_same_sec(struct objtool_file *file,
+				       struct instruction *insn)
 {
 	struct instruction *next = list_next_entry(insn, list);
 
diff --git a/tools/objtool/check.h b/tools/objtool/check.h
index 91adec42782c..15165d04d9cb 100644
--- a/tools/objtool/check.h
+++ b/tools/objtool/check.h
@@ -66,6 +66,8 @@ int check(const char *objname, bool orc);
 
 struct instruction *find_insn(struct objtool_file *file,
 			      struct section *sec, unsigned long offset);
+struct instruction *next_insn_same_sec(struct objtool_file *file,
+				       struct instruction *insn);
 
 #define for_each_insn(file, insn)					\
 	list_for_each_entry(insn, &file->insn_list, list)
-- 
2.21.0


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

* [RFC v5 45/57] objtool: arm64: Enable stack validation for arm64
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (43 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 44/57] objtool: arm64: Implement functions to add switch tables alternatives Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 46/57] arm64: alternative: Mark .altinstr_replacement as containing executable instructions Julien Thierry
                   ` (14 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

From: Raphael Gault <raphael.gault@arm.com>

Add build option to run stack validation at compile time.

Signed-off-by: Raphael Gault <raphael.gault@arm.com>
Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 arch/arm64/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index a7b2116d5d13..60a17af19aba 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -165,6 +165,7 @@ config ARM64
 	select HAVE_RCU_TABLE_FREE
 	select HAVE_RSEQ
 	select HAVE_STACKPROTECTOR
+	select HAVE_STACK_VALIDATION
 	select HAVE_SYSCALL_TRACEPOINTS
 	select HAVE_KPROBES
 	select HAVE_KRETPROBES
-- 
2.21.0


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

* [RFC v5 46/57] arm64: alternative: Mark .altinstr_replacement as containing executable instructions
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (44 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 45/57] objtool: arm64: Enable stack validation for arm64 Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 47/57] arm64: assembler: Add macro to annotate asm function having non standard stack-frame Julien Thierry
                   ` (13 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

From: Raphael Gault <raphael.gault@arm.com>

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 <raphael.gault@arm.com>
Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 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"							\
--
2.21.0


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

* [RFC v5 47/57] arm64: assembler: Add macro to annotate asm function having non standard stack-frame.
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (45 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 46/57] arm64: alternative: Mark .altinstr_replacement as containing executable instructions Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-21 10:30   ` Will Deacon
  2020-01-09 16:02 ` [RFC v5 48/57] arm64: sleep: Prevent stack frame warnings from objtool Julien Thierry
                   ` (12 subsequent siblings)
  59 siblings, 1 reply; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

From: Raphael Gault <raphael.gault@arm.com>

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 <raphael.gault@arm.com>
Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 include/linux/frame.h | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/include/linux/frame.h b/include/linux/frame.h
index 02d3ca2d9598..1e35e58ab259 100644
--- a/include/linux/frame.h
+++ b/include/linux/frame.h
@@ -11,14 +11,31 @@
  *
  * For more information, see tools/objtool/Documentation/stack-validation.txt.
  */
+#ifndef __ASSEMBLY__
 #define STACK_FRAME_NON_STANDARD(func) \
 	static void __used __section(.discard.func_stack_frame_non_standard) \
 		*__func_stack_frame_non_standard_##func = func
+#else
+	/*
+	 * 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
+	.pushsection ".discard.func_stack_frame_non_standard"
+	.quad	\func
+	.popsection
+	.endm

+#endif /* __ASSEMBLY__ */
 #else /* !CONFIG_STACK_VALIDATION */

+#ifndef __ASSEMBLY__
 #define STACK_FRAME_NON_STANDARD(func)
-
+#else
+	.macro	asm_stack_frame_non_standard	func
+	.endm
+#endif /* __ASSEMBLY__ */
 #endif /* CONFIG_STACK_VALIDATION */

 #endif /* _LINUX_FRAME_H */
--
2.21.0


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

* [RFC v5 48/57] arm64: sleep: Prevent stack frame warnings from objtool
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (46 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 47/57] arm64: assembler: Add macro to annotate asm function having non standard stack-frame Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 49/57] arm64: kvm: Annotate non-standard stack frame functions Julien Thierry
                   ` (11 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

From: Raphael Gault <raphael.gault@arm.com>

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 <raphael.gault@arm.com>
Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 arch/arm64/kernel/sleep.S | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm64/kernel/sleep.S b/arch/arm64/kernel/sleep.S
index f5b04dd8a710..55c7c099d32c 100644
--- a/arch/arm64/kernel/sleep.S
+++ b/arch/arm64/kernel/sleep.S
@@ -1,5 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 #include <linux/errno.h>
+#include <linux/frame.h>
 #include <linux/linkage.h>
 #include <asm/asm-offsets.h>
 #include <asm/assembler.h>
@@ -90,6 +91,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 +148,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
-- 
2.21.0


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

* [RFC v5 49/57] arm64: kvm: Annotate non-standard stack frame functions
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (47 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 48/57] arm64: sleep: Prevent stack frame warnings from objtool Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 50/57] arm64: kernel: Add exception on kuser32 to prevent stack analysis Julien Thierry
                   ` (10 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will,
	Julien Thierry, Marc Zyngier, James Morse, Suzuki K Poulose,
	kvmarm

From: Raphael Gault <raphael.gault@arm.com>

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 <raphael.gault@arm.com>
Signed-off-by: Julien Thierry <jthierry@redhat.com>
Cc: Marc Zyngier <maz@kernel.org>
Cc: James Morse <james.morse@arm.com>
Cc: Suzuki K Poulose <suzuki.poulose@arm.com>
Cc: kvmarm@lists.cs.columbia.edu
---
 arch/arm64/kvm/hyp/entry.S | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/arm64/kvm/hyp/entry.S b/arch/arm64/kvm/hyp/entry.S
index e5cc8d66bf53..c3443bfd0944 100644
--- a/arch/arm64/kvm/hyp/entry.S
+++ b/arch/arm64/kvm/hyp/entry.S
@@ -15,6 +15,7 @@
 #include <asm/kvm_asm.h>
 #include <asm/kvm_mmu.h>
 #include <asm/kvm_ptrauth.h>
+#include <linux/frame.h>

 #define CPU_GP_REG_OFFSET(x)	(CPU_GP_REGS + x)
 #define CPU_XREG_OFFSET(x)	CPU_GP_REG_OFFSET(CPU_USER_PT_REGS + 8*x)
@@ -97,6 +98,7 @@ alternative_else_nop_endif
 	eret
 	sb
 ENDPROC(__guest_enter)
+asm_stack_frame_non_standard __guest_enter

 ENTRY(__guest_exit)
 	// x0: return code
@@ -193,3 +195,4 @@ abort_guest_exit_end:
 	orr	x0, x0, x5
 1:	ret
 ENDPROC(__guest_exit)
+asm_stack_frame_non_standard __guest_exit
--
2.21.0


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

* [RFC v5 50/57] arm64: kernel: Add exception on kuser32 to prevent stack analysis
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (48 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 49/57] arm64: kvm: Annotate non-standard stack frame functions Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 51/57] arm64: crypto: Add exceptions for crypto object " Julien Thierry
                   ` (9 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

From: Raphael Gault <raphael.gault@arm.com>

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 <raphael.gault@arm.com>
Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 arch/arm64/kernel/Makefile | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index fc6488660f64..f5994679db5f 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -33,6 +33,9 @@ ifneq ($(CONFIG_COMPAT_VDSO), y)
 obj-$(CONFIG_COMPAT)			+= sigreturn32.o
 endif
 obj-$(CONFIG_KUSER_HELPERS)		+= kuser32.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
-- 
2.21.0


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

* [RFC v5 51/57] arm64: crypto: Add exceptions for crypto object to prevent stack analysis
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (49 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 50/57] arm64: kernel: Add exception on kuser32 to prevent stack analysis Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 52/57] arm64: kernel: Annotate non-standard stack frame functions Julien Thierry
                   ` (8 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

From: Raphael Gault <raphael.gault@arm.com>

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 being 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 <raphael.gault@arm.com>
Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 arch/arm64/crypto/Makefile | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/arm64/crypto/Makefile b/arch/arm64/crypto/Makefile
index d0901e610df3..576a19923185 100644
--- a/arch/arm64/crypto/Makefile
+++ b/arch/arm64/crypto/Makefile
@@ -43,9 +43,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
@@ -62,6 +64,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
 
-- 
2.21.0


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

* [RFC v5 52/57] arm64: kernel: Annotate non-standard stack frame functions
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (50 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 51/57] arm64: crypto: Add exceptions for crypto object " Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 53/57] arm64: Generate no-ops to pad executable section Julien Thierry
                   ` (7 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will,
	Julien Thierry, Marc Zyngier, James Morse, Suzuki K Poulose,
	kvmarm

From: Raphael Gault <raphael.gault@arm.com>

Annotate assembler functions which are callable but do not
setup a correct stack frame.

Signed-off-by: Raphael Gault <raphael.gault@arm.com>
Signed-off-by: Julien Thierry <jthierry@redhat.com>
Cc: Marc Zyngier <maz@kernel.org>
Cc: James Morse <james.morse@arm.com>
Cc: Suzuki K Poulose <suzuki.poulose@arm.com>
Cc: kvmarm@lists.cs.columbia.edu
---
 arch/arm64/kernel/hyp-stub.S | 3 +++
 arch/arm64/kvm/hyp-init.S    | 3 +++
 2 files changed, 6 insertions(+)

diff --git a/arch/arm64/kernel/hyp-stub.S b/arch/arm64/kernel/hyp-stub.S
index 73d46070b315..8917d42f38c7 100644
--- a/arch/arm64/kernel/hyp-stub.S
+++ b/arch/arm64/kernel/hyp-stub.S
@@ -6,6 +6,7 @@
  * Author:	Marc Zyngier <marc.zyngier@arm.com>
  */

+#include <linux/frame.h>
 #include <linux/init.h>
 #include <linux/linkage.h>
 #include <linux/irqchip/arm-gic-v3.h>
@@ -42,6 +43,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

@@ -69,6 +71,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 160be2b4696d..63deea39313d 100644
--- a/arch/arm64/kvm/hyp-init.S
+++ b/arch/arm64/kvm/hyp-init.S
@@ -12,6 +12,7 @@
 #include <asm/pgtable-hwdef.h>
 #include <asm/sysreg.h>
 #include <asm/virt.h>
+#include <linux/frame.h>

 	.text
 	.pushsection	.hyp.idmap.text, "ax"
@@ -118,6 +119,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
@@ -159,6 +161,7 @@ reset:
 	eret

 ENDPROC(__kvm_handle_stub_hvc)
+asm_stack_frame_non_standard __kvm_handle_stub_hvc

 	.ltorg

--
2.21.0


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

* [RFC v5 53/57] arm64: Generate no-ops to pad executable section
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (51 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 52/57] arm64: kernel: Annotate non-standard stack frame functions Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 54/57] arm64: Move constant to rodata Julien Thierry
                   ` (6 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

Directive .org fills the gap left to get to the new location with bytes
of value 0.

Having an executable section contain invalid opcodes confuses objtool,
so use .balign to fill the gap with nop instructions instead.

Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 arch/arm64/kernel/relocate_kernel.S | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm64/kernel/relocate_kernel.S b/arch/arm64/kernel/relocate_kernel.S
index c1d7db71a726..5e08845f701a 100644
--- a/arch/arm64/kernel/relocate_kernel.S
+++ b/arch/arm64/kernel/relocate_kernel.S
@@ -118,6 +118,8 @@ ENDPROC(arm64_relocate_new_kernel)
 .align 3	/* To keep the 64-bit values below naturally aligned. */
 
 .Lcopy_end:
+.balign	KEXEC_CONTROL_PAGE_SIZE
+/* Ensure we didn't go past the limit */
 .org	KEXEC_CONTROL_PAGE_SIZE
 
 /*
-- 
2.21.0


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

* [RFC v5 54/57] arm64: Move constant to rodata
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (52 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 53/57] arm64: Generate no-ops to pad executable section Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 55/57] arm64: Mark sigreturn32.o as containing non standard code Julien Thierry
                   ` (5 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

Constant arm64_relocate_new_kernel_size does not need to be in
the same section as the new kernel code/data region.

Move it to ".rodata" section.

Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 arch/arm64/kernel/relocate_kernel.S | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/arm64/kernel/relocate_kernel.S b/arch/arm64/kernel/relocate_kernel.S
index 5e08845f701a..e7a5fded59e6 100644
--- a/arch/arm64/kernel/relocate_kernel.S
+++ b/arch/arm64/kernel/relocate_kernel.S
@@ -122,10 +122,13 @@ ENDPROC(arm64_relocate_new_kernel)
 /* Ensure we didn't go past the limit */
 .org	KEXEC_CONTROL_PAGE_SIZE
 
+.pushsection ".rodata", "a"
 /*
  * arm64_relocate_new_kernel_size - Number of bytes to copy to the
  * control_code_page.
  */
 .globl arm64_relocate_new_kernel_size
+.align 8
 arm64_relocate_new_kernel_size:
 	.quad	.Lcopy_end - arm64_relocate_new_kernel
+.popsection
-- 
2.21.0


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

* [RFC v5 55/57] arm64: Mark sigreturn32.o as containing non standard code
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (53 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 54/57] arm64: Move constant to rodata Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:02 ` [RFC v5 56/57] arm64: entry: Avoid empty alternatives entries Julien Thierry
                   ` (4 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

sigreturn32.o contains aarch32 getting copied to the VDSO for
compat user tasks.

This code shouldn't get validated by arm64 objtool.

Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 arch/arm64/kernel/Makefile | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index f5994679db5f..b978026ea368 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -31,6 +31,7 @@ obj-$(CONFIG_COMPAT)			+= sys32.o signal32.o			\
 					   sys_compat.o
 ifneq ($(CONFIG_COMPAT_VDSO), y)
 obj-$(CONFIG_COMPAT)			+= sigreturn32.o
+OBJECT_FILES_NON_STANDARD_sigreturn32.o := y
 endif
 obj-$(CONFIG_KUSER_HELPERS)		+= kuser32.o
 
-- 
2.21.0


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

* [RFC v5 56/57] arm64: entry: Avoid empty alternatives entries
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (54 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 55/57] arm64: Mark sigreturn32.o as containing non standard code Julien Thierry
@ 2020-01-09 16:02 ` Julien Thierry
  2020-01-09 16:51   ` Mark Rutland
  2020-01-09 16:03 ` [RFC v5 57/57] arm64: crypto: Remove redundant branch Julien Thierry
                   ` (3 subsequent siblings)
  59 siblings, 1 reply; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:02 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

kernel_ventry will create alternative entries to potentially replace
0 instructions with 0 instructions for EL1 vectors. While this does not
cause an issue, it pointlessly takes up some bytes in the alternatives
section.

Do not generate such entries.

Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 arch/arm64/kernel/entry.S | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index 7c6a0a41676f..605bb7cbe499 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -60,16 +60,16 @@
 	.macro kernel_ventry, el, label, regsize = 64
 	.align 7
 #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
-alternative_if ARM64_UNMAP_KERNEL_AT_EL0
 	.if	\el == 0
+alternative_if ARM64_UNMAP_KERNEL_AT_EL0
 	.if	\regsize == 64
 	mrs	x30, tpidrro_el0
 	msr	tpidrro_el0, xzr
 	.else
 	mov	x30, xzr
 	.endif
-	.endif
 alternative_else_nop_endif
+	.endif
 #endif
 
 	sub	sp, sp, #S_FRAME_SIZE
-- 
2.21.0


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

* [RFC v5 57/57] arm64: crypto: Remove redundant branch
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (55 preceding siblings ...)
  2020-01-09 16:02 ` [RFC v5 56/57] arm64: entry: Avoid empty alternatives entries Julien Thierry
@ 2020-01-09 16:03 ` Julien Thierry
  2020-01-12  8:42 ` [RFC v5 00/57] objtool: Add support for arm64 Nathan Chancellor
                   ` (2 subsequent siblings)
  59 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-09 16:03 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will, Julien Thierry

Having a unconditional branch between the macros do_cond_yield_neon and
endif_yeild_neon causes the endif_yeild_neon to be unreachable. It so
happens that endif_yeild_neon expands to a branch and already allows to
provide the label to jump to after the yeild.

Get rid of the redundant branch instruction.

Signed-off-by: Julien Thierry <jthierry@redhat.com>
---
 arch/arm64/crypto/sha1-ce-core.S   | 3 +--
 arch/arm64/crypto/sha2-ce-core.S   | 3 +--
 arch/arm64/crypto/sha3-ce-core.S   | 3 +--
 arch/arm64/crypto/sha512-ce-core.S | 3 +--
 4 files changed, 4 insertions(+), 8 deletions(-)

diff --git a/arch/arm64/crypto/sha1-ce-core.S b/arch/arm64/crypto/sha1-ce-core.S
index c2ce1f820706..50ca9d11a61f 100644
--- a/arch/arm64/crypto/sha1-ce-core.S
+++ b/arch/arm64/crypto/sha1-ce-core.S
@@ -132,8 +132,7 @@ CPU_LE(	rev32		v11.16b, v11.16b	)
 	st1		{dgav.4s}, [x19]
 	str		dgb, [x19, #16]
 	do_cond_yield_neon
-	b		0b
-	endif_yield_neon
+	endif_yield_neon 0b
 
 	b		1b
 
diff --git a/arch/arm64/crypto/sha2-ce-core.S b/arch/arm64/crypto/sha2-ce-core.S
index 6f728a419009..c64716f5de19 100644
--- a/arch/arm64/crypto/sha2-ce-core.S
+++ b/arch/arm64/crypto/sha2-ce-core.S
@@ -139,8 +139,7 @@ CPU_LE(	rev32		v19.16b, v19.16b	)
 	if_will_cond_yield_neon
 	st1		{dgav.4s, dgbv.4s}, [x19]
 	do_cond_yield_neon
-	b		0b
-	endif_yield_neon
+	endif_yield_neon 0b
 
 	b		1b
 
diff --git a/arch/arm64/crypto/sha3-ce-core.S b/arch/arm64/crypto/sha3-ce-core.S
index a7d587fa54f6..2448d8dec0de 100644
--- a/arch/arm64/crypto/sha3-ce-core.S
+++ b/arch/arm64/crypto/sha3-ce-core.S
@@ -203,8 +203,7 @@ ENTRY(sha3_ce_transform)
 	st1	{v20.1d-v23.1d}, [x8], #32
 	st1	{v24.1d}, [x8]
 	do_cond_yield_neon
-	b		0b
-	endif_yield_neon
+	endif_yield_neon 0b
 
 	b	1b
 
diff --git a/arch/arm64/crypto/sha512-ce-core.S b/arch/arm64/crypto/sha512-ce-core.S
index ce65e3abe4f2..703724703f8f 100644
--- a/arch/arm64/crypto/sha512-ce-core.S
+++ b/arch/arm64/crypto/sha512-ce-core.S
@@ -207,8 +207,7 @@ CPU_LE(	rev64		v19.16b, v19.16b	)
 	if_will_cond_yield_neon
 	st1		{v8.2d-v11.2d}, [x19]
 	do_cond_yield_neon
-	b		0b
-	endif_yield_neon
+	endif_yield_neon 0b
 
 	b		1b
 
-- 
2.21.0


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

* Re: [RFC v5 56/57] arm64: entry: Avoid empty alternatives entries
  2020-01-09 16:02 ` [RFC v5 56/57] arm64: entry: Avoid empty alternatives entries Julien Thierry
@ 2020-01-09 16:51   ` Mark Rutland
  2020-01-21 10:30     ` Will Deacon
  0 siblings, 1 reply; 91+ messages in thread
From: Mark Rutland @ 2020-01-09 16:51 UTC (permalink / raw)
  To: Julien Thierry
  Cc: linux-kernel, linux-arm-kernel, jpoimboe, peterz, raphael.gault,
	catalin.marinas, will

On Thu, Jan 09, 2020 at 04:02:59PM +0000, Julien Thierry wrote:
> kernel_ventry will create alternative entries to potentially replace
> 0 instructions with 0 instructions for EL1 vectors. While this does not
> cause an issue, it pointlessly takes up some bytes in the alternatives
> section.
> 
> Do not generate such entries.
> 
> Signed-off-by: Julien Thierry <jthierry@redhat.com>

This looks like a sensible cleanup on its own. FWIW:

Acked-by: Mark Rutland <mark.rutland@arm.com>

Mark.

> ---
>  arch/arm64/kernel/entry.S | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
> index 7c6a0a41676f..605bb7cbe499 100644
> --- a/arch/arm64/kernel/entry.S
> +++ b/arch/arm64/kernel/entry.S
> @@ -60,16 +60,16 @@
>  	.macro kernel_ventry, el, label, regsize = 64
>  	.align 7
>  #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
> -alternative_if ARM64_UNMAP_KERNEL_AT_EL0
>  	.if	\el == 0
> +alternative_if ARM64_UNMAP_KERNEL_AT_EL0
>  	.if	\regsize == 64
>  	mrs	x30, tpidrro_el0
>  	msr	tpidrro_el0, xzr
>  	.else
>  	mov	x30, xzr
>  	.endif
> -	.endif
>  alternative_else_nop_endif
> +	.endif
>  #endif
>  
>  	sub	sp, sp, #S_FRAME_SIZE
> -- 
> 2.21.0
> 

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

* Re: [RFC v5 00/57] objtool: Add support for arm64
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (56 preceding siblings ...)
  2020-01-09 16:03 ` [RFC v5 57/57] arm64: crypto: Remove redundant branch Julien Thierry
@ 2020-01-12  8:42 ` Nathan Chancellor
  2020-01-13  7:57   ` Julien Thierry
  2020-01-13 17:18   ` Nick Desaulniers
  2020-01-20 15:07 ` Peter Zijlstra
  2020-01-21 10:30 ` Will Deacon
  59 siblings, 2 replies; 91+ messages in thread
From: Nathan Chancellor @ 2020-01-12  8:42 UTC (permalink / raw)
  To: Julien Thierry
  Cc: linux-kernel, linux-arm-kernel, jpoimboe, peterz, raphael.gault,
	catalin.marinas, will, clang-built-linux

On Thu, Jan 09, 2020 at 04:02:03PM +0000, Julien Thierry wrote:
> Hi,
> 
> This patch series is the continuation of Raphael's work [1]. All the
> patches can be retrieved from:
> git clone -b arm64-objtool-v5 https://github.com/julien-thierry/linux.git
> 
> There still are some outstanding issues but the series is starting to
> get pretty big so it is probably good to start having some discussions
> on the current state of things.
> 
> It felt necessary to split some of the patches (especially the arm64
> decoder). In order to give Raphael credit for his work I used the
> "Suggested-by" tag. If this is not the right way to give credit or if
> it should be present on more patches do let me know.
> 
> There still are some shortcomings. On defconfig here are the remaining
> warnings:
> * arch/arm64/crypto/crct10dif-ce-core.o: warning: objtool: crc_t10dif_pmull_p8()+0xf0: unsupported intra-function call
> * arch/arm64/kernel/cpu_errata.o: warning: objtool: qcom_link_stack_sanitization()+0x4: unsupported intra-function call
> Objtool currently does not support bl from a procedure to itself. This
> is also an issue with retpolines. I need to investigate more to figure
> out whether something can be done for this or if this file should not be
> validated by objtool.
> 
> * arch/arm64/kernel/efi-entry.o: warning: objtool: entry()+0xb0: sibling call from callable instruction with modified stack frame
> The EFI entry jumps to code mapped by EFI. Objtool cannot know statically where the code flow is going.
> 
> * arch/arm64/kernel/entry.o: warning: objtool: .entry.tramp.text+0x404: unsupported intra-function call
> Need to figure out what is needed to handle aarch64 trampolines. x86
> explicitly annotates theirs with ANNOTATE_NOSPEC_ALTERNATIVE and
> patching them as alternatives.
> 
> * arch/arm64/kernel/head.o: warning: objtool: .head.text+0x58: can't find jump dest instruction at .head.text+0x80884
> This is actually a constant that turns out to be a valid branch opcode.
> A possible solution could be to introduce a marco that explicitly
> annotates constants placed in code sections.
> 
> * arch/arm64/kernel/hibernate-asm.o: warning: objtool: el1_sync()+0x4: unsupported instruction in callable function
> Symbols el<x>_* shouldn't be considered as callable functions. Should we
> use SYM_CODE_END instead of PROC_END?
> 
> * arch/arm64/kvm/hyp/hyp-entry.o: warning: objtool: .hyp.text: empty alternative at end of section
> This is due to the arm64 alternative_cb. Currently, the feature
> corresponding to the alternative_cb is defined as the current number of
> features supported by the kernel, meaning the identifier is not fixed
> accross kernel versions. This makes it a bit hard to detect these
> alternative_cb for external tools.
> 
> Would it be acceptable to set a fixed identifier for alternative_cb?
> (probably 0xFF so it is always higher than the number of real features)
> 
> * drivers/ata/libata-scsi.o: warning: objtool: ata_sas_queuecmd() falls through to next function ata_scsi_scan_host()
> This is due to a limitation in the switch table metadata interpretation.
> The compiler might create a table of unsigned offsets and then
> compute the final offset as follows:
> 
> 	ldrb    offset_reg, [<offset_table>, <offset_idx>, uxtw]
> 	adr     base_reg, <base_addr>
> 	add     res_addr, base_reg, offset_reg, sxtb #2
> 
> Effectively using the loaded offset as a signed value.
> I don't have a simple way to solve this at the moment, I'd like to
> avoid decoding the instructions to check which ones might sign extend
> the loaded offset.
> 
> * kernel/bpf/core.o: warning: objtool: ___bpf_prog_run()+0x44: sibling call from callable instruction with modified stack frame
> This is because the function uses a C jump table which differ from
> basic jump tables. Also, the code generated for C jump tables on arm64
> does not follow the same form as the one for x86. So the existing x86 objtool
> code handling C jump tables can't be used.
> 
> I'll focus on understanding the arm64 pattern so objtool can handle them.
> 
> 
> In the mean time, any feedback on the current state is appreciated.
> 
> * Patches 1 to 18 adapts the current objtool code to make it easier to
>   support new architectures.
> * Patches 19 to 45 add the support for arm64 architecture to objtool.
> * Patches 46 to 57 fix warnings reported by objtool on the existing
>   arm64 code.
> 
> Changes since RFCv4[1]:
> * Rebase on v5.5-rc5
> * Misc cleanup/bug fixes
> * Fix some new objtool warnings reported on arm64 objects
> * Make ORC subcommand optional since arm64 does not currently support it
> * Support branch instructions in alternative sections when they jump
>   within the same set of alternative instructions
> * Replace the "extra" stack_op with a list of stack_op
> * Split the decoder into multiple patches to ease review
> * Mark constants generated by load literal instructions as bytes that
>   should not be reached by execution flow
> * Rework the switch table handling
> 
> [1] https://lkml.org/lkml/2019/8/16/400
> 
> Thanks,
> 
> Julien
> 
> -->
> 
> Julien Thierry (43):
>   objtool: check: Remove redundant checks on operand type
>   objtool: check: Clean instruction state before each function
>     validation
>   objtool: check: Use arch specific values in restore_reg()
>   objtool: check: Ignore empty alternative groups
>   objtool: Give ORC functions consistent name
>   objtool: Make ORC support optional
>   objtool: Split generic and arch specific CFI definitions
>   objtool: Abstract alternative special case handling
>   objtool: check: Allow jumps from an alternative group to itself
>   objtool: Do not look for STT_NOTYPE symbols
>   objtool: Support addition to set frame pointer
>   objtool: Support restoring BP from the stack without POP
>   objtool: Make stack validation more generic
>   objtool: Support multiple stack_op per instruction
>   objtool: arm64: Decode unknown instructions
>   objtool: arm64: Decode simple data processing instructions
>   objtool: arm64: Decode add/sub immediate instructions
>   objtool: arm64: Decode logical data processing instructions
>   objtool: arm64: Decode system instructions not affecting the flow
>   objtool: arm64: Decode calls to higher EL
>   objtool: arm64: Decode brk instruction
>   objtool: arm64: Decode instruction triggering context switch
>   objtool: arm64: Decode branch instructions with PC relative immediates
>   objtool: arm64: Decode branch to register instruction
>   objtool: arm64: Decode basic load/stores
>   objtool: arm64: Decode load/store with register offset
>   objtool: arm64: Decode load/store register pair instructions
>   objtool: arm64: Decode FP/SIMD load/store instructions
>   objtool: arm64: Decode load/store exclusive
>   objtool: arm64: Decode atomic load/store
>   objtool: arm64: Decode pointer auth load instructions
>   objtool: arm64: Decode load acquire/store release
>   objtool: arm64: Decode load/store with memory tag
>   objtool: arm64: Decode load literal
>   objtool: arm64: Decode register data processing instructions
>   objtool: arm64: Decode FP/SIMD data processing instructions
>   objtool: arm64: Decode SVE instructions
>   objtool: arm64: Implement functions to add switch tables alternatives
>   arm64: Generate no-ops to pad executable section
>   arm64: Move constant to rodata
>   arm64: Mark sigreturn32.o as containing non standard code
>   arm64: entry: Avoid empty alternatives entries
>   arm64: crypto: Remove redundant branch
> 
> Raphael Gault (14):
>   objtool: Add abstraction for computation of symbols offsets
>   objtool: orc: Refactor ORC API for other architectures to implement.
>   objtool: Move registers and control flow to arch-dependent code
>   objtool: Refactor switch-tables code to support other architectures
>   objtool: arm64: Add required implementation for supporting the aarch64
>     architecture in objtool.
>   gcc-plugins: objtool: Add plugin to detect switch table on arm64
>   objtool: arm64: Enable stack validation for arm64
>   arm64: alternative: Mark .altinstr_replacement as containing
>     executable instructions
>   arm64: assembler: Add macro to annotate asm function having non
>     standard stack-frame.
>   arm64: sleep: Prevent stack frame warnings from objtool
>   arm64: kvm: Annotate non-standard stack frame functions
>   arm64: kernel: Add exception on kuser32 to prevent stack analysis
>   arm64: crypto: Add exceptions for crypto object to prevent stack
>     analysis
>   arm64: kernel: Annotate non-standard stack frame functions
> 
>  arch/arm64/Kconfig                            |    2 +
>  arch/arm64/crypto/Makefile                    |    3 +
>  arch/arm64/crypto/sha1-ce-core.S              |    3 +-
>  arch/arm64/crypto/sha2-ce-core.S              |    3 +-
>  arch/arm64/crypto/sha3-ce-core.S              |    3 +-
>  arch/arm64/crypto/sha512-ce-core.S            |    3 +-
>  arch/arm64/include/asm/alternative.h          |    2 +-
>  arch/arm64/kernel/Makefile                    |    4 +
>  arch/arm64/kernel/entry.S                     |    4 +-
>  arch/arm64/kernel/hyp-stub.S                  |    3 +
>  arch/arm64/kernel/relocate_kernel.S           |    5 +
>  arch/arm64/kernel/sleep.S                     |    5 +
>  arch/arm64/kvm/hyp-init.S                     |    3 +
>  arch/arm64/kvm/hyp/entry.S                    |    3 +
>  include/linux/frame.h                         |   19 +-
>  scripts/Makefile.gcc-plugins                  |    2 +
>  scripts/gcc-plugins/Kconfig                   |    4 +
>  .../arm64_switch_table_detection_plugin.c     |   94 +
>  tools/objtool/Build                           |    4 +-
>  tools/objtool/Makefile                        |   13 +-
>  tools/objtool/arch.h                          |   14 +-
>  tools/objtool/arch/arm64/Build                |    5 +
>  tools/objtool/arch/arm64/arch_special.c       |  262 ++
>  tools/objtool/arch/arm64/bit_operations.c     |   69 +
>  tools/objtool/arch/arm64/decode.c             | 2866 +++++++++++++++++
>  .../objtool/arch/arm64/include/arch_special.h |   23 +
>  .../arch/arm64/include/bit_operations.h       |   31 +
>  tools/objtool/arch/arm64/include/cfi_regs.h   |   44 +
>  .../objtool/arch/arm64/include/insn_decode.h  |  206 ++
>  tools/objtool/arch/x86/Build                  |    3 +
>  tools/objtool/arch/x86/arch_special.c         |  182 ++
>  tools/objtool/arch/x86/decode.c               |   29 +-
>  tools/objtool/arch/x86/include/arch_special.h |   28 +
>  tools/objtool/arch/x86/include/cfi_regs.h     |   25 +
>  tools/objtool/{ => arch/x86}/orc_dump.c       |    4 +-
>  tools/objtool/{ => arch/x86}/orc_gen.c        |  114 +-
>  tools/objtool/cfi.h                           |   21 +-
>  tools/objtool/check.c                         |  461 +--
>  tools/objtool/check.h                         |   13 +-
>  tools/objtool/elf.c                           |    3 +-
>  tools/objtool/objtool.c                       |    2 +
>  tools/objtool/orc.h                           |   38 +-
>  tools/objtool/special.c                       |   44 +-
>  tools/objtool/special.h                       |   13 +
>  44 files changed, 4282 insertions(+), 400 deletions(-)
>  create mode 100644 scripts/gcc-plugins/arm64_switch_table_detection_plugin.c
>  create mode 100644 tools/objtool/arch/arm64/Build
>  create mode 100644 tools/objtool/arch/arm64/arch_special.c
>  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/bit_operations.h
>  create mode 100644 tools/objtool/arch/arm64/include/cfi_regs.h
>  create mode 100644 tools/objtool/arch/arm64/include/insn_decode.h
>  create mode 100644 tools/objtool/arch/x86/arch_special.c
>  create mode 100644 tools/objtool/arch/x86/include/arch_special.h
>  create mode 100644 tools/objtool/arch/x86/include/cfi_regs.h
>  rename tools/objtool/{ => arch/x86}/orc_dump.c (98%)
>  rename tools/objtool/{ => arch/x86}/orc_gen.c (62%)
> 
> --
> 2.21.0
> 

Hi Julien,

The 0day bot reported a couple of issues with clang with this series;
the full report is available here (clang reports are only sent to our
mailing lists for manual triage for the time being):

https://groups.google.com/d/msg/clang-built-linux/MJbl_xPxawg/mWjgDgZgBwAJ

The first obvious issue is that this series appears to depend on a GCC
plugin? I'll be quite honest, objtool and everything it does is rather
over my head but I see this warning during configuration (allyesconfig):

WARNING: unmet direct dependencies detected for GCC_PLUGIN_SWITCH_TABLES
  Depends on [n]: GCC_PLUGINS [=n] && ARM64 [=y]
    Selected by [y]:
      - ARM64 [=y] && STACK_VALIDATION [=y]

Followed by the actual error:

error: unable to load plugin
'./scripts/gcc-plugins/arm64_switch_table_detection_plugin.so':
'./scripts/gcc-plugins/arm64_switch_table_detection_plugin.so: cannot
open shared object file: No such file or directory'

If this plugin is absolutely necessary and can't be implemented in
another way so that clang can be used, seems like STACK_VALIDATION
should only be selected on ARM64 when CONFIG_CC_IS_GCC is not zero.

The second issue I see is the -Wenum-conversion warnings; they are
pretty trivial to fix (see commit e7e83dd3ff1d ("objtool: Fix Clang
enum conversion warning") upstream and the below diff).

Would you mind addressing these in a v6 if you happen to do one?

Cheers,
Nathan

diff --git a/tools/objtool/arch/arm64/decode.c b/tools/objtool/arch/arm64/decode.c
index 5a5f82b5cb81..1ed6bf0c85ce 100644
--- a/tools/objtool/arch/arm64/decode.c
+++ b/tools/objtool/arch/arm64/decode.c
@@ -1518,7 +1518,7 @@ int arm_decode_ld_st_regs_unsc_imm(u32 instr, enum insn_type *type,
 		op->dest.type = OP_DEST_REG_INDIRECT;
 		op->dest.reg = rn;
 		op->dest.offset = SIGN_EXTEND(imm9, 9);
-		op->src.type = OP_DEST_REG;
+		op->src.type = OP_SRC_REG;
 		op->src.reg = rt;
 		op->src.offset = 0;
 		break;
@@ -1605,7 +1605,7 @@ int arm_decode_ld_st_regs_unsigned(u32 instr, enum insn_type *type,
 		op->dest.type = OP_DEST_REG_INDIRECT;
 		op->dest.reg = rn;
 		op->dest.offset = imm12;
-		op->src.type = OP_DEST_REG;
+		op->src.type = OP_SRC_REG;
 		op->src.reg = rt;
 		op->src.offset = 0;
 	}
@@ -1772,7 +1772,7 @@ int arm_decode_ld_st_imm_unpriv(u32 instr, enum insn_type *type,
 		op->dest.type = OP_DEST_REG_INDIRECT;
 		op->dest.reg = rn;
 		op->dest.offset = SIGN_EXTEND(imm9, 9);
-		op->src.type = OP_DEST_REG;
+		op->src.type = OP_SRC_REG;
 		op->src.reg = rt;
 		op->src.offset = 0;
 		break;
@@ -1852,7 +1852,7 @@ int arm_decode_atomic(u32 instr, enum insn_type *type,
 	list_add_tail(&op->list, ops_list);
 
 	op->src.reg = rn;
-	op->src.type = OP_DEST_REG_INDIRECT;
+	op->src.type = OP_SRC_REG_INDIRECT;
 	op->src.offset = 0;
 	op->dest.type = OP_DEST_REG;
 	op->dest.reg = rt;
@@ -2187,7 +2187,7 @@ int arm_decode_ldapr_stlr_unsc_imm(u32 instr, enum insn_type *type,
 		break;
 	default:
 		/* store */
-		op->dest.type = OP_SRC_REG_INDIRECT;
+		op->dest.type = OP_DEST_REG_INDIRECT;
 		op->dest.reg = rn;
 		op->dest.offset = SIGN_EXTEND(imm9, 9);
 		op->src.type = OP_SRC_REG;

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

* Re: [RFC v5 00/57] objtool: Add support for arm64
  2020-01-12  8:42 ` [RFC v5 00/57] objtool: Add support for arm64 Nathan Chancellor
@ 2020-01-13  7:57   ` Julien Thierry
  2020-01-21 10:31     ` Will Deacon
  2020-01-13 17:18   ` Nick Desaulniers
  1 sibling, 1 reply; 91+ messages in thread
From: Julien Thierry @ 2020-01-13  7:57 UTC (permalink / raw)
  To: Nathan Chancellor
  Cc: linux-kernel, linux-arm-kernel, jpoimboe, peterz, raphael.gault,
	catalin.marinas, will, clang-built-linux

Hi Nathan,

On 1/12/20 8:42 AM, Nathan Chancellor wrote:
> 
> Hi Julien,
> 
> The 0day bot reported a couple of issues with clang with this series;
> the full report is available here (clang reports are only sent to our
> mailing lists for manual triage for the time being):
> 
> https://groups.google.com/d/msg/clang-built-linux/MJbl_xPxawg/mWjgDgZgBwAJ
> 

Thanks, I'll have a look at those.

> The first obvious issue is that this series appears to depend on a GCC
> plugin? I'll be quite honest, objtool and everything it does is rather
> over my head but I see this warning during configuration (allyesconfig):
> 
> WARNING: unmet direct dependencies detected for GCC_PLUGIN_SWITCH_TABLES
>    Depends on [n]: GCC_PLUGINS [=n] && ARM64 [=y]
>      Selected by [y]:
>        - ARM64 [=y] && STACK_VALIDATION [=y]
> 
> Followed by the actual error:
> 
> error: unable to load plugin
> './scripts/gcc-plugins/arm64_switch_table_detection_plugin.so':
> './scripts/gcc-plugins/arm64_switch_table_detection_plugin.so: cannot
> open shared object file: No such file or directory'
> 
> If this plugin is absolutely necessary and can't be implemented in
> another way so that clang can be used, seems like STACK_VALIDATION
> should only be selected on ARM64 when CONFIG_CC_IS_GCC is not zero.
> 

So currently the plugin is necessary for proper validation. One option 
can be to just let objtool output false positives on files containing 
jump tables when the plugin cannot be used. But overall I guess it makes 
more sense to disable stack validation for non-gcc builds, for now.

Once people are happy with the state of things of arm64 objtool with gcc 
it might be worth looking at a clang plugin (although I don't know if 
the kernel has any support to build those at the moment).

In the mean time, I'll do as you suggest and rely on CC_IS_GCC.

> The second issue I see is the -Wenum-conversion warnings; they are
> pretty trivial to fix (see commit e7e83dd3ff1d ("objtool: Fix Clang
> enum conversion warning") upstream and the below diff).
> 

Oh yes, these are valid warnings. I'll fix those.

> Would you mind addressing these in a v6 if you happen to do one?
> 

Yes, I'll most likely do one as I don't expect this to be a final version.

Thanks for reporting those. I'll fix them in the next iteration.

Cheers,

-- 
Julien Thierry


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

* Re: [RFC v5 14/57] objtool: Do not look for STT_NOTYPE symbols
  2020-01-09 16:02 ` [RFC v5 14/57] objtool: Do not look for STT_NOTYPE symbols Julien Thierry
@ 2020-01-13 10:20   ` Julien Thierry
  0 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-13 10:20 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, raphael.gault, catalin.marinas, will



On 1/9/20 4:02 PM, Julien Thierry wrote:
> ELF symbols can have type STT_NOTYPE which have no standard semantics.
> 
> Arm64 objects will contain STT_NOTYPE symbols at the beginning of each
> section which aren't of any use to generic objtool code. Those symbols
> unfortunately overlap with the first function of the section.
> 
> Skip symbols with type STT_NOTYPE when looking up symbols.
> 

Turns out some x86 callable objects have STT_NOTYPE (in the current case 
error_entry in arch/x86/entry/entry_64.S, and it seems to be the case 
for all asm symbols annotated with SYM_CODE_START_LOCAL).

A solution that works both for x86 and arm64 is that if the symbol has 
STT_NOTYPE, continue looking for another symbol at the same offset. If 
none is available, return the STT_NOTYPE symbol.

I'll fix that in next iteration.

> Suggested-by: Raphael Gault <raphael.gault@arm.com>
> Signed-off-by: Julien Thierry <jthierry@redhat.com>
> ---
>   tools/objtool/elf.c | 3 ++-
>   1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c
> index edba4745f25a..c6ac0b771b73 100644
> --- a/tools/objtool/elf.c
> +++ b/tools/objtool/elf.c
> @@ -62,7 +62,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;
>   
> 

-- 
Julien Thierry


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

* Re: [RFC v5 00/57] objtool: Add support for arm64
  2020-01-12  8:42 ` [RFC v5 00/57] objtool: Add support for arm64 Nathan Chancellor
  2020-01-13  7:57   ` Julien Thierry
@ 2020-01-13 17:18   ` Nick Desaulniers
  1 sibling, 0 replies; 91+ messages in thread
From: Nick Desaulniers @ 2020-01-13 17:18 UTC (permalink / raw)
  To: Julien Thierry
  Cc: LKML, Linux ARM, Josh Poimboeuf, Peter Zijlstra, raphael.gault,
	Catalin Marinas, Will Deacon, clang-built-linux, Tom Stellard,
	Nathan Chancellor

On Sun, Jan 12, 2020 at 12:43 AM Nathan Chancellor
<natechancellor@gmail.com> wrote:
>
> On Thu, Jan 09, 2020 at 04:02:03PM +0000, Julien Thierry wrote:
> > Hi,
> >
> > This patch series is the continuation of Raphael's work [1]. All the
> > patches can be retrieved from:
> > git clone -b arm64-objtool-v5 https://github.com/julien-thierry/linux.git
> >
> > There still are some outstanding issues but the series is starting to
> > get pretty big so it is probably good to start having some discussions
> > on the current state of things.
> >
> > It felt necessary to split some of the patches (especially the arm64
> > decoder). In order to give Raphael credit for his work I used the
> > "Suggested-by" tag. If this is not the right way to give credit or if
> > it should be present on more patches do let me know.
> >
> > There still are some shortcomings. On defconfig here are the remaining
> > warnings:
> > * arch/arm64/crypto/crct10dif-ce-core.o: warning: objtool: crc_t10dif_pmull_p8()+0xf0: unsupported intra-function call
> > * arch/arm64/kernel/cpu_errata.o: warning: objtool: qcom_link_stack_sanitization()+0x4: unsupported intra-function call
> > Objtool currently does not support bl from a procedure to itself. This
> > is also an issue with retpolines. I need to investigate more to figure
> > out whether something can be done for this or if this file should not be
> > validated by objtool.
> >
> > * arch/arm64/kernel/efi-entry.o: warning: objtool: entry()+0xb0: sibling call from callable instruction with modified stack frame
> > The EFI entry jumps to code mapped by EFI. Objtool cannot know statically where the code flow is going.
> >
> > * arch/arm64/kernel/entry.o: warning: objtool: .entry.tramp.text+0x404: unsupported intra-function call
> > Need to figure out what is needed to handle aarch64 trampolines. x86
> > explicitly annotates theirs with ANNOTATE_NOSPEC_ALTERNATIVE and
> > patching them as alternatives.
> >
> > * arch/arm64/kernel/head.o: warning: objtool: .head.text+0x58: can't find jump dest instruction at .head.text+0x80884
> > This is actually a constant that turns out to be a valid branch opcode.
> > A possible solution could be to introduce a marco that explicitly
> > annotates constants placed in code sections.
> >
> > * arch/arm64/kernel/hibernate-asm.o: warning: objtool: el1_sync()+0x4: unsupported instruction in callable function
> > Symbols el<x>_* shouldn't be considered as callable functions. Should we
> > use SYM_CODE_END instead of PROC_END?
> >
> > * arch/arm64/kvm/hyp/hyp-entry.o: warning: objtool: .hyp.text: empty alternative at end of section
> > This is due to the arm64 alternative_cb. Currently, the feature
> > corresponding to the alternative_cb is defined as the current number of
> > features supported by the kernel, meaning the identifier is not fixed
> > accross kernel versions. This makes it a bit hard to detect these
> > alternative_cb for external tools.
> >
> > Would it be acceptable to set a fixed identifier for alternative_cb?
> > (probably 0xFF so it is always higher than the number of real features)
> >
> > * drivers/ata/libata-scsi.o: warning: objtool: ata_sas_queuecmd() falls through to next function ata_scsi_scan_host()
> > This is due to a limitation in the switch table metadata interpretation.
> > The compiler might create a table of unsigned offsets and then
> > compute the final offset as follows:
> >
> >       ldrb    offset_reg, [<offset_table>, <offset_idx>, uxtw]
> >       adr     base_reg, <base_addr>
> >       add     res_addr, base_reg, offset_reg, sxtb #2
> >
> > Effectively using the loaded offset as a signed value.
> > I don't have a simple way to solve this at the moment, I'd like to
> > avoid decoding the instructions to check which ones might sign extend
> > the loaded offset.
> >
> > * kernel/bpf/core.o: warning: objtool: ___bpf_prog_run()+0x44: sibling call from callable instruction with modified stack frame
> > This is because the function uses a C jump table which differ from
> > basic jump tables. Also, the code generated for C jump tables on arm64
> > does not follow the same form as the one for x86. So the existing x86 objtool
> > code handling C jump tables can't be used.
> >
> > I'll focus on understanding the arm64 pattern so objtool can handle them.
> >
> >
> > In the mean time, any feedback on the current state is appreciated.
> >
> > * Patches 1 to 18 adapts the current objtool code to make it easier to
> >   support new architectures.
> > * Patches 19 to 45 add the support for arm64 architecture to objtool.
> > * Patches 46 to 57 fix warnings reported by objtool on the existing
> >   arm64 code.
> >
> > Changes since RFCv4[1]:
> > * Rebase on v5.5-rc5
> > * Misc cleanup/bug fixes
> > * Fix some new objtool warnings reported on arm64 objects
> > * Make ORC subcommand optional since arm64 does not currently support it
> > * Support branch instructions in alternative sections when they jump
> >   within the same set of alternative instructions
> > * Replace the "extra" stack_op with a list of stack_op
> > * Split the decoder into multiple patches to ease review
> > * Mark constants generated by load literal instructions as bytes that
> >   should not be reached by execution flow
> > * Rework the switch table handling
> >
> > [1] https://lkml.org/lkml/2019/8/16/400
> >
> > Thanks,
> >
> > Julien
> >
> > -->
> >
> > Julien Thierry (43):
> >   objtool: check: Remove redundant checks on operand type
> >   objtool: check: Clean instruction state before each function
> >     validation
> >   objtool: check: Use arch specific values in restore_reg()
> >   objtool: check: Ignore empty alternative groups
> >   objtool: Give ORC functions consistent name
> >   objtool: Make ORC support optional
> >   objtool: Split generic and arch specific CFI definitions
> >   objtool: Abstract alternative special case handling
> >   objtool: check: Allow jumps from an alternative group to itself
> >   objtool: Do not look for STT_NOTYPE symbols
> >   objtool: Support addition to set frame pointer
> >   objtool: Support restoring BP from the stack without POP
> >   objtool: Make stack validation more generic
> >   objtool: Support multiple stack_op per instruction
> >   objtool: arm64: Decode unknown instructions
> >   objtool: arm64: Decode simple data processing instructions
> >   objtool: arm64: Decode add/sub immediate instructions
> >   objtool: arm64: Decode logical data processing instructions
> >   objtool: arm64: Decode system instructions not affecting the flow
> >   objtool: arm64: Decode calls to higher EL
> >   objtool: arm64: Decode brk instruction
> >   objtool: arm64: Decode instruction triggering context switch
> >   objtool: arm64: Decode branch instructions with PC relative immediates
> >   objtool: arm64: Decode branch to register instruction
> >   objtool: arm64: Decode basic load/stores
> >   objtool: arm64: Decode load/store with register offset
> >   objtool: arm64: Decode load/store register pair instructions
> >   objtool: arm64: Decode FP/SIMD load/store instructions
> >   objtool: arm64: Decode load/store exclusive
> >   objtool: arm64: Decode atomic load/store
> >   objtool: arm64: Decode pointer auth load instructions
> >   objtool: arm64: Decode load acquire/store release
> >   objtool: arm64: Decode load/store with memory tag
> >   objtool: arm64: Decode load literal
> >   objtool: arm64: Decode register data processing instructions
> >   objtool: arm64: Decode FP/SIMD data processing instructions
> >   objtool: arm64: Decode SVE instructions
> >   objtool: arm64: Implement functions to add switch tables alternatives
> >   arm64: Generate no-ops to pad executable section
> >   arm64: Move constant to rodata
> >   arm64: Mark sigreturn32.o as containing non standard code
> >   arm64: entry: Avoid empty alternatives entries
> >   arm64: crypto: Remove redundant branch
> >
> > Raphael Gault (14):
> >   objtool: Add abstraction for computation of symbols offsets
> >   objtool: orc: Refactor ORC API for other architectures to implement.
> >   objtool: Move registers and control flow to arch-dependent code
> >   objtool: Refactor switch-tables code to support other architectures
> >   objtool: arm64: Add required implementation for supporting the aarch64
> >     architecture in objtool.
> >   gcc-plugins: objtool: Add plugin to detect switch table on arm64
> >   objtool: arm64: Enable stack validation for arm64
> >   arm64: alternative: Mark .altinstr_replacement as containing
> >     executable instructions
> >   arm64: assembler: Add macro to annotate asm function having non
> >     standard stack-frame.
> >   arm64: sleep: Prevent stack frame warnings from objtool
> >   arm64: kvm: Annotate non-standard stack frame functions
> >   arm64: kernel: Add exception on kuser32 to prevent stack analysis
> >   arm64: crypto: Add exceptions for crypto object to prevent stack
> >     analysis
> >   arm64: kernel: Annotate non-standard stack frame functions
> >
> >  arch/arm64/Kconfig                            |    2 +
> >  arch/arm64/crypto/Makefile                    |    3 +
> >  arch/arm64/crypto/sha1-ce-core.S              |    3 +-
> >  arch/arm64/crypto/sha2-ce-core.S              |    3 +-
> >  arch/arm64/crypto/sha3-ce-core.S              |    3 +-
> >  arch/arm64/crypto/sha512-ce-core.S            |    3 +-
> >  arch/arm64/include/asm/alternative.h          |    2 +-
> >  arch/arm64/kernel/Makefile                    |    4 +
> >  arch/arm64/kernel/entry.S                     |    4 +-
> >  arch/arm64/kernel/hyp-stub.S                  |    3 +
> >  arch/arm64/kernel/relocate_kernel.S           |    5 +
> >  arch/arm64/kernel/sleep.S                     |    5 +
> >  arch/arm64/kvm/hyp-init.S                     |    3 +
> >  arch/arm64/kvm/hyp/entry.S                    |    3 +
> >  include/linux/frame.h                         |   19 +-
> >  scripts/Makefile.gcc-plugins                  |    2 +
> >  scripts/gcc-plugins/Kconfig                   |    4 +
> >  .../arm64_switch_table_detection_plugin.c     |   94 +
> >  tools/objtool/Build                           |    4 +-
> >  tools/objtool/Makefile                        |   13 +-
> >  tools/objtool/arch.h                          |   14 +-
> >  tools/objtool/arch/arm64/Build                |    5 +
> >  tools/objtool/arch/arm64/arch_special.c       |  262 ++
> >  tools/objtool/arch/arm64/bit_operations.c     |   69 +
> >  tools/objtool/arch/arm64/decode.c             | 2866 +++++++++++++++++
> >  .../objtool/arch/arm64/include/arch_special.h |   23 +
> >  .../arch/arm64/include/bit_operations.h       |   31 +
> >  tools/objtool/arch/arm64/include/cfi_regs.h   |   44 +
> >  .../objtool/arch/arm64/include/insn_decode.h  |  206 ++
> >  tools/objtool/arch/x86/Build                  |    3 +
> >  tools/objtool/arch/x86/arch_special.c         |  182 ++
> >  tools/objtool/arch/x86/decode.c               |   29 +-
> >  tools/objtool/arch/x86/include/arch_special.h |   28 +
> >  tools/objtool/arch/x86/include/cfi_regs.h     |   25 +
> >  tools/objtool/{ => arch/x86}/orc_dump.c       |    4 +-
> >  tools/objtool/{ => arch/x86}/orc_gen.c        |  114 +-
> >  tools/objtool/cfi.h                           |   21 +-
> >  tools/objtool/check.c                         |  461 +--
> >  tools/objtool/check.h                         |   13 +-
> >  tools/objtool/elf.c                           |    3 +-
> >  tools/objtool/objtool.c                       |    2 +
> >  tools/objtool/orc.h                           |   38 +-
> >  tools/objtool/special.c                       |   44 +-
> >  tools/objtool/special.h                       |   13 +
> >  44 files changed, 4282 insertions(+), 400 deletions(-)
> >  create mode 100644 scripts/gcc-plugins/arm64_switch_table_detection_plugin.c
> >  create mode 100644 tools/objtool/arch/arm64/Build
> >  create mode 100644 tools/objtool/arch/arm64/arch_special.c
> >  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/bit_operations.h
> >  create mode 100644 tools/objtool/arch/arm64/include/cfi_regs.h
> >  create mode 100644 tools/objtool/arch/arm64/include/insn_decode.h
> >  create mode 100644 tools/objtool/arch/x86/arch_special.c
> >  create mode 100644 tools/objtool/arch/x86/include/arch_special.h
> >  create mode 100644 tools/objtool/arch/x86/include/cfi_regs.h
> >  rename tools/objtool/{ => arch/x86}/orc_dump.c (98%)
> >  rename tools/objtool/{ => arch/x86}/orc_gen.c (62%)
> >
> > --
> > 2.21.0
> >
>
> Hi Julien,
>
> The 0day bot reported a couple of issues with clang with this series;
> the full report is available here (clang reports are only sent to our
> mailing lists for manual triage for the time being):
>
> https://groups.google.com/d/msg/clang-built-linux/MJbl_xPxawg/mWjgDgZgBwAJ
>
> The first obvious issue is that this series appears to depend on a GCC
> plugin? I'll be quite honest, objtool and everything it does is rather
> over my head but I see this warning during configuration (allyesconfig):
>
> WARNING: unmet direct dependencies detected for GCC_PLUGIN_SWITCH_TABLES
>   Depends on [n]: GCC_PLUGINS [=n] && ARM64 [=y]
>     Selected by [y]:
>       - ARM64 [=y] && STACK_VALIDATION [=y]
>
> Followed by the actual error:
>
> error: unable to load plugin
> './scripts/gcc-plugins/arm64_switch_table_detection_plugin.so':
> './scripts/gcc-plugins/arm64_switch_table_detection_plugin.so: cannot
> open shared object file: No such file or directory'
>
> If this plugin is absolutely necessary and can't be implemented in
> another way so that clang can be used, seems like STACK_VALIDATION
> should only be selected on ARM64 when CONFIG_CC_IS_GCC is not zero.

Ah, cool. I look forward to having objtool check additional
architectures.  It's found legitimate codegen bugs in Clang before.
We should make sure this series doesn't regress Clang builds. Can you
please help ensure it doesn't?
$ ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- make CC=clang
We're happy to help take a look at anything that looks suspicious, but
some code sequences may be quite different than GCC.  We can't be
adding hard dependencies on GCC plugins.

>
> The second issue I see is the -Wenum-conversion warnings; they are
> pretty trivial to fix (see commit e7e83dd3ff1d ("objtool: Fix Clang
> enum conversion warning") upstream and the below diff).
>
> Would you mind addressing these in a v6 if you happen to do one?
>
> Cheers,
> Nathan
>
> diff --git a/tools/objtool/arch/arm64/decode.c b/tools/objtool/arch/arm64/decode.c
> index 5a5f82b5cb81..1ed6bf0c85ce 100644
> --- a/tools/objtool/arch/arm64/decode.c
> +++ b/tools/objtool/arch/arm64/decode.c
> @@ -1518,7 +1518,7 @@ int arm_decode_ld_st_regs_unsc_imm(u32 instr, enum insn_type *type,
>                 op->dest.type = OP_DEST_REG_INDIRECT;
>                 op->dest.reg = rn;
>                 op->dest.offset = SIGN_EXTEND(imm9, 9);
> -               op->src.type = OP_DEST_REG;
> +               op->src.type = OP_SRC_REG;
>                 op->src.reg = rt;
>                 op->src.offset = 0;
>                 break;
> @@ -1605,7 +1605,7 @@ int arm_decode_ld_st_regs_unsigned(u32 instr, enum insn_type *type,
>                 op->dest.type = OP_DEST_REG_INDIRECT;
>                 op->dest.reg = rn;
>                 op->dest.offset = imm12;
> -               op->src.type = OP_DEST_REG;
> +               op->src.type = OP_SRC_REG;
>                 op->src.reg = rt;
>                 op->src.offset = 0;
>         }
> @@ -1772,7 +1772,7 @@ int arm_decode_ld_st_imm_unpriv(u32 instr, enum insn_type *type,
>                 op->dest.type = OP_DEST_REG_INDIRECT;
>                 op->dest.reg = rn;
>                 op->dest.offset = SIGN_EXTEND(imm9, 9);
> -               op->src.type = OP_DEST_REG;
> +               op->src.type = OP_SRC_REG;
>                 op->src.reg = rt;
>                 op->src.offset = 0;
>                 break;
> @@ -1852,7 +1852,7 @@ int arm_decode_atomic(u32 instr, enum insn_type *type,
>         list_add_tail(&op->list, ops_list);
>
>         op->src.reg = rn;
> -       op->src.type = OP_DEST_REG_INDIRECT;
> +       op->src.type = OP_SRC_REG_INDIRECT;
>         op->src.offset = 0;
>         op->dest.type = OP_DEST_REG;
>         op->dest.reg = rt;
> @@ -2187,7 +2187,7 @@ int arm_decode_ldapr_stlr_unsc_imm(u32 instr, enum insn_type *type,
>                 break;
>         default:
>                 /* store */
> -               op->dest.type = OP_SRC_REG_INDIRECT;
> +               op->dest.type = OP_DEST_REG_INDIRECT;
>                 op->dest.reg = rn;
>                 op->dest.offset = SIGN_EXTEND(imm9, 9);
>                 op->src.type = OP_SRC_REG;
>
> --
> You received this message because you are subscribed to the Google Groups "Clang Built Linux" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to clang-built-linux+unsubscribe@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/clang-built-linux/20200112084258.GA44004%40ubuntu-x2-xlarge-x86.



-- 
Thanks,
~Nick Desaulniers

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

* Re: [RFC v5 44/57] objtool: arm64: Implement functions to add switch tables alternatives
  2020-01-09 16:02 ` [RFC v5 44/57] objtool: arm64: Implement functions to add switch tables alternatives Julien Thierry
@ 2020-01-15 16:37   ` Raphael Gault
  2020-01-17  8:28     ` Julien Thierry
  0 siblings, 1 reply; 91+ messages in thread
From: Raphael Gault @ 2020-01-15 16:37 UTC (permalink / raw)
  To: Julien Thierry, linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, catalin.marinas, will

Hi Julien,

On 1/9/20 4:02 PM, Julien Thierry wrote:
> This patch implements the functions required to identify and add as
> alternatives all the possible destinations of the switch table.
> This implementation relies on the new plugin introduced previously which
> records information about the switch-table in a
> .discard.switch_table_information section.

I think you forgot to update the name of the section with respect to 
what was done in the previous patch (.discard.switch_table_info instead 
of .discard.switch_table_information).

> 
> Signed-off-by: Raphael Gault <raphael.gault@arm.com>
> [J.T.: Update arch implementation to new prototypes,
>         Update switch table information section name,
>         Do some clean up,
>         Use the offset sign information,
>         Use the newly added rela to find the corresponding jump instruction]
> Signed-off-by: Julien Thierry <jthierry@redhat.com>
> ---
>   tools/objtool/arch/arm64/arch_special.c       | 251 +++++++++++++++++-
>   .../objtool/arch/arm64/include/arch_special.h |   2 +
>   tools/objtool/check.c                         |   4 +-
>   tools/objtool/check.h                         |   2 +
>   4 files changed, 255 insertions(+), 4 deletions(-)
> 
> diff --git a/tools/objtool/arch/arm64/arch_special.c b/tools/objtool/arch/arm64/arch_special.c
> index 5239489c9c57..a15f6697dc74 100644
> --- a/tools/objtool/arch/arm64/arch_special.c
> +++ b/tools/objtool/arch/arm64/arch_special.c
> @@ -1,15 +1,262 @@
>   // SPDX-License-Identifier: GPL-2.0-or-later
>   
> +#include <stdlib.h>
> +#include <string.h>
> +
>   #include "../../special.h"
> +#include "../../warn.h"
> +#include "arch_special.h"
> +#include "bit_operations.h"
> +#include "insn_decode.h"
> +
> +/*
> + * The arm64_switch_table_detection_plugin generate an array of elements
> + * described by the following structure.
> + * Each jump table found in the compilation unit is associated with one of
> + * entries of the array.
> + */
> +struct switch_table_info {
> +	u64 switch_table_ref; // Relocation target referencing the beginning of the jump table
> +	u64 dyn_jump_ref; // Relocation target referencing the set of instructions setting up the jump to the table
> +	u64 nb_entries;
> +	u64 offset_unsigned;
> +} __attribute__((__packed__));
> +
> +static bool insn_is_adr_pcrel(struct instruction *insn)
> +{
> +	u32 opcode = *(u32 *)(insn->sec->data->d_buf + insn->offset);
> +
> +	return ((opcode >> 24) & 0x1f) == 0x10;
> +}
> +
> +static s64 next_offset(void *table, u8 entry_size, bool is_signed)
> +{
> +	if (!is_signed) {
> +		switch (entry_size) {
> +		case 1:
> +			return *(u8 *)(table);
> +		case 2:
> +			return *(u16 *)(table);
> +		default:
> +			return *(u32 *)(table);
> +		}
> +	} else {
> +		switch (entry_size) {
> +		case 1:
> +			return *(s8 *)(table);
> +		case 2:
> +			return *(s16 *)(table);
> +		default:
> +			return *(s32 *)(table);
> +		}
> +	}
> +}
> +
> +static u32 get_table_entry_size(u32 insn)
> +{
> +	unsigned char size = (insn >> 30) & ONES(2);
> +
> +	switch (size) {
> +	case 0:
> +		return 1;
> +	case 1:
> +		return 2;
> +	default:
> +		return 4;
> +	}
> +}
> +
> +static int add_possible_branch(struct objtool_file *file,
> +			       struct instruction *insn,
> +			       u32 base, s64 offset)
> +{
> +	struct instruction *dest_insn;
> +	struct alternative *alt;
> +
> +	offset = base + 4 * offset;
> +
> +	dest_insn = find_insn(file, insn->sec, offset);
> +	if (!dest_insn)
> +		return 0;
> +
> +	alt = calloc(1, sizeof(*alt));
> +	if (!alt) {
> +		WARN("allocation failure, can't add jump alternative");
> +		return -1;
> +	}
> +
> +	alt->insn = dest_insn;
> +	alt->skip_orig = true;
> +	list_add_tail(&alt->list, &insn->alts);
> +	return 0;
> +}
> +
> +static struct switch_table_info *get_swt_info(struct section *swt_info_sec,
> +					      struct instruction *insn)
> +{
> +	u64 *table_ref;
> +
> +	if (!insn->jump_table) {
> +		WARN("no jump table available for %s+0x%lx",
> +		     insn->sec->name, insn->offset);
> +		return NULL;
> +	}
> +	table_ref = (void *)(swt_info_sec->data->d_buf +
> +			     insn->jump_table->offset);
> +	return container_of(table_ref, struct switch_table_info,
> +			    switch_table_ref);
> +}
> +
> +static int add_arm64_jump_table_dests(struct objtool_file *file,
> +				      struct instruction *insn)
> +{
> +	struct switch_table_info *swt_info;
> +	struct section *objtool_data;
> +	struct section *rodata_sec;
> +	struct section *branch_sec;
> +	struct instruction *pre_jump_insn;
> +	u8 *switch_table;
> +	u32 entry_size;
> +
> +	objtool_data = find_section_by_name(file->elf,
> +					    ".discard.switch_table_info");
> +	if (!objtool_data)
> +		return 0;
> +
> +	/*
> +	 * 1. Identify entry for the switch table
> +	 * 2. Retrieve branch instruction
> +	 * 3. Retrieve base offset
> +	 * 3. For all entries in switch table:
> +	 *     3.1. Compute new offset
> +	 *     3.2. Create alternative instruction
> +	 *     3.3. Add alt_instr to insn->alts list
> +	 */
> +	swt_info = get_swt_info(objtool_data, insn);
> +
> +	/* retrieving pre jump instruction (ldr) */
> +	branch_sec = insn->sec;
> +	pre_jump_insn = find_insn(file, branch_sec,
> +				  insn->offset - 3 * sizeof(u32));
> +	entry_size = get_table_entry_size(*(u32 *)(branch_sec->data->d_buf +
> +						   pre_jump_insn->offset));
> +
> +	/* retrieving switch table content */
> +	rodata_sec = find_section_by_name(file->elf, ".rodata");
> +	switch_table = (u8 *)(rodata_sec->data->d_buf +
> +			      insn->jump_table->addend);
> +
> +	/*
> +	 * iterating over the pre-jumps instruction in order to
> +	 * retrieve switch base offset.
> +	 */
> +	while (pre_jump_insn && pre_jump_insn->offset <= insn->offset) {
> +		if (insn_is_adr_pcrel(pre_jump_insn)) {
> +			u64 base_offset;
> +			int i;
> +
> +			base_offset = pre_jump_insn->offset +
> +				      pre_jump_insn->immediate;
> +
> +			/*
> +			 * Once we have the switch table entry size
> +			 * we add every possible destination using
> +			 * alternatives of the original branch
> +			 * instruction
> +			 */
> +			for (i = 0; i < swt_info->nb_entries; i++) {
> +				s64 table_offset = next_offset(switch_table,
> +							       entry_size,
> +							       !swt_info->offset_unsigned);
> +
> +				if (add_possible_branch(file, insn,
> +							base_offset,
> +							table_offset)) {
> +					return -1;
> +				}
> +				switch_table += entry_size;
> +			}
> +			break;
> +		}
> +		pre_jump_insn = next_insn_same_sec(file, pre_jump_insn);
> +	}
> +
> +	return 0;
> +}
>   
>   int arch_add_jump_table_dests(struct objtool_file *file,
>   			      struct instruction *insn)
>   {
> -	return 0;
> +	return add_arm64_jump_table_dests(file, insn);
>   }
>   
> +static struct rela *find_swt_info_jump_rela(struct section *swt_info_sec,
> +					    u32 index)
> +{
> +	u32 rela_offset;
> +
> +	rela_offset = index * sizeof(struct switch_table_info) +
> +		      offsetof(struct switch_table_info, dyn_jump_ref);
> +	return find_rela_by_dest(swt_info_sec, rela_offset);
> +}
> +
> +static struct rela *find_swt_info_table_rela(struct section *swt_info_sec,
> +					     u32 index)
> +{
> +	u32 rela_offset;
> +
> +	rela_offset = index * sizeof(struct switch_table_info) +
> +		      offsetof(struct switch_table_info, switch_table_ref);
> +	return find_rela_by_dest(swt_info_sec, rela_offset);
> +}
> +
> +/*
> + * Aarch64 jump tables are just arrays of offsets (of varying size/signess)
> + * representing the potential destination from a base address loaded by an adr
> + * instruction.
> + *
> + * Aarch64 branches to jump tables are composed of multiple instructions:
> + *
> + *     ldr<?>  x_offset, [x_offsets_table, x_index, ...]
> + *     adr     x_dest_base, <addr>
> + *     add     x_dest, x_target_base, x_offset, ...
> + *     br      x_dest
> + *
> + * The arm64_switch_table_detection_plugin will make the connection between
> + * the instruction setting x_offsets_table (dyn_jump_ref) and the actual
> + * table of offsets (switch_table_ref)
> + */
>   struct rela *arch_find_switch_table(struct objtool_file *file,
>   				    struct instruction *insn)
>   {
> -	return NULL;
> +	struct section *objtool_data;
> +	struct rela *res = NULL;
> +	u32 nb_swt_entries = 0;
> +	u32 i;
> +
> +	objtool_data = find_section_by_name(file->elf,
> +					    ".discard.switch_table_info");
> +	if (objtool_data)
> +		nb_swt_entries = objtool_data->sh.sh_size /
> +				 sizeof(struct switch_table_info);
> +
> +	for (i = 0; i < nb_swt_entries; i++) {
> +		struct rela *info_rela;
> +
> +		info_rela = find_swt_info_jump_rela(objtool_data, i);
> +		if (info_rela && info_rela->sym->sec == insn->sec &&
> +		    info_rela->addend == insn->offset) {
> +			if (res) {
> +				WARN_FUNC("duplicate objtool_data rela",
> +					  info_rela->sec, info_rela->offset);
> +				continue;
> +			}
> +			res = find_swt_info_table_rela(objtool_data, i);
> +			if (!res)
> +				WARN_FUNC("missing relocation in objtool data",
> +					  info_rela->sec, info_rela->offset);
> +		}
> +	}
> +
> +	return res;
>   }
> diff --git a/tools/objtool/arch/arm64/include/arch_special.h b/tools/objtool/arch/arm64/include/arch_special.h
> index a82a9b3e51df..b96bcee308cf 100644
> --- a/tools/objtool/arch/arm64/include/arch_special.h
> +++ b/tools/objtool/arch/arm64/include/arch_special.h
> @@ -3,6 +3,8 @@
>   #ifndef _ARM64_ARCH_SPECIAL_H
>   #define _ARM64_ARCH_SPECIAL_H
>   
> +#include <linux/types.h>
> +
>   #define EX_ENTRY_SIZE		8
>   #define EX_ORIG_OFFSET		0
>   #define EX_NEW_OFFSET		4
> diff --git a/tools/objtool/check.c b/tools/objtool/check.c
> index e0c6bda261c8..80ea5bbd36ab 100644
> --- a/tools/objtool/check.c
> +++ b/tools/objtool/check.c
> @@ -33,8 +33,8 @@ struct instruction *find_insn(struct objtool_file *file,
>   	return NULL;
>   }
>   
> -static struct instruction *next_insn_same_sec(struct objtool_file *file,
> -					      struct instruction *insn)
> +struct instruction *next_insn_same_sec(struct objtool_file *file,
> +				       struct instruction *insn)
>   {
>   	struct instruction *next = list_next_entry(insn, list);
>   
> diff --git a/tools/objtool/check.h b/tools/objtool/check.h
> index 91adec42782c..15165d04d9cb 100644
> --- a/tools/objtool/check.h
> +++ b/tools/objtool/check.h
> @@ -66,6 +66,8 @@ int check(const char *objname, bool orc);
>   
>   struct instruction *find_insn(struct objtool_file *file,
>   			      struct section *sec, unsigned long offset);
> +struct instruction *next_insn_same_sec(struct objtool_file *file,
> +				       struct instruction *insn);
>   
>   #define for_each_insn(file, insn)					\
>   	list_for_each_entry(insn, &file->insn_list, list)
> 

Cheers,

-- 
Raphaël Gault

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

* Re: [RFC v5 44/57] objtool: arm64: Implement functions to add switch tables alternatives
  2020-01-15 16:37   ` Raphael Gault
@ 2020-01-17  8:28     ` Julien Thierry
  0 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-17  8:28 UTC (permalink / raw)
  To: Raphael Gault, linux-kernel, linux-arm-kernel
  Cc: jpoimboe, peterz, catalin.marinas, will

Hi Raphaël,

On 1/15/20 4:37 PM, Raphael Gault wrote:
> Hi Julien,
> 
> On 1/9/20 4:02 PM, Julien Thierry wrote:
>> This patch implements the functions required to identify and add as
>> alternatives all the possible destinations of the switch table.
>> This implementation relies on the new plugin introduced previously which
>> records information about the switch-table in a
>> .discard.switch_table_information section.
> 
> I think you forgot to update the name of the section with respect to 
> what was done in the previous patch (.discard.switch_table_info instead 
> of .discard.switch_table_information).
> 

Oops, you are correct. Thanks for spotting this. I'll update the commit.

Thanks,

>>
>> Signed-off-by: Raphael Gault <raphael.gault@arm.com>
>> [J.T.: Update arch implementation to new prototypes,
>>         Update switch table information section name,
>>         Do some clean up,
>>         Use the offset sign information,
>>         Use the newly added rela to find the corresponding jump 
>> instruction]
>> Signed-off-by: Julien Thierry <jthierry@redhat.com>
>> ---
>>   tools/objtool/arch/arm64/arch_special.c       | 251 +++++++++++++++++-
>>   .../objtool/arch/arm64/include/arch_special.h |   2 +
>>   tools/objtool/check.c                         |   4 +-
>>   tools/objtool/check.h                         |   2 +
>>   4 files changed, 255 insertions(+), 4 deletions(-)
>>
>> diff --git a/tools/objtool/arch/arm64/arch_special.c 
>> b/tools/objtool/arch/arm64/arch_special.c
>> index 5239489c9c57..a15f6697dc74 100644
>> --- a/tools/objtool/arch/arm64/arch_special.c
>> +++ b/tools/objtool/arch/arm64/arch_special.c
>> @@ -1,15 +1,262 @@
>>   // SPDX-License-Identifier: GPL-2.0-or-later
>> +#include <stdlib.h>
>> +#include <string.h>
>> +
>>   #include "../../special.h"
>> +#include "../../warn.h"
>> +#include "arch_special.h"
>> +#include "bit_operations.h"
>> +#include "insn_decode.h"
>> +
>> +/*
>> + * The arm64_switch_table_detection_plugin generate an array of elements
>> + * described by the following structure.
>> + * Each jump table found in the compilation unit is associated with 
>> one of
>> + * entries of the array.
>> + */
>> +struct switch_table_info {
>> +    u64 switch_table_ref; // Relocation target referencing the 
>> beginning of the jump table
>> +    u64 dyn_jump_ref; // Relocation target referencing the set of 
>> instructions setting up the jump to the table
>> +    u64 nb_entries;
>> +    u64 offset_unsigned;
>> +} __attribute__((__packed__));
>> +
>> +static bool insn_is_adr_pcrel(struct instruction *insn)
>> +{
>> +    u32 opcode = *(u32 *)(insn->sec->data->d_buf + insn->offset);
>> +
>> +    return ((opcode >> 24) & 0x1f) == 0x10;
>> +}
>> +
>> +static s64 next_offset(void *table, u8 entry_size, bool is_signed)
>> +{
>> +    if (!is_signed) {
>> +        switch (entry_size) {
>> +        case 1:
>> +            return *(u8 *)(table);
>> +        case 2:
>> +            return *(u16 *)(table);
>> +        default:
>> +            return *(u32 *)(table);
>> +        }
>> +    } else {
>> +        switch (entry_size) {
>> +        case 1:
>> +            return *(s8 *)(table);
>> +        case 2:
>> +            return *(s16 *)(table);
>> +        default:
>> +            return *(s32 *)(table);
>> +        }
>> +    }
>> +}
>> +
>> +static u32 get_table_entry_size(u32 insn)
>> +{
>> +    unsigned char size = (insn >> 30) & ONES(2);
>> +
>> +    switch (size) {
>> +    case 0:
>> +        return 1;
>> +    case 1:
>> +        return 2;
>> +    default:
>> +        return 4;
>> +    }
>> +}
>> +
>> +static int add_possible_branch(struct objtool_file *file,
>> +                   struct instruction *insn,
>> +                   u32 base, s64 offset)
>> +{
>> +    struct instruction *dest_insn;
>> +    struct alternative *alt;
>> +
>> +    offset = base + 4 * offset;
>> +
>> +    dest_insn = find_insn(file, insn->sec, offset);
>> +    if (!dest_insn)
>> +        return 0;
>> +
>> +    alt = calloc(1, sizeof(*alt));
>> +    if (!alt) {
>> +        WARN("allocation failure, can't add jump alternative");
>> +        return -1;
>> +    }
>> +
>> +    alt->insn = dest_insn;
>> +    alt->skip_orig = true;
>> +    list_add_tail(&alt->list, &insn->alts);
>> +    return 0;
>> +}
>> +
>> +static struct switch_table_info *get_swt_info(struct section 
>> *swt_info_sec,
>> +                          struct instruction *insn)
>> +{
>> +    u64 *table_ref;
>> +
>> +    if (!insn->jump_table) {
>> +        WARN("no jump table available for %s+0x%lx",
>> +             insn->sec->name, insn->offset);
>> +        return NULL;
>> +    }
>> +    table_ref = (void *)(swt_info_sec->data->d_buf +
>> +                 insn->jump_table->offset);
>> +    return container_of(table_ref, struct switch_table_info,
>> +                switch_table_ref);
>> +}
>> +
>> +static int add_arm64_jump_table_dests(struct objtool_file *file,
>> +                      struct instruction *insn)
>> +{
>> +    struct switch_table_info *swt_info;
>> +    struct section *objtool_data;
>> +    struct section *rodata_sec;
>> +    struct section *branch_sec;
>> +    struct instruction *pre_jump_insn;
>> +    u8 *switch_table;
>> +    u32 entry_size;
>> +
>> +    objtool_data = find_section_by_name(file->elf,
>> +                        ".discard.switch_table_info");
>> +    if (!objtool_data)
>> +        return 0;
>> +
>> +    /*
>> +     * 1. Identify entry for the switch table
>> +     * 2. Retrieve branch instruction
>> +     * 3. Retrieve base offset
>> +     * 3. For all entries in switch table:
>> +     *     3.1. Compute new offset
>> +     *     3.2. Create alternative instruction
>> +     *     3.3. Add alt_instr to insn->alts list
>> +     */
>> +    swt_info = get_swt_info(objtool_data, insn);
>> +
>> +    /* retrieving pre jump instruction (ldr) */
>> +    branch_sec = insn->sec;
>> +    pre_jump_insn = find_insn(file, branch_sec,
>> +                  insn->offset - 3 * sizeof(u32));
>> +    entry_size = get_table_entry_size(*(u32 *)(branch_sec->data->d_buf +
>> +                           pre_jump_insn->offset));
>> +
>> +    /* retrieving switch table content */
>> +    rodata_sec = find_section_by_name(file->elf, ".rodata");
>> +    switch_table = (u8 *)(rodata_sec->data->d_buf +
>> +                  insn->jump_table->addend);
>> +
>> +    /*
>> +     * iterating over the pre-jumps instruction in order to
>> +     * retrieve switch base offset.
>> +     */
>> +    while (pre_jump_insn && pre_jump_insn->offset <= insn->offset) {
>> +        if (insn_is_adr_pcrel(pre_jump_insn)) {
>> +            u64 base_offset;
>> +            int i;
>> +
>> +            base_offset = pre_jump_insn->offset +
>> +                      pre_jump_insn->immediate;
>> +
>> +            /*
>> +             * Once we have the switch table entry size
>> +             * we add every possible destination using
>> +             * alternatives of the original branch
>> +             * instruction
>> +             */
>> +            for (i = 0; i < swt_info->nb_entries; i++) {
>> +                s64 table_offset = next_offset(switch_table,
>> +                                   entry_size,
>> +                                   !swt_info->offset_unsigned);
>> +
>> +                if (add_possible_branch(file, insn,
>> +                            base_offset,
>> +                            table_offset)) {
>> +                    return -1;
>> +                }
>> +                switch_table += entry_size;
>> +            }
>> +            break;
>> +        }
>> +        pre_jump_insn = next_insn_same_sec(file, pre_jump_insn);
>> +    }
>> +
>> +    return 0;
>> +}
>>   int arch_add_jump_table_dests(struct objtool_file *file,
>>                     struct instruction *insn)
>>   {
>> -    return 0;
>> +    return add_arm64_jump_table_dests(file, insn);
>>   }
>> +static struct rela *find_swt_info_jump_rela(struct section 
>> *swt_info_sec,
>> +                        u32 index)
>> +{
>> +    u32 rela_offset;
>> +
>> +    rela_offset = index * sizeof(struct switch_table_info) +
>> +              offsetof(struct switch_table_info, dyn_jump_ref);
>> +    return find_rela_by_dest(swt_info_sec, rela_offset);
>> +}
>> +
>> +static struct rela *find_swt_info_table_rela(struct section 
>> *swt_info_sec,
>> +                         u32 index)
>> +{
>> +    u32 rela_offset;
>> +
>> +    rela_offset = index * sizeof(struct switch_table_info) +
>> +              offsetof(struct switch_table_info, switch_table_ref);
>> +    return find_rela_by_dest(swt_info_sec, rela_offset);
>> +}
>> +
>> +/*
>> + * Aarch64 jump tables are just arrays of offsets (of varying 
>> size/signess)
>> + * representing the potential destination from a base address loaded 
>> by an adr
>> + * instruction.
>> + *
>> + * Aarch64 branches to jump tables are composed of multiple 
>> instructions:
>> + *
>> + *     ldr<?>  x_offset, [x_offsets_table, x_index, ...]
>> + *     adr     x_dest_base, <addr>
>> + *     add     x_dest, x_target_base, x_offset, ...
>> + *     br      x_dest
>> + *
>> + * The arm64_switch_table_detection_plugin will make the connection 
>> between
>> + * the instruction setting x_offsets_table (dyn_jump_ref) and the actual
>> + * table of offsets (switch_table_ref)
>> + */
>>   struct rela *arch_find_switch_table(struct objtool_file *file,
>>                       struct instruction *insn)
>>   {
>> -    return NULL;
>> +    struct section *objtool_data;
>> +    struct rela *res = NULL;
>> +    u32 nb_swt_entries = 0;
>> +    u32 i;
>> +
>> +    objtool_data = find_section_by_name(file->elf,
>> +                        ".discard.switch_table_info");
>> +    if (objtool_data)
>> +        nb_swt_entries = objtool_data->sh.sh_size /
>> +                 sizeof(struct switch_table_info);
>> +
>> +    for (i = 0; i < nb_swt_entries; i++) {
>> +        struct rela *info_rela;
>> +
>> +        info_rela = find_swt_info_jump_rela(objtool_data, i);
>> +        if (info_rela && info_rela->sym->sec == insn->sec &&
>> +            info_rela->addend == insn->offset) {
>> +            if (res) {
>> +                WARN_FUNC("duplicate objtool_data rela",
>> +                      info_rela->sec, info_rela->offset);
>> +                continue;
>> +            }
>> +            res = find_swt_info_table_rela(objtool_data, i);
>> +            if (!res)
>> +                WARN_FUNC("missing relocation in objtool data",
>> +                      info_rela->sec, info_rela->offset);
>> +        }
>> +    }
>> +
>> +    return res;
>>   }
>> diff --git a/tools/objtool/arch/arm64/include/arch_special.h 
>> b/tools/objtool/arch/arm64/include/arch_special.h
>> index a82a9b3e51df..b96bcee308cf 100644
>> --- a/tools/objtool/arch/arm64/include/arch_special.h
>> +++ b/tools/objtool/arch/arm64/include/arch_special.h
>> @@ -3,6 +3,8 @@
>>   #ifndef _ARM64_ARCH_SPECIAL_H
>>   #define _ARM64_ARCH_SPECIAL_H
>> +#include <linux/types.h>
>> +
>>   #define EX_ENTRY_SIZE        8
>>   #define EX_ORIG_OFFSET        0
>>   #define EX_NEW_OFFSET        4
>> diff --git a/tools/objtool/check.c b/tools/objtool/check.c
>> index e0c6bda261c8..80ea5bbd36ab 100644
>> --- a/tools/objtool/check.c
>> +++ b/tools/objtool/check.c
>> @@ -33,8 +33,8 @@ struct instruction *find_insn(struct objtool_file 
>> *file,
>>       return NULL;
>>   }
>> -static struct instruction *next_insn_same_sec(struct objtool_file *file,
>> -                          struct instruction *insn)
>> +struct instruction *next_insn_same_sec(struct objtool_file *file,
>> +                       struct instruction *insn)
>>   {
>>       struct instruction *next = list_next_entry(insn, list);
>> diff --git a/tools/objtool/check.h b/tools/objtool/check.h
>> index 91adec42782c..15165d04d9cb 100644
>> --- a/tools/objtool/check.h
>> +++ b/tools/objtool/check.h
>> @@ -66,6 +66,8 @@ int check(const char *objname, bool orc);
>>   struct instruction *find_insn(struct objtool_file *file,
>>                     struct section *sec, unsigned long offset);
>> +struct instruction *next_insn_same_sec(struct objtool_file *file,
>> +                       struct instruction *insn);
>>   #define for_each_insn(file, insn)                    \
>>       list_for_each_entry(insn, &file->insn_list, list)
>>
> 
> Cheers,
> 

-- 
Julien Thierry


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

* Re: [RFC v5 11/57] objtool: Abstract alternative special case handling
  2020-01-09 16:02 ` [RFC v5 11/57] objtool: Abstract alternative special case handling Julien Thierry
@ 2020-01-20 14:54   ` Peter Zijlstra
  2020-01-23 11:45     ` Julien Thierry
  0 siblings, 1 reply; 91+ messages in thread
From: Peter Zijlstra @ 2020-01-20 14:54 UTC (permalink / raw)
  To: Julien Thierry
  Cc: linux-kernel, linux-arm-kernel, jpoimboe, raphael.gault,
	catalin.marinas, will

On Thu, Jan 09, 2020 at 04:02:14PM +0000, Julien Thierry wrote:
> diff --git a/tools/objtool/arch/x86/arch_special.c b/tools/objtool/arch/x86/arch_special.c
> new file mode 100644
> index 000000000000..6dba31f419d0
> --- /dev/null
> +++ b/tools/objtool/arch/x86/arch_special.c
> @@ -0,0 +1,34 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +#include "../../special.h"
> +#include "../../builtin.h"
> +
> +void arch_handle_alternative(unsigned short feature, struct special_alt *alt)
> +{
> +	/*
> +	 * If UACCESS validation is enabled; force that alternative;
> +	 * otherwise force it the other way.
> +	 *
> +	 * What we want to avoid is having both the original and the
> +	 * alternative code flow at the same time, in that case we can
> +	 * find paths that see the STAC but take the NOP instead of
> +	 * CLAC and the other way around.
> +	 */

That comment ^,

> +	switch (feature) {
> +	case X86_FEATURE_SMAP:

goes here >

> +		if (uaccess)
> +			alt->skip_orig = true;
> +		else
> +			alt->skip_alt = true;
> +		break;

> +	case X86_FEATURE_POPCNT:
> +		/*
> +		 * It has been requested that we don't validate the !POPCNT
> +		 * feature path which is a "very very small percentage of
> +		 * machines".
> +		 */
> +		alt->skip_orig = true;
> +		break;
> +	default:
> +		break;
> +	}
> +}

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

* Re: [RFC v5 12/57] objtool: check: Allow jumps from an alternative group to itself
  2020-01-09 16:02 ` [RFC v5 12/57] objtool: check: Allow jumps from an alternative group to itself Julien Thierry
@ 2020-01-20 14:56   ` Peter Zijlstra
  2020-01-21 10:30     ` Will Deacon
  2020-01-21 17:33   ` Josh Poimboeuf
  1 sibling, 1 reply; 91+ messages in thread
From: Peter Zijlstra @ 2020-01-20 14:56 UTC (permalink / raw)
  To: Julien Thierry
  Cc: linux-kernel, linux-arm-kernel, jpoimboe, raphael.gault,
	catalin.marinas, will

On Thu, Jan 09, 2020 at 04:02:15PM +0000, Julien Thierry wrote:
> Alternatives can contain instructions that jump to another instruction
> in the same alternative group. This is actually a common pattern on
> arm64.

LL/SC I bet...


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

* Re: [RFC v5 00/57] objtool: Add support for arm64
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (57 preceding siblings ...)
  2020-01-12  8:42 ` [RFC v5 00/57] objtool: Add support for arm64 Nathan Chancellor
@ 2020-01-20 15:07 ` Peter Zijlstra
  2020-01-21 17:50   ` Josh Poimboeuf
  2020-01-21 10:30 ` Will Deacon
  59 siblings, 1 reply; 91+ messages in thread
From: Peter Zijlstra @ 2020-01-20 15:07 UTC (permalink / raw)
  To: Julien Thierry
  Cc: linux-kernel, linux-arm-kernel, jpoimboe, raphael.gault,
	catalin.marinas, will

On Thu, Jan 09, 2020 at 04:02:03PM +0000, Julien Thierry wrote:
> In the mean time, any feedback on the current state is appreciated.
> 
> * Patches 1 to 18 adapts the current objtool code to make it easier to
>   support new architectures.

In the interrest of moving things along; I've looked through these
and 1-14,16 look good to me, 17,18 hurt my brain.

Josh, what say you?

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

* Re: [RFC v5 47/57] arm64: assembler: Add macro to annotate asm function having non standard stack-frame.
  2020-01-09 16:02 ` [RFC v5 47/57] arm64: assembler: Add macro to annotate asm function having non standard stack-frame Julien Thierry
@ 2020-01-21 10:30   ` Will Deacon
  2020-01-23 13:45     ` Julien Thierry
  0 siblings, 1 reply; 91+ messages in thread
From: Will Deacon @ 2020-01-21 10:30 UTC (permalink / raw)
  To: Julien Thierry
  Cc: linux-kernel, linux-arm-kernel, jpoimboe, peterz, raphael.gault,
	catalin.marinas

On Thu, Jan 09, 2020 at 04:02:50PM +0000, Julien Thierry wrote:
> From: Raphael Gault <raphael.gault@arm.com>
> 
> 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 <raphael.gault@arm.com>
> Signed-off-by: Julien Thierry <jthierry@redhat.com>
> ---
>  include/linux/frame.h | 19 ++++++++++++++++++-
>  1 file changed, 18 insertions(+), 1 deletion(-)
> 
> diff --git a/include/linux/frame.h b/include/linux/frame.h
> index 02d3ca2d9598..1e35e58ab259 100644
> --- a/include/linux/frame.h
> +++ b/include/linux/frame.h
> @@ -11,14 +11,31 @@
>   *
>   * For more information, see tools/objtool/Documentation/stack-validation.txt.
>   */
> +#ifndef __ASSEMBLY__
>  #define STACK_FRAME_NON_STANDARD(func) \
>  	static void __used __section(.discard.func_stack_frame_non_standard) \
>  		*__func_stack_frame_non_standard_##func = func
> +#else
> +	/*
> +	 * 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
> +	.pushsection ".discard.func_stack_frame_non_standard"
> +	.quad	\func
> +	.popsection
> +	.endm
> 
> +#endif /* __ASSEMBLY__ */
>  #else /* !CONFIG_STACK_VALIDATION */
> 
> +#ifndef __ASSEMBLY__
>  #define STACK_FRAME_NON_STANDARD(func)
> -
> +#else
> +	.macro	asm_stack_frame_non_standard	func
> +	.endm
> +#endif /* __ASSEMBLY__ */

Hmm. Given that we're currently going through the exercise of converting
a bunch of ENTRY/ENDPROC macros to use the new SYM_{CODE,FUNC}_{START,END}
macros, I would much prefer for this to be a new flavour of those.

In fact, can you just use SYM_CODE_* for this?

Will

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

* Re: [RFC v5 12/57] objtool: check: Allow jumps from an alternative group to itself
  2020-01-20 14:56   ` Peter Zijlstra
@ 2020-01-21 10:30     ` Will Deacon
  0 siblings, 0 replies; 91+ messages in thread
From: Will Deacon @ 2020-01-21 10:30 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Julien Thierry, linux-kernel, linux-arm-kernel, jpoimboe,
	raphael.gault, catalin.marinas

On Mon, Jan 20, 2020 at 03:56:56PM +0100, Peter Zijlstra wrote:
> On Thu, Jan 09, 2020 at 04:02:15PM +0000, Julien Thierry wrote:
> > Alternatives can contain instructions that jump to another instruction
> > in the same alternative group. This is actually a common pattern on
> > arm64.
> 
> LL/SC I bet...

I think there are some nasty errata workarounds that need it too.

WIll

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

* Re: [RFC v5 00/57] objtool: Add support for arm64
  2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
                   ` (58 preceding siblings ...)
  2020-01-20 15:07 ` Peter Zijlstra
@ 2020-01-21 10:30 ` Will Deacon
  2020-01-23 13:52   ` Julien Thierry
  59 siblings, 1 reply; 91+ messages in thread
From: Will Deacon @ 2020-01-21 10:30 UTC (permalink / raw)
  To: Julien Thierry
  Cc: linux-kernel, linux-arm-kernel, jpoimboe, peterz, raphael.gault,
	catalin.marinas

On Thu, Jan 09, 2020 at 04:02:03PM +0000, Julien Thierry wrote:
> This patch series is the continuation of Raphael's work [1]. All the
> patches can be retrieved from:
> git clone -b arm64-objtool-v5 https://github.com/julien-thierry/linux.git

[...]

>   objtool: arm64: Decode unknown instructions
>   objtool: arm64: Decode simple data processing instructions
>   objtool: arm64: Decode add/sub immediate instructions
>   objtool: arm64: Decode logical data processing instructions
>   objtool: arm64: Decode system instructions not affecting the flow
>   objtool: arm64: Decode calls to higher EL
>   objtool: arm64: Decode brk instruction
>   objtool: arm64: Decode instruction triggering context switch
>   objtool: arm64: Decode branch instructions with PC relative immediates
>   objtool: arm64: Decode branch to register instruction
>   objtool: arm64: Decode basic load/stores
>   objtool: arm64: Decode load/store with register offset
>   objtool: arm64: Decode load/store register pair instructions
>   objtool: arm64: Decode FP/SIMD load/store instructions
>   objtool: arm64: Decode load/store exclusive
>   objtool: arm64: Decode atomic load/store
>   objtool: arm64: Decode pointer auth load instructions
>   objtool: arm64: Decode load acquire/store release
>   objtool: arm64: Decode load/store with memory tag
>   objtool: arm64: Decode load literal
>   objtool: arm64: Decode register data processing instructions
>   objtool: arm64: Decode FP/SIMD data processing instructions
>   objtool: arm64: Decode SVE instructions

That's a lot of decoding logic which we already have in
arch/arm64/{kernel/insn.c,include/asm/insn.h}. I'd prefer to see this stuff
reused or generated from a single source, since it's really easy to get it
wrong, has a tendency to bitrot and is nasty to debug.

Will

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

* Re: [RFC v5 56/57] arm64: entry: Avoid empty alternatives entries
  2020-01-09 16:51   ` Mark Rutland
@ 2020-01-21 10:30     ` Will Deacon
  0 siblings, 0 replies; 91+ messages in thread
From: Will Deacon @ 2020-01-21 10:30 UTC (permalink / raw)
  To: Mark Rutland
  Cc: Julien Thierry, linux-kernel, linux-arm-kernel, jpoimboe, peterz,
	raphael.gault, catalin.marinas

On Thu, Jan 09, 2020 at 04:51:46PM +0000, Mark Rutland wrote:
> On Thu, Jan 09, 2020 at 04:02:59PM +0000, Julien Thierry wrote:
> > kernel_ventry will create alternative entries to potentially replace
> > 0 instructions with 0 instructions for EL1 vectors. While this does not
> > cause an issue, it pointlessly takes up some bytes in the alternatives
> > section.
> > 
> > Do not generate such entries.
> > 
> > Signed-off-by: Julien Thierry <jthierry@redhat.com>
> 
> This looks like a sensible cleanup on its own. FWIW:
> 
> Acked-by: Mark Rutland <mark.rutland@arm.com>

I'll pick this one up, thanks.

Will

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

* Re: [RFC v5 00/57] objtool: Add support for arm64
  2020-01-13  7:57   ` Julien Thierry
@ 2020-01-21 10:31     ` Will Deacon
  2020-01-21 17:08       ` Nick Desaulniers
  0 siblings, 1 reply; 91+ messages in thread
From: Will Deacon @ 2020-01-21 10:31 UTC (permalink / raw)
  To: Julien Thierry
  Cc: Nathan Chancellor, linux-kernel, linux-arm-kernel, jpoimboe,
	peterz, raphael.gault, catalin.marinas, clang-built-linux

On Mon, Jan 13, 2020 at 07:57:48AM +0000, Julien Thierry wrote:
> On 1/12/20 8:42 AM, Nathan Chancellor wrote:
> > The 0day bot reported a couple of issues with clang with this series;
> > the full report is available here (clang reports are only sent to our
> > mailing lists for manual triage for the time being):
> > 
> > https://groups.google.com/d/msg/clang-built-linux/MJbl_xPxawg/mWjgDgZgBwAJ
> > 
> 
> Thanks, I'll have a look at those.
> 
> > The first obvious issue is that this series appears to depend on a GCC
> > plugin? I'll be quite honest, objtool and everything it does is rather
> > over my head but I see this warning during configuration (allyesconfig):
> > 
> > WARNING: unmet direct dependencies detected for GCC_PLUGIN_SWITCH_TABLES
> >    Depends on [n]: GCC_PLUGINS [=n] && ARM64 [=y]
> >      Selected by [y]:
> >        - ARM64 [=y] && STACK_VALIDATION [=y]
> > 
> > Followed by the actual error:
> > 
> > error: unable to load plugin
> > './scripts/gcc-plugins/arm64_switch_table_detection_plugin.so':
> > './scripts/gcc-plugins/arm64_switch_table_detection_plugin.so: cannot
> > open shared object file: No such file or directory'
> > 
> > If this plugin is absolutely necessary and can't be implemented in
> > another way so that clang can be used, seems like STACK_VALIDATION
> > should only be selected on ARM64 when CONFIG_CC_IS_GCC is not zero.
> > 
> 
> So currently the plugin is necessary for proper validation. One option can
> be to just let objtool output false positives on files containing jump
> tables when the plugin cannot be used. But overall I guess it makes more
> sense to disable stack validation for non-gcc builds, for now.

Alternatively, could we add '-fno-jump-tables' to the KBUILD_CFLAGS if
STACK_VALIDATION is selected but we're not using GCC? Is that sufficient
to prevent generation of these things?

Will

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

* Re: [RFC v5 04/57] objtool: check: Ignore empty alternative groups
  2020-01-09 16:02 ` [RFC v5 04/57] objtool: check: Ignore empty alternative groups Julien Thierry
@ 2020-01-21 16:30   ` Josh Poimboeuf
  2020-01-23 11:45     ` Julien Thierry
  0 siblings, 1 reply; 91+ messages in thread
From: Josh Poimboeuf @ 2020-01-21 16:30 UTC (permalink / raw)
  To: Julien Thierry
  Cc: linux-kernel, linux-arm-kernel, peterz, raphael.gault,
	catalin.marinas, will

On Thu, Jan 09, 2020 at 04:02:07PM +0000, Julien Thierry wrote:
> Atlernative section can contain entries for alternatives with no
> instructions. Objtool will currently crash when handling such an entry.
> 
> Just skip that entry, but still give a warning to discourage useless
> entries.
> 
> Signed-off-by: Julien Thierry <jthierry@redhat.com>
> ---
>  tools/objtool/check.c | 7 +++++++
>  1 file changed, 7 insertions(+)
> 
> diff --git a/tools/objtool/check.c b/tools/objtool/check.c
> index 5968e6f08891..27e5380e0e0b 100644
> --- a/tools/objtool/check.c
> +++ b/tools/objtool/check.c
> @@ -866,6 +866,13 @@ static int add_special_section_alts(struct objtool_file *file)
>  		}
>  
>  		if (special_alt->group) {
> +			if (!special_alt->orig_len) {
> +				WARN("empty alternative entry at %s+0x%lx",
> +				     orig_insn->sec->name,
> +				     orig_insn->offset);
> +				continue;
> +			}
> +

I think WARN_FUNC() can be used here instead.

-- 
Josh


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

* Re: [RFC v5 08/57] objtool: Make ORC support optional
  2020-01-09 16:02 ` [RFC v5 08/57] objtool: Make ORC support optional Julien Thierry
@ 2020-01-21 16:37   ` Josh Poimboeuf
  2020-01-23 11:45     ` Julien Thierry
  0 siblings, 1 reply; 91+ messages in thread
From: Josh Poimboeuf @ 2020-01-21 16:37 UTC (permalink / raw)
  To: Julien Thierry
  Cc: linux-kernel, linux-arm-kernel, peterz, raphael.gault,
	catalin.marinas, will

On Thu, Jan 09, 2020 at 04:02:11PM +0000, Julien Thierry wrote:
> diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile
> index d2a19b0bc05a..24d653e0b6ec 100644
> --- a/tools/objtool/Makefile
> +++ b/tools/objtool/Makefile
> @@ -6,6 +6,10 @@ ifeq ($(ARCH),x86_64)
>  ARCH := x86
>  endif
>  
> +ifeq ($(ARCH),x86)
> +OBJTOOL_ORC := y
> +endif

I think this should check SRCARCH instead, a la:

  https://lkml.kernel.org/r/d5d11370ae116df6c653493acd300ec3d7f5e925.1579543924.git.jpoimboe@redhat.com

-- 
Josh


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

* Re: [RFC v5 00/57] objtool: Add support for arm64
  2020-01-21 10:31     ` Will Deacon
@ 2020-01-21 17:08       ` Nick Desaulniers
  2020-01-21 18:06         ` Will Deacon
  0 siblings, 1 reply; 91+ messages in thread
From: Nick Desaulniers @ 2020-01-21 17:08 UTC (permalink / raw)
  To: Will Deacon
  Cc: Julien Thierry, Nathan Chancellor, LKML, Linux ARM,
	Josh Poimboeuf, Peter Zijlstra, raphael.gault, Catalin Marinas,
	clang-built-linux

On Tue, Jan 21, 2020 at 2:31 AM Will Deacon <will@kernel.org> wrote:
>
> On Mon, Jan 13, 2020 at 07:57:48AM +0000, Julien Thierry wrote:
> > On 1/12/20 8:42 AM, Nathan Chancellor wrote:
> > > The 0day bot reported a couple of issues with clang with this series;
> > > the full report is available here (clang reports are only sent to our
> > > mailing lists for manual triage for the time being):
> > >
> > > https://groups.google.com/d/msg/clang-built-linux/MJbl_xPxawg/mWjgDgZgBwAJ
> > >
> >
> > Thanks, I'll have a look at those.
> >
> > > The first obvious issue is that this series appears to depend on a GCC
> > > plugin? I'll be quite honest, objtool and everything it does is rather
> > > over my head but I see this warning during configuration (allyesconfig):
> > >
> > > WARNING: unmet direct dependencies detected for GCC_PLUGIN_SWITCH_TABLES
> > >    Depends on [n]: GCC_PLUGINS [=n] && ARM64 [=y]
> > >      Selected by [y]:
> > >        - ARM64 [=y] && STACK_VALIDATION [=y]
> > >
> > > Followed by the actual error:
> > >
> > > error: unable to load plugin
> > > './scripts/gcc-plugins/arm64_switch_table_detection_plugin.so':
> > > './scripts/gcc-plugins/arm64_switch_table_detection_plugin.so: cannot
> > > open shared object file: No such file or directory'
> > >
> > > If this plugin is absolutely necessary and can't be implemented in
> > > another way so that clang can be used, seems like STACK_VALIDATION
> > > should only be selected on ARM64 when CONFIG_CC_IS_GCC is not zero.
> > >
> >
> > So currently the plugin is necessary for proper validation. One option can
> > be to just let objtool output false positives on files containing jump
> > tables when the plugin cannot be used. But overall I guess it makes more
> > sense to disable stack validation for non-gcc builds, for now.
>
> Alternatively, could we add '-fno-jump-tables' to the KBUILD_CFLAGS if
> STACK_VALIDATION is selected but we're not using GCC? Is that sufficient
> to prevent generation of these things?

Surely we wouldn't want to replace jump tables with long chains of
comparisons just because objtool couldn't validate jump tables without
a GCC plugin for aarch64 for some reason, right?  objtool validation
is valuable, but tying runtime performance to a GCC plugin used for
validation seems bad.
-- 
Thanks,
~Nick Desaulniers

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

* Re: [RFC v5 12/57] objtool: check: Allow jumps from an alternative group to itself
  2020-01-09 16:02 ` [RFC v5 12/57] objtool: check: Allow jumps from an alternative group to itself Julien Thierry
  2020-01-20 14:56   ` Peter Zijlstra
@ 2020-01-21 17:33   ` Josh Poimboeuf
  2020-01-23 13:42     ` Julien Thierry
  1 sibling, 1 reply; 91+ messages in thread
From: Josh Poimboeuf @ 2020-01-21 17:33 UTC (permalink / raw)
  To: Julien Thierry
  Cc: linux-kernel, linux-arm-kernel, peterz, raphael.gault,
	catalin.marinas, will

On Thu, Jan 09, 2020 at 04:02:15PM +0000, Julien Thierry wrote:
> Alternatives can contain instructions that jump to another instruction
> in the same alternative group. This is actually a common pattern on
> arm64.
> 
> Keep track of instructions jumping within their own alternative group
> and carry on validating such branches.
> 
> Signed-off-by: Julien Thierry <jthierry@redhat.com>
> ---
>  tools/objtool/check.c | 48 ++++++++++++++++++++++++++++++++++---------
>  tools/objtool/check.h |  1 +
>  2 files changed, 39 insertions(+), 10 deletions(-)
> 
> diff --git a/tools/objtool/check.c b/tools/objtool/check.c
> index 8f2ff030936d..c7b3f1e2a628 100644
> --- a/tools/objtool/check.c
> +++ b/tools/objtool/check.c
> @@ -722,6 +722,14 @@ static int handle_group_alt(struct objtool_file *file,
>  	sec_for_each_insn_from(file, insn) {
>  		if (insn->offset >= special_alt->orig_off + special_alt->orig_len)
>  			break;
> +		/* Is insn a jump to an instruction within the alt_group */
> +		if (insn->jump_dest && insn->sec == insn->jump_dest->sec &&
> +		    (insn->type == INSN_JUMP_CONDITIONAL ||
> +		     insn->type == INSN_JUMP_UNCONDITIONAL)) {
> +			dest_off = insn->jump_dest->offset;
> +			insn->intra_group_jump = special_alt->orig_off <= dest_off &&
> +				dest_off < special_alt->orig_off + special_alt->orig_len;
> +		}

This patch adds some complexity, just so we can keep the

  "don't know how to handle branch to middle of alternative instruction group"

warning for the case where code from outside an alternative insn group
is branching to inside the group.  But I've never actually seen that
case in practice, and I get the feeling that warning isn't very useful
or realistic.

How about we just remove the warning?

-- 
Josh


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

* Re: [RFC v5 00/57] objtool: Add support for arm64
  2020-01-20 15:07 ` Peter Zijlstra
@ 2020-01-21 17:50   ` Josh Poimboeuf
  2020-01-23 13:56     ` Julien Thierry
  0 siblings, 1 reply; 91+ messages in thread
From: Josh Poimboeuf @ 2020-01-21 17:50 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Julien Thierry, linux-kernel, linux-arm-kernel, raphael.gault,
	catalin.marinas, will

On Mon, Jan 20, 2020 at 04:07:11PM +0100, Peter Zijlstra wrote:
> On Thu, Jan 09, 2020 at 04:02:03PM +0000, Julien Thierry wrote:
> > In the mean time, any feedback on the current state is appreciated.
> > 
> > * Patches 1 to 18 adapts the current objtool code to make it easier to
> >   support new architectures.
> 
> In the interrest of moving things along; I've looked through these
> and 1-14,16 look good to me, 17,18 hurt my brain.
> 
> Josh, what say you?

Agreed.

Julien, thanks a lot for splitting these up nicely.  If you post 1-14
(updated based on the recent comments), we can look at merging those
sooner.

15-18 also hurt my brain -- probably a symptom of the existing fragile
mess -- so I'll need to spend more time staring at them.

-- 
Josh


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

* Re: [RFC v5 00/57] objtool: Add support for arm64
  2020-01-21 17:08       ` Nick Desaulniers
@ 2020-01-21 18:06         ` Will Deacon
  2020-01-21 18:30           ` Josh Poimboeuf
  0 siblings, 1 reply; 91+ messages in thread
From: Will Deacon @ 2020-01-21 18:06 UTC (permalink / raw)
  To: Nick Desaulniers
  Cc: Julien Thierry, Nathan Chancellor, LKML, Linux ARM,
	Josh Poimboeuf, Peter Zijlstra, raphael.gault, Catalin Marinas,
	clang-built-linux

On Tue, Jan 21, 2020 at 09:08:29AM -0800, Nick Desaulniers wrote:
> On Tue, Jan 21, 2020 at 2:31 AM Will Deacon <will@kernel.org> wrote:
> >
> > On Mon, Jan 13, 2020 at 07:57:48AM +0000, Julien Thierry wrote:
> > > On 1/12/20 8:42 AM, Nathan Chancellor wrote:
> > > > The 0day bot reported a couple of issues with clang with this series;
> > > > the full report is available here (clang reports are only sent to our
> > > > mailing lists for manual triage for the time being):
> > > >
> > > > https://groups.google.com/d/msg/clang-built-linux/MJbl_xPxawg/mWjgDgZgBwAJ
> > > >
> > >
> > > Thanks, I'll have a look at those.
> > >
> > > > The first obvious issue is that this series appears to depend on a GCC
> > > > plugin? I'll be quite honest, objtool and everything it does is rather
> > > > over my head but I see this warning during configuration (allyesconfig):
> > > >
> > > > WARNING: unmet direct dependencies detected for GCC_PLUGIN_SWITCH_TABLES
> > > >    Depends on [n]: GCC_PLUGINS [=n] && ARM64 [=y]
> > > >      Selected by [y]:
> > > >        - ARM64 [=y] && STACK_VALIDATION [=y]
> > > >
> > > > Followed by the actual error:
> > > >
> > > > error: unable to load plugin
> > > > './scripts/gcc-plugins/arm64_switch_table_detection_plugin.so':
> > > > './scripts/gcc-plugins/arm64_switch_table_detection_plugin.so: cannot
> > > > open shared object file: No such file or directory'
> > > >
> > > > If this plugin is absolutely necessary and can't be implemented in
> > > > another way so that clang can be used, seems like STACK_VALIDATION
> > > > should only be selected on ARM64 when CONFIG_CC_IS_GCC is not zero.
> > > >
> > >
> > > So currently the plugin is necessary for proper validation. One option can
> > > be to just let objtool output false positives on files containing jump
> > > tables when the plugin cannot be used. But overall I guess it makes more
> > > sense to disable stack validation for non-gcc builds, for now.
> >
> > Alternatively, could we add '-fno-jump-tables' to the KBUILD_CFLAGS if
> > STACK_VALIDATION is selected but we're not using GCC? Is that sufficient
> > to prevent generation of these things?
> 
> Surely we wouldn't want to replace jump tables with long chains of
> comparisons just because objtool couldn't validate jump tables without
> a GCC plugin for aarch64 for some reason, right?  objtool validation
> is valuable, but tying runtime performance to a GCC plugin used for
> validation seems bad.

I'm only suggesting it if STACK_VALIDATION is selected. It's off by default,
and lives in Kconfig.debug. I'd prefer that to "cross your fingers are do
nothing differently", which is what the other option seems to be.

Will

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

* Re: [RFC v5 00/57] objtool: Add support for arm64
  2020-01-21 18:06         ` Will Deacon
@ 2020-01-21 18:30           ` Josh Poimboeuf
  2020-01-22 14:47             ` Will Deacon
  0 siblings, 1 reply; 91+ messages in thread
From: Josh Poimboeuf @ 2020-01-21 18:30 UTC (permalink / raw)
  To: Will Deacon
  Cc: Nick Desaulniers, Julien Thierry, Nathan Chancellor, LKML,
	Linux ARM, Peter Zijlstra, raphael.gault, Catalin Marinas,
	clang-built-linux

On Tue, Jan 21, 2020 at 06:06:34PM +0000, Will Deacon wrote:
> On Tue, Jan 21, 2020 at 09:08:29AM -0800, Nick Desaulniers wrote:
> > On Tue, Jan 21, 2020 at 2:31 AM Will Deacon <will@kernel.org> wrote:
> > >
> > > On Mon, Jan 13, 2020 at 07:57:48AM +0000, Julien Thierry wrote:
> > > > On 1/12/20 8:42 AM, Nathan Chancellor wrote:
> > > > > The 0day bot reported a couple of issues with clang with this series;
> > > > > the full report is available here (clang reports are only sent to our
> > > > > mailing lists for manual triage for the time being):
> > > > >
> > > > > https://groups.google.com/d/msg/clang-built-linux/MJbl_xPxawg/mWjgDgZgBwAJ
> > > > >
> > > >
> > > > Thanks, I'll have a look at those.
> > > >
> > > > > The first obvious issue is that this series appears to depend on a GCC
> > > > > plugin? I'll be quite honest, objtool and everything it does is rather
> > > > > over my head but I see this warning during configuration (allyesconfig):
> > > > >
> > > > > WARNING: unmet direct dependencies detected for GCC_PLUGIN_SWITCH_TABLES
> > > > >    Depends on [n]: GCC_PLUGINS [=n] && ARM64 [=y]
> > > > >      Selected by [y]:
> > > > >        - ARM64 [=y] && STACK_VALIDATION [=y]
> > > > >
> > > > > Followed by the actual error:
> > > > >
> > > > > error: unable to load plugin
> > > > > './scripts/gcc-plugins/arm64_switch_table_detection_plugin.so':
> > > > > './scripts/gcc-plugins/arm64_switch_table_detection_plugin.so: cannot
> > > > > open shared object file: No such file or directory'
> > > > >
> > > > > If this plugin is absolutely necessary and can't be implemented in
> > > > > another way so that clang can be used, seems like STACK_VALIDATION
> > > > > should only be selected on ARM64 when CONFIG_CC_IS_GCC is not zero.
> > > > >
> > > >
> > > > So currently the plugin is necessary for proper validation. One option can
> > > > be to just let objtool output false positives on files containing jump
> > > > tables when the plugin cannot be used. But overall I guess it makes more
> > > > sense to disable stack validation for non-gcc builds, for now.
> > >
> > > Alternatively, could we add '-fno-jump-tables' to the KBUILD_CFLAGS if
> > > STACK_VALIDATION is selected but we're not using GCC? Is that sufficient
> > > to prevent generation of these things?
> > 
> > Surely we wouldn't want to replace jump tables with long chains of
> > comparisons just because objtool couldn't validate jump tables without
> > a GCC plugin for aarch64 for some reason, right?  objtool validation
> > is valuable, but tying runtime performance to a GCC plugin used for
> > validation seems bad.
> 
> I'm only suggesting it if STACK_VALIDATION is selected. It's off by default,
> and lives in Kconfig.debug. I'd prefer that to "cross your fingers are do
> nothing differently", which is what the other option seems to be.

I don't know what the right answer is here, but keep in mind that
objtool is on by default for x86, so don't be surprised if that
eventually happens to arch64 too.

Short term it might be ok to disable jump tables with objtool enabled,
or to disable objtool when clang is in use, but long term we'll need to
figure out a better solution.

-- 
Josh


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

* Re: [RFC v5 00/57] objtool: Add support for arm64
  2020-01-21 18:30           ` Josh Poimboeuf
@ 2020-01-22 14:47             ` Will Deacon
  0 siblings, 0 replies; 91+ messages in thread
From: Will Deacon @ 2020-01-22 14:47 UTC (permalink / raw)
  To: Josh Poimboeuf
  Cc: Nick Desaulniers, Julien Thierry, Nathan Chancellor, LKML,
	Linux ARM, Peter Zijlstra, raphael.gault, Catalin Marinas,
	clang-built-linux

On Tue, Jan 21, 2020 at 12:30:09PM -0600, Josh Poimboeuf wrote:
> On Tue, Jan 21, 2020 at 06:06:34PM +0000, Will Deacon wrote:
> > On Tue, Jan 21, 2020 at 09:08:29AM -0800, Nick Desaulniers wrote:
> > > On Tue, Jan 21, 2020 at 2:31 AM Will Deacon <will@kernel.org> wrote:
> > > >
> > > > On Mon, Jan 13, 2020 at 07:57:48AM +0000, Julien Thierry wrote:
> > > > > On 1/12/20 8:42 AM, Nathan Chancellor wrote:
> > > > > > The 0day bot reported a couple of issues with clang with this series;
> > > > > > the full report is available here (clang reports are only sent to our
> > > > > > mailing lists for manual triage for the time being):
> > > > > >
> > > > > > https://groups.google.com/d/msg/clang-built-linux/MJbl_xPxawg/mWjgDgZgBwAJ
> > > > > >
> > > > >
> > > > > Thanks, I'll have a look at those.
> > > > >
> > > > > > The first obvious issue is that this series appears to depend on a GCC
> > > > > > plugin? I'll be quite honest, objtool and everything it does is rather
> > > > > > over my head but I see this warning during configuration (allyesconfig):
> > > > > >
> > > > > > WARNING: unmet direct dependencies detected for GCC_PLUGIN_SWITCH_TABLES
> > > > > >    Depends on [n]: GCC_PLUGINS [=n] && ARM64 [=y]
> > > > > >      Selected by [y]:
> > > > > >        - ARM64 [=y] && STACK_VALIDATION [=y]
> > > > > >
> > > > > > Followed by the actual error:
> > > > > >
> > > > > > error: unable to load plugin
> > > > > > './scripts/gcc-plugins/arm64_switch_table_detection_plugin.so':
> > > > > > './scripts/gcc-plugins/arm64_switch_table_detection_plugin.so: cannot
> > > > > > open shared object file: No such file or directory'
> > > > > >
> > > > > > If this plugin is absolutely necessary and can't be implemented in
> > > > > > another way so that clang can be used, seems like STACK_VALIDATION
> > > > > > should only be selected on ARM64 when CONFIG_CC_IS_GCC is not zero.
> > > > > >
> > > > >
> > > > > So currently the plugin is necessary for proper validation. One option can
> > > > > be to just let objtool output false positives on files containing jump
> > > > > tables when the plugin cannot be used. But overall I guess it makes more
> > > > > sense to disable stack validation for non-gcc builds, for now.
> > > >
> > > > Alternatively, could we add '-fno-jump-tables' to the KBUILD_CFLAGS if
> > > > STACK_VALIDATION is selected but we're not using GCC? Is that sufficient
> > > > to prevent generation of these things?
> > > 
> > > Surely we wouldn't want to replace jump tables with long chains of
> > > comparisons just because objtool couldn't validate jump tables without
> > > a GCC plugin for aarch64 for some reason, right?  objtool validation
> > > is valuable, but tying runtime performance to a GCC plugin used for
> > > validation seems bad.
> > 
> > I'm only suggesting it if STACK_VALIDATION is selected. It's off by default,
> > and lives in Kconfig.debug. I'd prefer that to "cross your fingers are do
> > nothing differently", which is what the other option seems to be.
> 
> I don't know what the right answer is here, but keep in mind that
> objtool is on by default for x86, so don't be surprised if that
> eventually happens to arch64 too.
> 
> Short term it might be ok to disable jump tables with objtool enabled,
> or to disable objtool when clang is in use, but long term we'll need to
> figure out a better solution.

Oh, absolutely. No objection from me fixing this properly in the long
term. I just don't want to be in a situation where STACK_VALIDATION is
silently ignored in the meantime.

Will

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

* Re: [RFC v5 04/57] objtool: check: Ignore empty alternative groups
  2020-01-21 16:30   ` Josh Poimboeuf
@ 2020-01-23 11:45     ` Julien Thierry
  0 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-23 11:45 UTC (permalink / raw)
  To: Josh Poimboeuf
  Cc: linux-kernel, linux-arm-kernel, peterz, raphael.gault,
	catalin.marinas, will



On 1/21/20 4:30 PM, Josh Poimboeuf wrote:
> On Thu, Jan 09, 2020 at 04:02:07PM +0000, Julien Thierry wrote:
>> Atlernative section can contain entries for alternatives with no
>> instructions. Objtool will currently crash when handling such an entry.
>>
>> Just skip that entry, but still give a warning to discourage useless
>> entries.
>>
>> Signed-off-by: Julien Thierry <jthierry@redhat.com>
>> ---
>>   tools/objtool/check.c | 7 +++++++
>>   1 file changed, 7 insertions(+)
>>
>> diff --git a/tools/objtool/check.c b/tools/objtool/check.c
>> index 5968e6f08891..27e5380e0e0b 100644
>> --- a/tools/objtool/check.c
>> +++ b/tools/objtool/check.c
>> @@ -866,6 +866,13 @@ static int add_special_section_alts(struct objtool_file *file)
>>   		}
>>   
>>   		if (special_alt->group) {
>> +			if (!special_alt->orig_len) {
>> +				WARN("empty alternative entry at %s+0x%lx",
>> +				     orig_insn->sec->name,
>> +				     orig_insn->offset);
>> +				continue;
>> +			}
>> +
> 
> I think WARN_FUNC() can be used here instead.
> 

I'll do that.

Thanks,

-- 
Julien Thierry


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

* Re: [RFC v5 08/57] objtool: Make ORC support optional
  2020-01-21 16:37   ` Josh Poimboeuf
@ 2020-01-23 11:45     ` Julien Thierry
  0 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-23 11:45 UTC (permalink / raw)
  To: Josh Poimboeuf
  Cc: linux-kernel, linux-arm-kernel, peterz, raphael.gault,
	catalin.marinas, will



On 1/21/20 4:37 PM, Josh Poimboeuf wrote:
> On Thu, Jan 09, 2020 at 04:02:11PM +0000, Julien Thierry wrote:
>> diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile
>> index d2a19b0bc05a..24d653e0b6ec 100644
>> --- a/tools/objtool/Makefile
>> +++ b/tools/objtool/Makefile
>> @@ -6,6 +6,10 @@ ifeq ($(ARCH),x86_64)
>>   ARCH := x86
>>   endif
>>   
>> +ifeq ($(ARCH),x86)
>> +OBJTOOL_ORC := y
>> +endif
> 
> I think this should check SRCARCH instead, a la:
> 
>    https://lkml.kernel.org/r/d5d11370ae116df6c653493acd300ec3d7f5e925.1579543924.git.jpoimboe@redhat.com
> 

Yes, thanks for pointing it out.

-- 
Julien Thierry


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

* Re: [RFC v5 11/57] objtool: Abstract alternative special case handling
  2020-01-20 14:54   ` Peter Zijlstra
@ 2020-01-23 11:45     ` Julien Thierry
  0 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-23 11:45 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: linux-kernel, linux-arm-kernel, jpoimboe, raphael.gault,
	catalin.marinas, will



On 1/20/20 2:54 PM, Peter Zijlstra wrote:
> On Thu, Jan 09, 2020 at 04:02:14PM +0000, Julien Thierry wrote:
>> diff --git a/tools/objtool/arch/x86/arch_special.c b/tools/objtool/arch/x86/arch_special.c
>> new file mode 100644
>> index 000000000000..6dba31f419d0
>> --- /dev/null
>> +++ b/tools/objtool/arch/x86/arch_special.c
>> @@ -0,0 +1,34 @@
>> +// SPDX-License-Identifier: GPL-2.0-or-later
>> +#include "../../special.h"
>> +#include "../../builtin.h"
>> +
>> +void arch_handle_alternative(unsigned short feature, struct special_alt *alt)
>> +{
>> +	/*
>> +	 * If UACCESS validation is enabled; force that alternative;
>> +	 * otherwise force it the other way.
>> +	 *
>> +	 * What we want to avoid is having both the original and the
>> +	 * alternative code flow at the same time, in that case we can
>> +	 * find paths that see the STAC but take the NOP instead of
>> +	 * CLAC and the other way around.
>> +	 */
> 
> That comment ^,
> 
>> +	switch (feature) {
>> +	case X86_FEATURE_SMAP:
> 
> goes here >
> 

Good catch, I'll fix that.

>> +		if (uaccess)
>> +			alt->skip_orig = true;
>> +		else
>> +			alt->skip_alt = true;
>> +		break;
> 
>> +	case X86_FEATURE_POPCNT:
>> +		/*
>> +		 * It has been requested that we don't validate the !POPCNT
>> +		 * feature path which is a "very very small percentage of
>> +		 * machines".
>> +		 */
>> +		alt->skip_orig = true;
>> +		break;
>> +	default:
>> +		break;
>> +	}
>> +}
> 

Thanks,

-- 
Julien Thierry


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

* Re: [RFC v5 12/57] objtool: check: Allow jumps from an alternative group to itself
  2020-01-21 17:33   ` Josh Poimboeuf
@ 2020-01-23 13:42     ` Julien Thierry
  0 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-23 13:42 UTC (permalink / raw)
  To: Josh Poimboeuf
  Cc: linux-kernel, linux-arm-kernel, peterz, raphael.gault,
	catalin.marinas, will



On 1/21/20 5:33 PM, Josh Poimboeuf wrote:
> On Thu, Jan 09, 2020 at 04:02:15PM +0000, Julien Thierry wrote:
>> Alternatives can contain instructions that jump to another instruction
>> in the same alternative group. This is actually a common pattern on
>> arm64.
>>
>> Keep track of instructions jumping within their own alternative group
>> and carry on validating such branches.
>>
>> Signed-off-by: Julien Thierry <jthierry@redhat.com>
>> ---
>>   tools/objtool/check.c | 48 ++++++++++++++++++++++++++++++++++---------
>>   tools/objtool/check.h |  1 +
>>   2 files changed, 39 insertions(+), 10 deletions(-)
>>
>> diff --git a/tools/objtool/check.c b/tools/objtool/check.c
>> index 8f2ff030936d..c7b3f1e2a628 100644
>> --- a/tools/objtool/check.c
>> +++ b/tools/objtool/check.c
>> @@ -722,6 +722,14 @@ static int handle_group_alt(struct objtool_file *file,
>>   	sec_for_each_insn_from(file, insn) {
>>   		if (insn->offset >= special_alt->orig_off + special_alt->orig_len)
>>   			break;
>> +		/* Is insn a jump to an instruction within the alt_group */
>> +		if (insn->jump_dest && insn->sec == insn->jump_dest->sec &&
>> +		    (insn->type == INSN_JUMP_CONDITIONAL ||
>> +		     insn->type == INSN_JUMP_UNCONDITIONAL)) {
>> +			dest_off = insn->jump_dest->offset;
>> +			insn->intra_group_jump = special_alt->orig_off <= dest_off &&
>> +				dest_off < special_alt->orig_off + special_alt->orig_len;
>> +		}
> 
> This patch adds some complexity, just so we can keep the
> 
>    "don't know how to handle branch to middle of alternative instruction group"
> 
> warning for the case where code from outside an alternative insn group
> is branching to inside the group.  But I've never actually seen that
> case in practice, and I get the feeling that warning isn't very useful
> or realistic.
> 
> How about we just remove the warning?
> 

I'm happy to remove it.

I was trying to look for a less intrusive place to only check for 
instructions jumping into alternatives. add_jump_destinations() could be 
an option, but it would require to duplicate some stuff done in 
add_special_section_alts(). So maybe just ignoring for now can be fine.

Thanks,

-- 
Julien Thierry


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

* Re: [RFC v5 47/57] arm64: assembler: Add macro to annotate asm function having non standard stack-frame.
  2020-01-21 10:30   ` Will Deacon
@ 2020-01-23 13:45     ` Julien Thierry
  2020-01-23 14:40       ` Will Deacon
  0 siblings, 1 reply; 91+ messages in thread
From: Julien Thierry @ 2020-01-23 13:45 UTC (permalink / raw)
  To: Will Deacon
  Cc: linux-kernel, linux-arm-kernel, jpoimboe, peterz, raphael.gault,
	catalin.marinas



On 1/21/20 10:30 AM, Will Deacon wrote:
> On Thu, Jan 09, 2020 at 04:02:50PM +0000, Julien Thierry wrote:
>> From: Raphael Gault <raphael.gault@arm.com>
>>
>> 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 <raphael.gault@arm.com>
>> Signed-off-by: Julien Thierry <jthierry@redhat.com>
>> ---
>>   include/linux/frame.h | 19 ++++++++++++++++++-
>>   1 file changed, 18 insertions(+), 1 deletion(-)
>>
>> diff --git a/include/linux/frame.h b/include/linux/frame.h
>> index 02d3ca2d9598..1e35e58ab259 100644
>> --- a/include/linux/frame.h
>> +++ b/include/linux/frame.h
>> @@ -11,14 +11,31 @@
>>    *
>>    * For more information, see tools/objtool/Documentation/stack-validation.txt.
>>    */
>> +#ifndef __ASSEMBLY__
>>   #define STACK_FRAME_NON_STANDARD(func) \
>>   	static void __used __section(.discard.func_stack_frame_non_standard) \
>>   		*__func_stack_frame_non_standard_##func = func
>> +#else
>> +	/*
>> +	 * 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
>> +	.pushsection ".discard.func_stack_frame_non_standard"
>> +	.quad	\func
>> +	.popsection
>> +	.endm
>>
>> +#endif /* __ASSEMBLY__ */
>>   #else /* !CONFIG_STACK_VALIDATION */
>>
>> +#ifndef __ASSEMBLY__
>>   #define STACK_FRAME_NON_STANDARD(func)
>> -
>> +#else
>> +	.macro	asm_stack_frame_non_standard	func
>> +	.endm
>> +#endif /* __ASSEMBLY__ */
> 
> Hmm. Given that we're currently going through the exercise of converting
> a bunch of ENTRY/ENDPROC macros to use the new SYM_{CODE,FUNC}_{START,END}
> macros, I would much prefer for this to be a new flavour of those.
> 
> In fact, can you just use SYM_CODE_* for this?
> 

You mean to not introduce the STACK_FRAME_NON_STANDARD() macro and just 
mark the asm callable symbols that don't set up a stackframe as SYM_CODE_* ?

-- 
Julien Thierry


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

* Re: [RFC v5 00/57] objtool: Add support for arm64
  2020-01-21 10:30 ` Will Deacon
@ 2020-01-23 13:52   ` Julien Thierry
  2020-01-23 14:35     ` Will Deacon
  0 siblings, 1 reply; 91+ messages in thread
From: Julien Thierry @ 2020-01-23 13:52 UTC (permalink / raw)
  To: Will Deacon
  Cc: linux-kernel, linux-arm-kernel, jpoimboe, peterz, raphael.gault,
	catalin.marinas



On 1/21/20 10:30 AM, Will Deacon wrote:
> On Thu, Jan 09, 2020 at 04:02:03PM +0000, Julien Thierry wrote:
>> This patch series is the continuation of Raphael's work [1]. All the
>> patches can be retrieved from:
>> git clone -b arm64-objtool-v5 https://github.com/julien-thierry/linux.git
> 
> [...]
> 
>>    objtool: arm64: Decode unknown instructions
>>    objtool: arm64: Decode simple data processing instructions
>>    objtool: arm64: Decode add/sub immediate instructions
>>    objtool: arm64: Decode logical data processing instructions
>>    objtool: arm64: Decode system instructions not affecting the flow
>>    objtool: arm64: Decode calls to higher EL
>>    objtool: arm64: Decode brk instruction
>>    objtool: arm64: Decode instruction triggering context switch
>>    objtool: arm64: Decode branch instructions with PC relative immediates
>>    objtool: arm64: Decode branch to register instruction
>>    objtool: arm64: Decode basic load/stores
>>    objtool: arm64: Decode load/store with register offset
>>    objtool: arm64: Decode load/store register pair instructions
>>    objtool: arm64: Decode FP/SIMD load/store instructions
>>    objtool: arm64: Decode load/store exclusive
>>    objtool: arm64: Decode atomic load/store
>>    objtool: arm64: Decode pointer auth load instructions
>>    objtool: arm64: Decode load acquire/store release
>>    objtool: arm64: Decode load/store with memory tag
>>    objtool: arm64: Decode load literal
>>    objtool: arm64: Decode register data processing instructions
>>    objtool: arm64: Decode FP/SIMD data processing instructions
>>    objtool: arm64: Decode SVE instructions
> 
> That's a lot of decoding logic which we already have in
> arch/arm64/{kernel/insn.c,include/asm/insn.h}. I'd prefer to see this stuff
> reused or generated from a single source, since it's really easy to get it
> wrong, has a tendency to bitrot and is nasty to debug.
> 

The thing is that the code in those files is mostly encoding logic 
(motivated by BPF) rather than decoding (except for the instruction that 
might be trapped, but these rarely overlap with instructions that 
objtools cares about). I agree that ideally the decoding/encoding should 
be under arch/arm64/lib, I was just a bit weary introducing a lot of 
decoding code under arch/arm64 that wouldn't even be used in kernel code.

But I can make an attempt for the encode/decode lib and post it as part 
of the next version.

Cheers,

-- 
Julien Thierry


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

* Re: [RFC v5 00/57] objtool: Add support for arm64
  2020-01-21 17:50   ` Josh Poimboeuf
@ 2020-01-23 13:56     ` Julien Thierry
  0 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-23 13:56 UTC (permalink / raw)
  To: Josh Poimboeuf, Peter Zijlstra
  Cc: linux-kernel, linux-arm-kernel, raphael.gault, catalin.marinas, will



On 1/21/20 5:50 PM, Josh Poimboeuf wrote:
> On Mon, Jan 20, 2020 at 04:07:11PM +0100, Peter Zijlstra wrote:
>> On Thu, Jan 09, 2020 at 04:02:03PM +0000, Julien Thierry wrote:
>>> In the mean time, any feedback on the current state is appreciated.
>>>
>>> * Patches 1 to 18 adapts the current objtool code to make it easier to
>>>    support new architectures.
>>
>> In the interrest of moving things along; I've looked through these
>> and 1-14,16 look good to me, 17,18 hurt my brain.
>>
>> Josh, what say you?
> 
> Agreed.
> 
> Julien, thanks a lot for splitting these up nicely.  If you post 1-14
> (updated based on the recent comments), we can look at merging those
> sooner.
> 

Sure, I'll repost the refactoring patches separately once I've updated them.

> 15-18 also hurt my brain -- probably a symptom of the existing fragile
> mess -- so I'll need to spend more time staring at them.
> 

Yes, the whole state update code hurt quite a lot as well. It took me a 
while to convince myself that my changes felt correct (to me at least, 
it might be that I got things wrong :) ).

Thanks,

-- 
Julien Thierry


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

* Re: [RFC v5 00/57] objtool: Add support for arm64
  2020-01-23 13:52   ` Julien Thierry
@ 2020-01-23 14:35     ` Will Deacon
  2020-01-23 15:11       ` Julien Thierry
  0 siblings, 1 reply; 91+ messages in thread
From: Will Deacon @ 2020-01-23 14:35 UTC (permalink / raw)
  To: Julien Thierry
  Cc: linux-kernel, linux-arm-kernel, jpoimboe, peterz, raphael.gault,
	catalin.marinas

On Thu, Jan 23, 2020 at 01:52:17PM +0000, Julien Thierry wrote:
> 
> 
> On 1/21/20 10:30 AM, Will Deacon wrote:
> > On Thu, Jan 09, 2020 at 04:02:03PM +0000, Julien Thierry wrote:
> > > This patch series is the continuation of Raphael's work [1]. All the
> > > patches can be retrieved from:
> > > git clone -b arm64-objtool-v5 https://github.com/julien-thierry/linux.git
> > 
> > [...]
> > 
> > >    objtool: arm64: Decode unknown instructions
> > >    objtool: arm64: Decode simple data processing instructions
> > >    objtool: arm64: Decode add/sub immediate instructions
> > >    objtool: arm64: Decode logical data processing instructions
> > >    objtool: arm64: Decode system instructions not affecting the flow
> > >    objtool: arm64: Decode calls to higher EL
> > >    objtool: arm64: Decode brk instruction
> > >    objtool: arm64: Decode instruction triggering context switch
> > >    objtool: arm64: Decode branch instructions with PC relative immediates
> > >    objtool: arm64: Decode branch to register instruction
> > >    objtool: arm64: Decode basic load/stores
> > >    objtool: arm64: Decode load/store with register offset
> > >    objtool: arm64: Decode load/store register pair instructions
> > >    objtool: arm64: Decode FP/SIMD load/store instructions
> > >    objtool: arm64: Decode load/store exclusive
> > >    objtool: arm64: Decode atomic load/store
> > >    objtool: arm64: Decode pointer auth load instructions
> > >    objtool: arm64: Decode load acquire/store release
> > >    objtool: arm64: Decode load/store with memory tag
> > >    objtool: arm64: Decode load literal
> > >    objtool: arm64: Decode register data processing instructions
> > >    objtool: arm64: Decode FP/SIMD data processing instructions
> > >    objtool: arm64: Decode SVE instructions
> > 
> > That's a lot of decoding logic which we already have in
> > arch/arm64/{kernel/insn.c,include/asm/insn.h}. I'd prefer to see this stuff
> > reused or generated from a single source, since it's really easy to get it
> > wrong, has a tendency to bitrot and is nasty to debug.
> > 
> 
> The thing is that the code in those files is mostly encoding logic
> (motivated by BPF) rather than decoding (except for the instruction that
> might be trapped, but these rarely overlap with instructions that objtools
> cares about). I agree that ideally the decoding/encoding should be under
> arch/arm64/lib, I was just a bit weary introducing a lot of decoding code
> under arch/arm64 that wouldn't even be used in kernel code.

Hmm, but kprobes decodes instructions somehow :p

Not saying you have to refactor everything, but I'd hope you could reuse
some of the aarch64_insn_is* and aarch64_insn_extract* functions at least.

Will

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

* Re: [RFC v5 47/57] arm64: assembler: Add macro to annotate asm function having non standard stack-frame.
  2020-01-23 13:45     ` Julien Thierry
@ 2020-01-23 14:40       ` Will Deacon
  0 siblings, 0 replies; 91+ messages in thread
From: Will Deacon @ 2020-01-23 14:40 UTC (permalink / raw)
  To: Julien Thierry
  Cc: linux-kernel, linux-arm-kernel, jpoimboe, peterz, raphael.gault,
	catalin.marinas

On Thu, Jan 23, 2020 at 01:45:58PM +0000, Julien Thierry wrote:
> On 1/21/20 10:30 AM, Will Deacon wrote:
> > On Thu, Jan 09, 2020 at 04:02:50PM +0000, Julien Thierry wrote:
> > > From: Raphael Gault <raphael.gault@arm.com>
> > > diff --git a/include/linux/frame.h b/include/linux/frame.h
> > > index 02d3ca2d9598..1e35e58ab259 100644
> > > --- a/include/linux/frame.h
> > > +++ b/include/linux/frame.h
> > > @@ -11,14 +11,31 @@
> > >    *
> > >    * For more information, see tools/objtool/Documentation/stack-validation.txt.
> > >    */
> > > +#ifndef __ASSEMBLY__
> > >   #define STACK_FRAME_NON_STANDARD(func) \
> > >   	static void __used __section(.discard.func_stack_frame_non_standard) \
> > >   		*__func_stack_frame_non_standard_##func = func
> > > +#else
> > > +	/*
> > > +	 * 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
> > > +	.pushsection ".discard.func_stack_frame_non_standard"
> > > +	.quad	\func
> > > +	.popsection
> > > +	.endm
> > > 
> > > +#endif /* __ASSEMBLY__ */
> > >   #else /* !CONFIG_STACK_VALIDATION */
> > > 
> > > +#ifndef __ASSEMBLY__
> > >   #define STACK_FRAME_NON_STANDARD(func)
> > > -
> > > +#else
> > > +	.macro	asm_stack_frame_non_standard	func
> > > +	.endm
> > > +#endif /* __ASSEMBLY__ */
> > 
> > Hmm. Given that we're currently going through the exercise of converting
> > a bunch of ENTRY/ENDPROC macros to use the new SYM_{CODE,FUNC}_{START,END}
> > macros, I would much prefer for this to be a new flavour of those.
> > 
> > In fact, can you just use SYM_CODE_* for this?
> > 
> 
> You mean to not introduce the STACK_FRAME_NON_STANDARD() macro and just mark
> the asm callable symbols that don't set up a stackframe as SYM_CODE_* ?

Yes, unless I'm mistaken, SYM_CODE_* is intended for that sort of thing
anyway.

Will

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

* Re: [RFC v5 00/57] objtool: Add support for arm64
  2020-01-23 14:35     ` Will Deacon
@ 2020-01-23 15:11       ` Julien Thierry
  0 siblings, 0 replies; 91+ messages in thread
From: Julien Thierry @ 2020-01-23 15:11 UTC (permalink / raw)
  To: Will Deacon
  Cc: linux-kernel, linux-arm-kernel, jpoimboe, peterz, raphael.gault,
	catalin.marinas



On 1/23/20 2:35 PM, Will Deacon wrote:
> On Thu, Jan 23, 2020 at 01:52:17PM +0000, Julien Thierry wrote:
>>
>>
>> On 1/21/20 10:30 AM, Will Deacon wrote:
>>> On Thu, Jan 09, 2020 at 04:02:03PM +0000, Julien Thierry wrote:
>>>> This patch series is the continuation of Raphael's work [1]. All the
>>>> patches can be retrieved from:
>>>> git clone -b arm64-objtool-v5 https://github.com/julien-thierry/linux.git
>>>
>>> [...]
>>>
>>>>     objtool: arm64: Decode unknown instructions
>>>>     objtool: arm64: Decode simple data processing instructions
>>>>     objtool: arm64: Decode add/sub immediate instructions
>>>>     objtool: arm64: Decode logical data processing instructions
>>>>     objtool: arm64: Decode system instructions not affecting the flow
>>>>     objtool: arm64: Decode calls to higher EL
>>>>     objtool: arm64: Decode brk instruction
>>>>     objtool: arm64: Decode instruction triggering context switch
>>>>     objtool: arm64: Decode branch instructions with PC relative immediates
>>>>     objtool: arm64: Decode branch to register instruction
>>>>     objtool: arm64: Decode basic load/stores
>>>>     objtool: arm64: Decode load/store with register offset
>>>>     objtool: arm64: Decode load/store register pair instructions
>>>>     objtool: arm64: Decode FP/SIMD load/store instructions
>>>>     objtool: arm64: Decode load/store exclusive
>>>>     objtool: arm64: Decode atomic load/store
>>>>     objtool: arm64: Decode pointer auth load instructions
>>>>     objtool: arm64: Decode load acquire/store release
>>>>     objtool: arm64: Decode load/store with memory tag
>>>>     objtool: arm64: Decode load literal
>>>>     objtool: arm64: Decode register data processing instructions
>>>>     objtool: arm64: Decode FP/SIMD data processing instructions
>>>>     objtool: arm64: Decode SVE instructions
>>>
>>> That's a lot of decoding logic which we already have in
>>> arch/arm64/{kernel/insn.c,include/asm/insn.h}. I'd prefer to see this stuff
>>> reused or generated from a single source, since it's really easy to get it
>>> wrong, has a tendency to bitrot and is nasty to debug.
>>>
>>
>> The thing is that the code in those files is mostly encoding logic
>> (motivated by BPF) rather than decoding (except for the instruction that
>> might be trapped, but these rarely overlap with instructions that objtools
>> cares about). I agree that ideally the decoding/encoding should be under
>> arch/arm64/lib, I was just a bit weary introducing a lot of decoding code
>> under arch/arm64 that wouldn't even be used in kernel code.
> 
> Hmm, but kprobes decodes instructions somehow :p
> 
> Not saying you have to refactor everything, but I'd hope you could reuse
> some of the aarch64_insn_is* and aarch64_insn_extract* functions at least.
> 

Oh, you're right, there seem to be more than what I remembered. There is 
probably a bunch of things I can reuse (and I'll feel more at ease with 
that rather than introducing a whole bunch of new code :D ).

Thanks,

-- 
Julien Thierry


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

end of thread, other threads:[~2020-01-23 15:11 UTC | newest]

Thread overview: 91+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-01-09 16:02 [RFC v5 00/57] objtool: Add support for arm64 Julien Thierry
2020-01-09 16:02 ` [RFC v5 01/57] objtool: check: Remove redundant checks on operand type Julien Thierry
2020-01-09 16:02 ` [RFC v5 02/57] objtool: check: Clean instruction state before each function validation Julien Thierry
2020-01-09 16:02 ` [RFC v5 03/57] objtool: check: Use arch specific values in restore_reg() Julien Thierry
2020-01-09 16:02 ` [RFC v5 04/57] objtool: check: Ignore empty alternative groups Julien Thierry
2020-01-21 16:30   ` Josh Poimboeuf
2020-01-23 11:45     ` Julien Thierry
2020-01-09 16:02 ` [RFC v5 05/57] objtool: Add abstraction for computation of symbols offsets Julien Thierry
2020-01-09 16:02 ` [RFC v5 06/57] objtool: Give ORC functions consistent name Julien Thierry
2020-01-09 16:02 ` [RFC v5 07/57] objtool: orc: Refactor ORC API for other architectures to implement Julien Thierry
2020-01-09 16:02 ` [RFC v5 08/57] objtool: Make ORC support optional Julien Thierry
2020-01-21 16:37   ` Josh Poimboeuf
2020-01-23 11:45     ` Julien Thierry
2020-01-09 16:02 ` [RFC v5 09/57] objtool: Move registers and control flow to arch-dependent code Julien Thierry
2020-01-09 16:02 ` [RFC v5 10/57] objtool: Split generic and arch specific CFI definitions Julien Thierry
2020-01-09 16:02 ` [RFC v5 11/57] objtool: Abstract alternative special case handling Julien Thierry
2020-01-20 14:54   ` Peter Zijlstra
2020-01-23 11:45     ` Julien Thierry
2020-01-09 16:02 ` [RFC v5 12/57] objtool: check: Allow jumps from an alternative group to itself Julien Thierry
2020-01-20 14:56   ` Peter Zijlstra
2020-01-21 10:30     ` Will Deacon
2020-01-21 17:33   ` Josh Poimboeuf
2020-01-23 13:42     ` Julien Thierry
2020-01-09 16:02 ` [RFC v5 13/57] objtool: Refactor switch-tables code to support other architectures Julien Thierry
2020-01-09 16:02 ` [RFC v5 14/57] objtool: Do not look for STT_NOTYPE symbols Julien Thierry
2020-01-13 10:20   ` Julien Thierry
2020-01-09 16:02 ` [RFC v5 15/57] objtool: Support addition to set frame pointer Julien Thierry
2020-01-09 16:02 ` [RFC v5 16/57] objtool: Support restoring BP from the stack without POP Julien Thierry
2020-01-09 16:02 ` [RFC v5 17/57] objtool: Make stack validation more generic Julien Thierry
2020-01-09 16:02 ` [RFC v5 18/57] objtool: Support multiple stack_op per instruction Julien Thierry
2020-01-09 16:02 ` [RFC v5 19/57] objtool: arm64: Add required implementation for supporting the aarch64 architecture in objtool Julien Thierry
2020-01-09 16:02 ` [RFC v5 20/57] objtool: arm64: Decode unknown instructions Julien Thierry
2020-01-09 16:02 ` [RFC v5 21/57] objtool: arm64: Decode simple data processing instructions Julien Thierry
2020-01-09 16:02 ` [RFC v5 22/57] objtool: arm64: Decode add/sub immediate instructions Julien Thierry
2020-01-09 16:02 ` [RFC v5 23/57] objtool: arm64: Decode logical data processing instructions Julien Thierry
2020-01-09 16:02 ` [RFC v5 24/57] objtool: arm64: Decode system instructions not affecting the flow Julien Thierry
2020-01-09 16:02 ` [RFC v5 25/57] objtool: arm64: Decode calls to higher EL Julien Thierry
2020-01-09 16:02 ` [RFC v5 26/57] objtool: arm64: Decode brk instruction Julien Thierry
2020-01-09 16:02 ` [RFC v5 27/57] objtool: arm64: Decode instruction triggering context switch Julien Thierry
2020-01-09 16:02 ` [RFC v5 28/57] objtool: arm64: Decode branch instructions with PC relative immediates Julien Thierry
2020-01-09 16:02 ` [RFC v5 29/57] objtool: arm64: Decode branch to register instruction Julien Thierry
2020-01-09 16:02 ` [RFC v5 30/57] objtool: arm64: Decode basic load/stores Julien Thierry
2020-01-09 16:02 ` [RFC v5 31/57] objtool: arm64: Decode load/store with register offset Julien Thierry
2020-01-09 16:02 ` [RFC v5 32/57] objtool: arm64: Decode load/store register pair instructions Julien Thierry
2020-01-09 16:02 ` [RFC v5 33/57] objtool: arm64: Decode FP/SIMD load/store instructions Julien Thierry
2020-01-09 16:02 ` [RFC v5 34/57] objtool: arm64: Decode load/store exclusive Julien Thierry
2020-01-09 16:02 ` [RFC v5 35/57] objtool: arm64: Decode atomic load/store Julien Thierry
2020-01-09 16:02 ` [RFC v5 36/57] objtool: arm64: Decode pointer auth load instructions Julien Thierry
2020-01-09 16:02 ` [RFC v5 37/57] objtool: arm64: Decode load acquire/store release Julien Thierry
2020-01-09 16:02 ` [RFC v5 38/57] objtool: arm64: Decode load/store with memory tag Julien Thierry
2020-01-09 16:02 ` [RFC v5 39/57] objtool: arm64: Decode load literal Julien Thierry
2020-01-09 16:02 ` [RFC v5 40/57] objtool: arm64: Decode register data processing instructions Julien Thierry
2020-01-09 16:02 ` [RFC v5 41/57] objtool: arm64: Decode FP/SIMD " Julien Thierry
2020-01-09 16:02 ` [RFC v5 42/57] objtool: arm64: Decode SVE instructions Julien Thierry
2020-01-09 16:02 ` [RFC v5 43/57] gcc-plugins: objtool: Add plugin to detect switch table on arm64 Julien Thierry
2020-01-09 16:02 ` [RFC v5 44/57] objtool: arm64: Implement functions to add switch tables alternatives Julien Thierry
2020-01-15 16:37   ` Raphael Gault
2020-01-17  8:28     ` Julien Thierry
2020-01-09 16:02 ` [RFC v5 45/57] objtool: arm64: Enable stack validation for arm64 Julien Thierry
2020-01-09 16:02 ` [RFC v5 46/57] arm64: alternative: Mark .altinstr_replacement as containing executable instructions Julien Thierry
2020-01-09 16:02 ` [RFC v5 47/57] arm64: assembler: Add macro to annotate asm function having non standard stack-frame Julien Thierry
2020-01-21 10:30   ` Will Deacon
2020-01-23 13:45     ` Julien Thierry
2020-01-23 14:40       ` Will Deacon
2020-01-09 16:02 ` [RFC v5 48/57] arm64: sleep: Prevent stack frame warnings from objtool Julien Thierry
2020-01-09 16:02 ` [RFC v5 49/57] arm64: kvm: Annotate non-standard stack frame functions Julien Thierry
2020-01-09 16:02 ` [RFC v5 50/57] arm64: kernel: Add exception on kuser32 to prevent stack analysis Julien Thierry
2020-01-09 16:02 ` [RFC v5 51/57] arm64: crypto: Add exceptions for crypto object " Julien Thierry
2020-01-09 16:02 ` [RFC v5 52/57] arm64: kernel: Annotate non-standard stack frame functions Julien Thierry
2020-01-09 16:02 ` [RFC v5 53/57] arm64: Generate no-ops to pad executable section Julien Thierry
2020-01-09 16:02 ` [RFC v5 54/57] arm64: Move constant to rodata Julien Thierry
2020-01-09 16:02 ` [RFC v5 55/57] arm64: Mark sigreturn32.o as containing non standard code Julien Thierry
2020-01-09 16:02 ` [RFC v5 56/57] arm64: entry: Avoid empty alternatives entries Julien Thierry
2020-01-09 16:51   ` Mark Rutland
2020-01-21 10:30     ` Will Deacon
2020-01-09 16:03 ` [RFC v5 57/57] arm64: crypto: Remove redundant branch Julien Thierry
2020-01-12  8:42 ` [RFC v5 00/57] objtool: Add support for arm64 Nathan Chancellor
2020-01-13  7:57   ` Julien Thierry
2020-01-21 10:31     ` Will Deacon
2020-01-21 17:08       ` Nick Desaulniers
2020-01-21 18:06         ` Will Deacon
2020-01-21 18:30           ` Josh Poimboeuf
2020-01-22 14:47             ` Will Deacon
2020-01-13 17:18   ` Nick Desaulniers
2020-01-20 15:07 ` Peter Zijlstra
2020-01-21 17:50   ` Josh Poimboeuf
2020-01-23 13:56     ` Julien Thierry
2020-01-21 10:30 ` Will Deacon
2020-01-23 13:52   ` Julien Thierry
2020-01-23 14:35     ` Will Deacon
2020-01-23 15:11       ` Julien Thierry

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).