linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
From: Julien Thierry <jthierry@redhat.com>
To: Raphael Gault <raphael.gault@arm.com>,
	linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org
Cc: peterz@infradead.org, catalin.marinas@arm.com, will@kernel.org,
	jpoimboe@redhat.com
Subject: Re: [RFC v5 44/57] objtool: arm64: Implement functions to add switch tables alternatives
Date: Fri, 17 Jan 2020 08:28:49 +0000	[thread overview]
Message-ID: <3d471dd2-f2ad-3cc4-b1f7-9a5da9c24cd1@redhat.com> (raw)
In-Reply-To: <370e38b3-3c0c-e552-16fa-36571dd8e66b@arm.com>

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


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

  reply	other threads:[~2020-01-17  8:29 UTC|newest]

Thread overview: 91+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 [this message]
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=3d471dd2-f2ad-3cc4-b1f7-9a5da9c24cd1@redhat.com \
    --to=jthierry@redhat.com \
    --cc=catalin.marinas@arm.com \
    --cc=jpoimboe@redhat.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=peterz@infradead.org \
    --cc=raphael.gault@arm.com \
    --cc=will@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).