| .. | .. | 
|---|
|  | 1 | +// SPDX-License-Identifier: GPL-2.0-or-later | 
|---|
| 1 | 2 | /* | 
|---|
| 2 | 3 | * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com> | 
|---|
| 3 |  | - * | 
|---|
| 4 |  | - * This program is free software; you can redistribute it and/or | 
|---|
| 5 |  | - * modify it under the terms of the GNU General Public License | 
|---|
| 6 |  | - * as published by the Free Software Foundation; either version 2 | 
|---|
| 7 |  | - * of the License, or (at your option) any later version. | 
|---|
| 8 |  | - * | 
|---|
| 9 |  | - * This program is distributed in the hope that it will be useful, | 
|---|
| 10 |  | - * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|---|
| 11 |  | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|---|
| 12 |  | - * GNU General Public License for more details. | 
|---|
| 13 |  | - * | 
|---|
| 14 |  | - * You should have received a copy of the GNU General Public License | 
|---|
| 15 |  | - * along with this program; if not, see <http://www.gnu.org/licenses/>. | 
|---|
| 16 | 4 | */ | 
|---|
| 17 | 5 |  | 
|---|
| 18 | 6 | #include <stdlib.h> | 
|---|
| 19 | 7 | #include <string.h> | 
|---|
| 20 | 8 |  | 
|---|
| 21 |  | -#include "orc.h" | 
|---|
|  | 9 | +#include <linux/objtool.h> | 
|---|
|  | 10 | +#include <asm/orc_types.h> | 
|---|
|  | 11 | + | 
|---|
| 22 | 12 | #include "check.h" | 
|---|
| 23 | 13 | #include "warn.h" | 
|---|
| 24 | 14 |  | 
|---|
| 25 |  | -int create_orc(struct objtool_file *file) | 
|---|
|  | 15 | +static int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, | 
|---|
|  | 16 | +			  struct instruction *insn) | 
|---|
| 26 | 17 | { | 
|---|
| 27 |  | -	struct instruction *insn; | 
|---|
|  | 18 | +	struct cfi_reg *bp = &cfi->regs[CFI_BP]; | 
|---|
| 28 | 19 |  | 
|---|
| 29 |  | -	for_each_insn(file, insn) { | 
|---|
| 30 |  | -		struct orc_entry *orc = &insn->orc; | 
|---|
| 31 |  | -		struct cfi_reg *cfa = &insn->state.cfa; | 
|---|
| 32 |  | -		struct cfi_reg *bp = &insn->state.regs[CFI_BP]; | 
|---|
|  | 20 | +	memset(orc, 0, sizeof(*orc)); | 
|---|
| 33 | 21 |  | 
|---|
| 34 |  | -		orc->end = insn->state.end; | 
|---|
| 35 |  | - | 
|---|
| 36 |  | -		if (cfa->base == CFI_UNDEFINED) { | 
|---|
| 37 |  | -			orc->sp_reg = ORC_REG_UNDEFINED; | 
|---|
| 38 |  | -			continue; | 
|---|
| 39 |  | -		} | 
|---|
| 40 |  | - | 
|---|
| 41 |  | -		switch (cfa->base) { | 
|---|
| 42 |  | -		case CFI_SP: | 
|---|
| 43 |  | -			orc->sp_reg = ORC_REG_SP; | 
|---|
| 44 |  | -			break; | 
|---|
| 45 |  | -		case CFI_SP_INDIRECT: | 
|---|
| 46 |  | -			orc->sp_reg = ORC_REG_SP_INDIRECT; | 
|---|
| 47 |  | -			break; | 
|---|
| 48 |  | -		case CFI_BP: | 
|---|
| 49 |  | -			orc->sp_reg = ORC_REG_BP; | 
|---|
| 50 |  | -			break; | 
|---|
| 51 |  | -		case CFI_BP_INDIRECT: | 
|---|
| 52 |  | -			orc->sp_reg = ORC_REG_BP_INDIRECT; | 
|---|
| 53 |  | -			break; | 
|---|
| 54 |  | -		case CFI_R10: | 
|---|
| 55 |  | -			orc->sp_reg = ORC_REG_R10; | 
|---|
| 56 |  | -			break; | 
|---|
| 57 |  | -		case CFI_R13: | 
|---|
| 58 |  | -			orc->sp_reg = ORC_REG_R13; | 
|---|
| 59 |  | -			break; | 
|---|
| 60 |  | -		case CFI_DI: | 
|---|
| 61 |  | -			orc->sp_reg = ORC_REG_DI; | 
|---|
| 62 |  | -			break; | 
|---|
| 63 |  | -		case CFI_DX: | 
|---|
| 64 |  | -			orc->sp_reg = ORC_REG_DX; | 
|---|
| 65 |  | -			break; | 
|---|
| 66 |  | -		default: | 
|---|
| 67 |  | -			WARN_FUNC("unknown CFA base reg %d", | 
|---|
| 68 |  | -				  insn->sec, insn->offset, cfa->base); | 
|---|
| 69 |  | -			return -1; | 
|---|
| 70 |  | -		} | 
|---|
| 71 |  | - | 
|---|
| 72 |  | -		switch(bp->base) { | 
|---|
| 73 |  | -		case CFI_UNDEFINED: | 
|---|
| 74 |  | -			orc->bp_reg = ORC_REG_UNDEFINED; | 
|---|
| 75 |  | -			break; | 
|---|
| 76 |  | -		case CFI_CFA: | 
|---|
| 77 |  | -			orc->bp_reg = ORC_REG_PREV_SP; | 
|---|
| 78 |  | -			break; | 
|---|
| 79 |  | -		case CFI_BP: | 
|---|
| 80 |  | -			orc->bp_reg = ORC_REG_BP; | 
|---|
| 81 |  | -			break; | 
|---|
| 82 |  | -		default: | 
|---|
| 83 |  | -			WARN_FUNC("unknown BP base reg %d", | 
|---|
| 84 |  | -				  insn->sec, insn->offset, bp->base); | 
|---|
| 85 |  | -			return -1; | 
|---|
| 86 |  | -		} | 
|---|
| 87 |  | - | 
|---|
| 88 |  | -		orc->sp_offset = cfa->offset; | 
|---|
| 89 |  | -		orc->bp_offset = bp->offset; | 
|---|
| 90 |  | -		orc->type = insn->state.type; | 
|---|
|  | 22 | +	if (!cfi) { | 
|---|
|  | 23 | +		orc->end = 0; | 
|---|
|  | 24 | +		orc->sp_reg = ORC_REG_UNDEFINED; | 
|---|
|  | 25 | +		return 0; | 
|---|
| 91 | 26 | } | 
|---|
| 92 | 27 |  | 
|---|
| 93 |  | -	return 0; | 
|---|
| 94 |  | -} | 
|---|
|  | 28 | +	orc->end = cfi->end; | 
|---|
| 95 | 29 |  | 
|---|
| 96 |  | -static int create_orc_entry(struct section *u_sec, struct section *ip_relasec, | 
|---|
| 97 |  | -				unsigned int idx, struct section *insn_sec, | 
|---|
| 98 |  | -				unsigned long insn_off, struct orc_entry *o) | 
|---|
| 99 |  | -{ | 
|---|
| 100 |  | -	struct orc_entry *orc; | 
|---|
| 101 |  | -	struct rela *rela; | 
|---|
|  | 30 | +	if (cfi->cfa.base == CFI_UNDEFINED) { | 
|---|
|  | 31 | +		orc->sp_reg = ORC_REG_UNDEFINED; | 
|---|
|  | 32 | +		return 0; | 
|---|
|  | 33 | +	} | 
|---|
| 102 | 34 |  | 
|---|
| 103 |  | -	/* populate ORC data */ | 
|---|
| 104 |  | -	orc = (struct orc_entry *)u_sec->data->d_buf + idx; | 
|---|
| 105 |  | -	memcpy(orc, o, sizeof(*orc)); | 
|---|
| 106 |  | - | 
|---|
| 107 |  | -	/* populate rela for ip */ | 
|---|
| 108 |  | -	rela = malloc(sizeof(*rela)); | 
|---|
| 109 |  | -	if (!rela) { | 
|---|
| 110 |  | -		perror("malloc"); | 
|---|
|  | 35 | +	switch (cfi->cfa.base) { | 
|---|
|  | 36 | +	case CFI_SP: | 
|---|
|  | 37 | +		orc->sp_reg = ORC_REG_SP; | 
|---|
|  | 38 | +		break; | 
|---|
|  | 39 | +	case CFI_SP_INDIRECT: | 
|---|
|  | 40 | +		orc->sp_reg = ORC_REG_SP_INDIRECT; | 
|---|
|  | 41 | +		break; | 
|---|
|  | 42 | +	case CFI_BP: | 
|---|
|  | 43 | +		orc->sp_reg = ORC_REG_BP; | 
|---|
|  | 44 | +		break; | 
|---|
|  | 45 | +	case CFI_BP_INDIRECT: | 
|---|
|  | 46 | +		orc->sp_reg = ORC_REG_BP_INDIRECT; | 
|---|
|  | 47 | +		break; | 
|---|
|  | 48 | +	case CFI_R10: | 
|---|
|  | 49 | +		orc->sp_reg = ORC_REG_R10; | 
|---|
|  | 50 | +		break; | 
|---|
|  | 51 | +	case CFI_R13: | 
|---|
|  | 52 | +		orc->sp_reg = ORC_REG_R13; | 
|---|
|  | 53 | +		break; | 
|---|
|  | 54 | +	case CFI_DI: | 
|---|
|  | 55 | +		orc->sp_reg = ORC_REG_DI; | 
|---|
|  | 56 | +		break; | 
|---|
|  | 57 | +	case CFI_DX: | 
|---|
|  | 58 | +		orc->sp_reg = ORC_REG_DX; | 
|---|
|  | 59 | +		break; | 
|---|
|  | 60 | +	default: | 
|---|
|  | 61 | +		WARN_FUNC("unknown CFA base reg %d", | 
|---|
|  | 62 | +			  insn->sec, insn->offset, cfi->cfa.base); | 
|---|
| 111 | 63 | return -1; | 
|---|
| 112 | 64 | } | 
|---|
| 113 |  | -	memset(rela, 0, sizeof(*rela)); | 
|---|
| 114 | 65 |  | 
|---|
| 115 |  | -	if (insn_sec->sym) { | 
|---|
| 116 |  | -		rela->sym = insn_sec->sym; | 
|---|
| 117 |  | -		rela->addend = insn_off; | 
|---|
| 118 |  | -	} else { | 
|---|
| 119 |  | -		/* | 
|---|
| 120 |  | -		 * The Clang assembler doesn't produce section symbols, so we | 
|---|
| 121 |  | -		 * have to reference the function symbol instead: | 
|---|
| 122 |  | -		 */ | 
|---|
| 123 |  | -		rela->sym = find_symbol_containing(insn_sec, insn_off); | 
|---|
| 124 |  | -		if (!rela->sym) { | 
|---|
| 125 |  | -			/* | 
|---|
| 126 |  | -			 * Hack alert.  This happens when we need to reference | 
|---|
| 127 |  | -			 * the NOP pad insn immediately after the function. | 
|---|
| 128 |  | -			 */ | 
|---|
| 129 |  | -			rela->sym = find_symbol_containing(insn_sec, | 
|---|
| 130 |  | -							   insn_off - 1); | 
|---|
| 131 |  | -		} | 
|---|
| 132 |  | -		if (!rela->sym) { | 
|---|
| 133 |  | -			WARN("missing symbol for insn at offset 0x%lx\n", | 
|---|
| 134 |  | -			     insn_off); | 
|---|
| 135 |  | -			return -1; | 
|---|
| 136 |  | -		} | 
|---|
| 137 |  | - | 
|---|
| 138 |  | -		rela->addend = insn_off - rela->sym->offset; | 
|---|
|  | 66 | +	switch (bp->base) { | 
|---|
|  | 67 | +	case CFI_UNDEFINED: | 
|---|
|  | 68 | +		orc->bp_reg = ORC_REG_UNDEFINED; | 
|---|
|  | 69 | +		break; | 
|---|
|  | 70 | +	case CFI_CFA: | 
|---|
|  | 71 | +		orc->bp_reg = ORC_REG_PREV_SP; | 
|---|
|  | 72 | +		break; | 
|---|
|  | 73 | +	case CFI_BP: | 
|---|
|  | 74 | +		orc->bp_reg = ORC_REG_BP; | 
|---|
|  | 75 | +		break; | 
|---|
|  | 76 | +	default: | 
|---|
|  | 77 | +		WARN_FUNC("unknown BP base reg %d", | 
|---|
|  | 78 | +			  insn->sec, insn->offset, bp->base); | 
|---|
|  | 79 | +		return -1; | 
|---|
| 139 | 80 | } | 
|---|
| 140 | 81 |  | 
|---|
| 141 |  | -	rela->type = R_X86_64_PC32; | 
|---|
| 142 |  | -	rela->offset = idx * sizeof(int); | 
|---|
| 143 |  | - | 
|---|
| 144 |  | -	list_add_tail(&rela->list, &ip_relasec->rela_list); | 
|---|
| 145 |  | -	hash_add(ip_relasec->rela_hash, &rela->hash, rela->offset); | 
|---|
|  | 82 | +	orc->sp_offset = cfi->cfa.offset; | 
|---|
|  | 83 | +	orc->bp_offset = bp->offset; | 
|---|
|  | 84 | +	orc->type = cfi->type; | 
|---|
| 146 | 85 |  | 
|---|
| 147 | 86 | return 0; | 
|---|
| 148 | 87 | } | 
|---|
| 149 | 88 |  | 
|---|
| 150 |  | -int create_orc_sections(struct objtool_file *file) | 
|---|
|  | 89 | +static int write_orc_entry(struct elf *elf, struct section *orc_sec, | 
|---|
|  | 90 | +			   struct section *ip_sec, unsigned int idx, | 
|---|
|  | 91 | +			   struct section *insn_sec, unsigned long insn_off, | 
|---|
|  | 92 | +			   struct orc_entry *o) | 
|---|
| 151 | 93 | { | 
|---|
| 152 |  | -	struct instruction *insn, *prev_insn; | 
|---|
| 153 |  | -	struct section *sec, *u_sec, *ip_relasec; | 
|---|
| 154 |  | -	unsigned int idx; | 
|---|
|  | 94 | +	struct orc_entry *orc; | 
|---|
| 155 | 95 |  | 
|---|
| 156 |  | -	struct orc_entry empty = { | 
|---|
| 157 |  | -		.sp_reg = ORC_REG_UNDEFINED, | 
|---|
|  | 96 | +	/* populate ORC data */ | 
|---|
|  | 97 | +	orc = (struct orc_entry *)orc_sec->data->d_buf + idx; | 
|---|
|  | 98 | +	memcpy(orc, o, sizeof(*orc)); | 
|---|
|  | 99 | + | 
|---|
|  | 100 | +	/* populate reloc for ip */ | 
|---|
|  | 101 | +	if (elf_add_reloc_to_insn(elf, ip_sec, idx * sizeof(int), R_X86_64_PC32, | 
|---|
|  | 102 | +				  insn_sec, insn_off)) | 
|---|
|  | 103 | +		return -1; | 
|---|
|  | 104 | + | 
|---|
|  | 105 | +	return 0; | 
|---|
|  | 106 | +} | 
|---|
|  | 107 | + | 
|---|
|  | 108 | +struct orc_list_entry { | 
|---|
|  | 109 | +	struct list_head list; | 
|---|
|  | 110 | +	struct orc_entry orc; | 
|---|
|  | 111 | +	struct section *insn_sec; | 
|---|
|  | 112 | +	unsigned long insn_off; | 
|---|
|  | 113 | +}; | 
|---|
|  | 114 | + | 
|---|
|  | 115 | +static int orc_list_add(struct list_head *orc_list, struct orc_entry *orc, | 
|---|
|  | 116 | +			struct section *sec, unsigned long offset) | 
|---|
|  | 117 | +{ | 
|---|
|  | 118 | +	struct orc_list_entry *entry = malloc(sizeof(*entry)); | 
|---|
|  | 119 | + | 
|---|
|  | 120 | +	if (!entry) { | 
|---|
|  | 121 | +		WARN("malloc failed"); | 
|---|
|  | 122 | +		return -1; | 
|---|
|  | 123 | +	} | 
|---|
|  | 124 | + | 
|---|
|  | 125 | +	entry->orc	= *orc; | 
|---|
|  | 126 | +	entry->insn_sec = sec; | 
|---|
|  | 127 | +	entry->insn_off = offset; | 
|---|
|  | 128 | + | 
|---|
|  | 129 | +	list_add_tail(&entry->list, orc_list); | 
|---|
|  | 130 | +	return 0; | 
|---|
|  | 131 | +} | 
|---|
|  | 132 | + | 
|---|
|  | 133 | +static unsigned long alt_group_len(struct alt_group *alt_group) | 
|---|
|  | 134 | +{ | 
|---|
|  | 135 | +	return alt_group->last_insn->offset + | 
|---|
|  | 136 | +	       alt_group->last_insn->len - | 
|---|
|  | 137 | +	       alt_group->first_insn->offset; | 
|---|
|  | 138 | +} | 
|---|
|  | 139 | + | 
|---|
|  | 140 | +int orc_create(struct objtool_file *file) | 
|---|
|  | 141 | +{ | 
|---|
|  | 142 | +	struct section *sec, *orc_sec; | 
|---|
|  | 143 | +	unsigned int nr = 0, idx = 0; | 
|---|
|  | 144 | +	struct orc_list_entry *entry; | 
|---|
|  | 145 | +	struct list_head orc_list; | 
|---|
|  | 146 | + | 
|---|
|  | 147 | +	struct orc_entry null = { | 
|---|
|  | 148 | +		.sp_reg  = ORC_REG_UNDEFINED, | 
|---|
| 158 | 149 | .bp_reg  = ORC_REG_UNDEFINED, | 
|---|
| 159 |  | -		.type    = ORC_TYPE_CALL, | 
|---|
|  | 150 | +		.type    = UNWIND_HINT_TYPE_CALL, | 
|---|
| 160 | 151 | }; | 
|---|
| 161 | 152 |  | 
|---|
|  | 153 | +	/* Build a deduplicated list of ORC entries: */ | 
|---|
|  | 154 | +	INIT_LIST_HEAD(&orc_list); | 
|---|
|  | 155 | +	for_each_sec(file, sec) { | 
|---|
|  | 156 | +		struct orc_entry orc, prev_orc = {0}; | 
|---|
|  | 157 | +		struct instruction *insn; | 
|---|
|  | 158 | +		bool empty = true; | 
|---|
|  | 159 | + | 
|---|
|  | 160 | +		if (!sec->text) | 
|---|
|  | 161 | +			continue; | 
|---|
|  | 162 | + | 
|---|
|  | 163 | +		sec_for_each_insn(file, sec, insn) { | 
|---|
|  | 164 | +			struct alt_group *alt_group = insn->alt_group; | 
|---|
|  | 165 | +			int i; | 
|---|
|  | 166 | + | 
|---|
|  | 167 | +			if (!alt_group) { | 
|---|
|  | 168 | +				if (init_orc_entry(&orc, insn->cfi, insn)) | 
|---|
|  | 169 | +					return -1; | 
|---|
|  | 170 | +				if (!memcmp(&prev_orc, &orc, sizeof(orc))) | 
|---|
|  | 171 | +					continue; | 
|---|
|  | 172 | +				if (orc_list_add(&orc_list, &orc, sec, | 
|---|
|  | 173 | +						 insn->offset)) | 
|---|
|  | 174 | +					return -1; | 
|---|
|  | 175 | +				nr++; | 
|---|
|  | 176 | +				prev_orc = orc; | 
|---|
|  | 177 | +				empty = false; | 
|---|
|  | 178 | +				continue; | 
|---|
|  | 179 | +			} | 
|---|
|  | 180 | + | 
|---|
|  | 181 | +			/* | 
|---|
|  | 182 | +			 * Alternatives can have different stack layout | 
|---|
|  | 183 | +			 * possibilities (but they shouldn't conflict). | 
|---|
|  | 184 | +			 * Instead of traversing the instructions, use the | 
|---|
|  | 185 | +			 * alt_group's flattened byte-offset-addressed CFI | 
|---|
|  | 186 | +			 * array. | 
|---|
|  | 187 | +			 */ | 
|---|
|  | 188 | +			for (i = 0; i < alt_group_len(alt_group); i++) { | 
|---|
|  | 189 | +				struct cfi_state *cfi = alt_group->cfi[i]; | 
|---|
|  | 190 | +				if (!cfi) | 
|---|
|  | 191 | +					continue; | 
|---|
|  | 192 | +				/* errors are reported on the original insn */ | 
|---|
|  | 193 | +				if (init_orc_entry(&orc, cfi, insn)) | 
|---|
|  | 194 | +					return -1; | 
|---|
|  | 195 | +				if (!memcmp(&prev_orc, &orc, sizeof(orc))) | 
|---|
|  | 196 | +					continue; | 
|---|
|  | 197 | +				if (orc_list_add(&orc_list, &orc, insn->sec, | 
|---|
|  | 198 | +						 insn->offset + i)) | 
|---|
|  | 199 | +					return -1; | 
|---|
|  | 200 | +				nr++; | 
|---|
|  | 201 | +				prev_orc = orc; | 
|---|
|  | 202 | +				empty = false; | 
|---|
|  | 203 | +			} | 
|---|
|  | 204 | + | 
|---|
|  | 205 | +			/* Skip to the end of the alt_group */ | 
|---|
|  | 206 | +			insn = alt_group->last_insn; | 
|---|
|  | 207 | +		} | 
|---|
|  | 208 | + | 
|---|
|  | 209 | +		/* Add a section terminator */ | 
|---|
|  | 210 | +		if (!empty) { | 
|---|
|  | 211 | +			orc_list_add(&orc_list, &null, sec, sec->len); | 
|---|
|  | 212 | +			nr++; | 
|---|
|  | 213 | +		} | 
|---|
|  | 214 | +	} | 
|---|
|  | 215 | +	if (!nr) | 
|---|
|  | 216 | +		return 0; | 
|---|
|  | 217 | + | 
|---|
|  | 218 | +	/* Create .orc_unwind, .orc_unwind_ip and .rela.orc_unwind_ip sections: */ | 
|---|
| 162 | 219 | sec = find_section_by_name(file->elf, ".orc_unwind"); | 
|---|
| 163 | 220 | if (sec) { | 
|---|
| 164 | 221 | WARN("file already has .orc_unwind section, skipping"); | 
|---|
| 165 | 222 | return -1; | 
|---|
| 166 | 223 | } | 
|---|
| 167 |  | - | 
|---|
| 168 |  | -	/* count the number of needed orcs */ | 
|---|
| 169 |  | -	idx = 0; | 
|---|
| 170 |  | -	for_each_sec(file, sec) { | 
|---|
| 171 |  | -		if (!sec->text) | 
|---|
| 172 |  | -			continue; | 
|---|
| 173 |  | - | 
|---|
| 174 |  | -		prev_insn = NULL; | 
|---|
| 175 |  | -		sec_for_each_insn(file, sec, insn) { | 
|---|
| 176 |  | -			if (!prev_insn || | 
|---|
| 177 |  | -			    memcmp(&insn->orc, &prev_insn->orc, | 
|---|
| 178 |  | -				   sizeof(struct orc_entry))) { | 
|---|
| 179 |  | -				idx++; | 
|---|
| 180 |  | -			} | 
|---|
| 181 |  | -			prev_insn = insn; | 
|---|
| 182 |  | -		} | 
|---|
| 183 |  | - | 
|---|
| 184 |  | -		/* section terminator */ | 
|---|
| 185 |  | -		if (prev_insn) | 
|---|
| 186 |  | -			idx++; | 
|---|
| 187 |  | -	} | 
|---|
| 188 |  | -	if (!idx) | 
|---|
|  | 224 | +	orc_sec = elf_create_section(file->elf, ".orc_unwind", 0, | 
|---|
|  | 225 | +				     sizeof(struct orc_entry), nr); | 
|---|
|  | 226 | +	if (!orc_sec) | 
|---|
| 189 | 227 | return -1; | 
|---|
| 190 | 228 |  | 
|---|
| 191 |  | - | 
|---|
| 192 |  | -	/* create .orc_unwind_ip and .rela.orc_unwind_ip sections */ | 
|---|
| 193 |  | -	sec = elf_create_section(file->elf, ".orc_unwind_ip", sizeof(int), idx); | 
|---|
|  | 229 | +	sec = elf_create_section(file->elf, ".orc_unwind_ip", 0, sizeof(int), nr); | 
|---|
| 194 | 230 | if (!sec) | 
|---|
| 195 | 231 | return -1; | 
|---|
| 196 | 232 |  | 
|---|
| 197 |  | -	ip_relasec = elf_create_rela_section(file->elf, sec); | 
|---|
| 198 |  | -	if (!ip_relasec) | 
|---|
| 199 |  | -		return -1; | 
|---|
| 200 |  | - | 
|---|
| 201 |  | -	/* create .orc_unwind section */ | 
|---|
| 202 |  | -	u_sec = elf_create_section(file->elf, ".orc_unwind", | 
|---|
| 203 |  | -				   sizeof(struct orc_entry), idx); | 
|---|
| 204 |  | - | 
|---|
| 205 |  | -	/* populate sections */ | 
|---|
| 206 |  | -	idx = 0; | 
|---|
| 207 |  | -	for_each_sec(file, sec) { | 
|---|
| 208 |  | -		if (!sec->text) | 
|---|
| 209 |  | -			continue; | 
|---|
| 210 |  | - | 
|---|
| 211 |  | -		prev_insn = NULL; | 
|---|
| 212 |  | -		sec_for_each_insn(file, sec, insn) { | 
|---|
| 213 |  | -			if (!prev_insn || memcmp(&insn->orc, &prev_insn->orc, | 
|---|
| 214 |  | -						 sizeof(struct orc_entry))) { | 
|---|
| 215 |  | - | 
|---|
| 216 |  | -				if (create_orc_entry(u_sec, ip_relasec, idx, | 
|---|
| 217 |  | -						     insn->sec, insn->offset, | 
|---|
| 218 |  | -						     &insn->orc)) | 
|---|
| 219 |  | -					return -1; | 
|---|
| 220 |  | - | 
|---|
| 221 |  | -				idx++; | 
|---|
| 222 |  | -			} | 
|---|
| 223 |  | -			prev_insn = insn; | 
|---|
| 224 |  | -		} | 
|---|
| 225 |  | - | 
|---|
| 226 |  | -		/* section terminator */ | 
|---|
| 227 |  | -		if (prev_insn) { | 
|---|
| 228 |  | -			if (create_orc_entry(u_sec, ip_relasec, idx, | 
|---|
| 229 |  | -					     prev_insn->sec, | 
|---|
| 230 |  | -					     prev_insn->offset + prev_insn->len, | 
|---|
| 231 |  | -					     &empty)) | 
|---|
| 232 |  | -				return -1; | 
|---|
| 233 |  | - | 
|---|
| 234 |  | -			idx++; | 
|---|
| 235 |  | -		} | 
|---|
|  | 233 | +	/* Write ORC entries to sections: */ | 
|---|
|  | 234 | +	list_for_each_entry(entry, &orc_list, list) { | 
|---|
|  | 235 | +		if (write_orc_entry(file->elf, orc_sec, sec, idx++, | 
|---|
|  | 236 | +				    entry->insn_sec, entry->insn_off, | 
|---|
|  | 237 | +				    &entry->orc)) | 
|---|
|  | 238 | +			return -1; | 
|---|
| 236 | 239 | } | 
|---|
| 237 |  | - | 
|---|
| 238 |  | -	if (elf_rebuild_rela_section(ip_relasec)) | 
|---|
| 239 |  | -		return -1; | 
|---|
| 240 | 240 |  | 
|---|
| 241 | 241 | return 0; | 
|---|
| 242 | 242 | } | 
|---|