root/tools/objtool/orc_gen.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. create_orc
  2. create_orc_entry
  3. create_orc_sections

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com>
   4  */
   5 
   6 #include <stdlib.h>
   7 #include <string.h>
   8 
   9 #include "orc.h"
  10 #include "check.h"
  11 #include "warn.h"
  12 
  13 int create_orc(struct objtool_file *file)
  14 {
  15         struct instruction *insn;
  16 
  17         for_each_insn(file, insn) {
  18                 struct orc_entry *orc = &insn->orc;
  19                 struct cfi_reg *cfa = &insn->state.cfa;
  20                 struct cfi_reg *bp = &insn->state.regs[CFI_BP];
  21 
  22                 orc->end = insn->state.end;
  23 
  24                 if (cfa->base == CFI_UNDEFINED) {
  25                         orc->sp_reg = ORC_REG_UNDEFINED;
  26                         continue;
  27                 }
  28 
  29                 switch (cfa->base) {
  30                 case CFI_SP:
  31                         orc->sp_reg = ORC_REG_SP;
  32                         break;
  33                 case CFI_SP_INDIRECT:
  34                         orc->sp_reg = ORC_REG_SP_INDIRECT;
  35                         break;
  36                 case CFI_BP:
  37                         orc->sp_reg = ORC_REG_BP;
  38                         break;
  39                 case CFI_BP_INDIRECT:
  40                         orc->sp_reg = ORC_REG_BP_INDIRECT;
  41                         break;
  42                 case CFI_R10:
  43                         orc->sp_reg = ORC_REG_R10;
  44                         break;
  45                 case CFI_R13:
  46                         orc->sp_reg = ORC_REG_R13;
  47                         break;
  48                 case CFI_DI:
  49                         orc->sp_reg = ORC_REG_DI;
  50                         break;
  51                 case CFI_DX:
  52                         orc->sp_reg = ORC_REG_DX;
  53                         break;
  54                 default:
  55                         WARN_FUNC("unknown CFA base reg %d",
  56                                   insn->sec, insn->offset, cfa->base);
  57                         return -1;
  58                 }
  59 
  60                 switch(bp->base) {
  61                 case CFI_UNDEFINED:
  62                         orc->bp_reg = ORC_REG_UNDEFINED;
  63                         break;
  64                 case CFI_CFA:
  65                         orc->bp_reg = ORC_REG_PREV_SP;
  66                         break;
  67                 case CFI_BP:
  68                         orc->bp_reg = ORC_REG_BP;
  69                         break;
  70                 default:
  71                         WARN_FUNC("unknown BP base reg %d",
  72                                   insn->sec, insn->offset, bp->base);
  73                         return -1;
  74                 }
  75 
  76                 orc->sp_offset = cfa->offset;
  77                 orc->bp_offset = bp->offset;
  78                 orc->type = insn->state.type;
  79         }
  80 
  81         return 0;
  82 }
  83 
  84 static int create_orc_entry(struct section *u_sec, struct section *ip_relasec,
  85                                 unsigned int idx, struct section *insn_sec,
  86                                 unsigned long insn_off, struct orc_entry *o)
  87 {
  88         struct orc_entry *orc;
  89         struct rela *rela;
  90 
  91         if (!insn_sec->sym) {
  92                 WARN("missing symbol for section %s", insn_sec->name);
  93                 return -1;
  94         }
  95 
  96         /* populate ORC data */
  97         orc = (struct orc_entry *)u_sec->data->d_buf + idx;
  98         memcpy(orc, o, sizeof(*orc));
  99 
 100         /* populate rela for ip */
 101         rela = malloc(sizeof(*rela));
 102         if (!rela) {
 103                 perror("malloc");
 104                 return -1;
 105         }
 106         memset(rela, 0, sizeof(*rela));
 107 
 108         rela->sym = insn_sec->sym;
 109         rela->addend = insn_off;
 110         rela->type = R_X86_64_PC32;
 111         rela->offset = idx * sizeof(int);
 112 
 113         list_add_tail(&rela->list, &ip_relasec->rela_list);
 114         hash_add(ip_relasec->rela_hash, &rela->hash, rela->offset);
 115 
 116         return 0;
 117 }
 118 
 119 int create_orc_sections(struct objtool_file *file)
 120 {
 121         struct instruction *insn, *prev_insn;
 122         struct section *sec, *u_sec, *ip_relasec;
 123         unsigned int idx;
 124 
 125         struct orc_entry empty = {
 126                 .sp_reg = ORC_REG_UNDEFINED,
 127                 .bp_reg  = ORC_REG_UNDEFINED,
 128                 .type    = ORC_TYPE_CALL,
 129         };
 130 
 131         sec = find_section_by_name(file->elf, ".orc_unwind");
 132         if (sec) {
 133                 WARN("file already has .orc_unwind section, skipping");
 134                 return -1;
 135         }
 136 
 137         /* count the number of needed orcs */
 138         idx = 0;
 139         for_each_sec(file, sec) {
 140                 if (!sec->text)
 141                         continue;
 142 
 143                 prev_insn = NULL;
 144                 sec_for_each_insn(file, sec, insn) {
 145                         if (!prev_insn ||
 146                             memcmp(&insn->orc, &prev_insn->orc,
 147                                    sizeof(struct orc_entry))) {
 148                                 idx++;
 149                         }
 150                         prev_insn = insn;
 151                 }
 152 
 153                 /* section terminator */
 154                 if (prev_insn)
 155                         idx++;
 156         }
 157         if (!idx)
 158                 return -1;
 159 
 160 
 161         /* create .orc_unwind_ip and .rela.orc_unwind_ip sections */
 162         sec = elf_create_section(file->elf, ".orc_unwind_ip", sizeof(int), idx);
 163         if (!sec)
 164                 return -1;
 165 
 166         ip_relasec = elf_create_rela_section(file->elf, sec);
 167         if (!ip_relasec)
 168                 return -1;
 169 
 170         /* create .orc_unwind section */
 171         u_sec = elf_create_section(file->elf, ".orc_unwind",
 172                                    sizeof(struct orc_entry), idx);
 173 
 174         /* populate sections */
 175         idx = 0;
 176         for_each_sec(file, sec) {
 177                 if (!sec->text)
 178                         continue;
 179 
 180                 prev_insn = NULL;
 181                 sec_for_each_insn(file, sec, insn) {
 182                         if (!prev_insn || memcmp(&insn->orc, &prev_insn->orc,
 183                                                  sizeof(struct orc_entry))) {
 184 
 185                                 if (create_orc_entry(u_sec, ip_relasec, idx,
 186                                                      insn->sec, insn->offset,
 187                                                      &insn->orc))
 188                                         return -1;
 189 
 190                                 idx++;
 191                         }
 192                         prev_insn = insn;
 193                 }
 194 
 195                 /* section terminator */
 196                 if (prev_insn) {
 197                         if (create_orc_entry(u_sec, ip_relasec, idx,
 198                                              prev_insn->sec,
 199                                              prev_insn->offset + prev_insn->len,
 200                                              &empty))
 201                                 return -1;
 202 
 203                         idx++;
 204                 }
 205         }
 206 
 207         if (elf_rebuild_rela_section(ip_relasec))
 208                 return -1;
 209 
 210         return 0;
 211 }

/* [<][>][^][v][top][bottom][index][help] */