brintos

brintos / linux-shallow public Read only

0
0
Text · 3.4 KiB · 922e6aa Raw
148 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com>4 */5 6#include <stdlib.h>7#include <string.h>8 9#include <linux/objtool_types.h>10#include <asm/orc_types.h>11 12#include <objtool/check.h>13#include <objtool/orc.h>14#include <objtool/warn.h>15#include <objtool/endianness.h>16 17struct orc_list_entry {18	struct list_head list;19	struct orc_entry orc;20	struct section *insn_sec;21	unsigned long insn_off;22};23 24static int orc_list_add(struct list_head *orc_list, struct orc_entry *orc,25			struct section *sec, unsigned long offset)26{27	struct orc_list_entry *entry = malloc(sizeof(*entry));28 29	if (!entry) {30		WARN("malloc failed");31		return -1;32	}33 34	entry->orc	= *orc;35	entry->insn_sec = sec;36	entry->insn_off = offset;37 38	list_add_tail(&entry->list, orc_list);39	return 0;40}41 42static unsigned long alt_group_len(struct alt_group *alt_group)43{44	return alt_group->last_insn->offset +45	       alt_group->last_insn->len -46	       alt_group->first_insn->offset;47}48 49int orc_create(struct objtool_file *file)50{51	struct section *sec, *orc_sec;52	unsigned int nr = 0, idx = 0;53	struct orc_list_entry *entry;54	struct list_head orc_list;55 56	struct orc_entry null = { .type = ORC_TYPE_UNDEFINED };57 58	/* Build a deduplicated list of ORC entries: */59	INIT_LIST_HEAD(&orc_list);60	for_each_sec(file, sec) {61		struct orc_entry orc, prev_orc = {0};62		struct instruction *insn;63		bool empty = true;64 65		if (!sec->text)66			continue;67 68		sec_for_each_insn(file, sec, insn) {69			struct alt_group *alt_group = insn->alt_group;70			int i;71 72			if (!alt_group) {73				if (init_orc_entry(&orc, insn->cfi, insn))74					return -1;75				if (!memcmp(&prev_orc, &orc, sizeof(orc)))76					continue;77				if (orc_list_add(&orc_list, &orc, sec,78						 insn->offset))79					return -1;80				nr++;81				prev_orc = orc;82				empty = false;83				continue;84			}85 86			/*87			 * Alternatives can have different stack layout88			 * possibilities (but they shouldn't conflict).89			 * Instead of traversing the instructions, use the90			 * alt_group's flattened byte-offset-addressed CFI91			 * array.92			 */93			for (i = 0; i < alt_group_len(alt_group); i++) {94				struct cfi_state *cfi = alt_group->cfi[i];95				if (!cfi)96					continue;97				/* errors are reported on the original insn */98				if (init_orc_entry(&orc, cfi, insn))99					return -1;100				if (!memcmp(&prev_orc, &orc, sizeof(orc)))101					continue;102				if (orc_list_add(&orc_list, &orc, insn->sec,103						 insn->offset + i))104					return -1;105				nr++;106				prev_orc = orc;107				empty = false;108			}109 110			/* Skip to the end of the alt_group */111			insn = alt_group->last_insn;112		}113 114		/* Add a section terminator */115		if (!empty) {116			orc_list_add(&orc_list, &null, sec, sec->sh.sh_size);117			nr++;118		}119	}120	if (!nr)121		return 0;122 123	/* Create .orc_unwind, .orc_unwind_ip and .rela.orc_unwind_ip sections: */124	sec = find_section_by_name(file->elf, ".orc_unwind");125	if (sec) {126		WARN("file already has .orc_unwind section, skipping");127		return -1;128	}129	orc_sec = elf_create_section(file->elf, ".orc_unwind",130				     sizeof(struct orc_entry), nr);131	if (!orc_sec)132		return -1;133 134	sec = elf_create_section_pair(file->elf, ".orc_unwind_ip", sizeof(int), nr, nr);135	if (!sec)136		return -1;137 138	/* Write ORC entries to sections: */139	list_for_each_entry(entry, &orc_list, list) {140		if (write_orc_entry(file->elf, orc_sec, sec, idx++,141				    entry->insn_sec, entry->insn_off,142				    &entry->orc))143			return -1;144	}145 146	return 0;147}148