File Index
Files and directories
Sign in
FILE

special.c

File preview with syntax highlighting.

linux-6.19.14/tools/objtool/arch/loongarch/special.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2#include <string.h>
  3#include <objtool/special.h>
  4#include <objtool/warn.h>
  5
  6bool arch_support_alt_relocation(struct special_alt *special_alt,
  7				 struct instruction *insn,
  8				 struct reloc *reloc)
  9{
 10	return false;
 11}
 12
 13struct table_info {
 14	struct list_head jump_info;
 15	unsigned long insn_offset;
 16	unsigned long rodata_offset;
 17};
 18
 19static void get_rodata_table_size_by_table_annotate(struct objtool_file *file,
 20						    struct instruction *insn,
 21						    unsigned long *table_size)
 22{
 23	struct section *rsec;
 24	struct reloc *reloc;
 25	struct list_head table_list;
 26	struct table_info *orig_table;
 27	struct table_info *next_table;
 28	unsigned long tmp_insn_offset;
 29	unsigned long tmp_rodata_offset;
 30	bool is_valid_list = false;
 31
 32	rsec = find_section_by_name(file->elf, ".rela.discard.tablejump_annotate");
 33	if (!rsec)
 34		return;
 35
 36	INIT_LIST_HEAD(&table_list);
 37
 38	for_each_reloc(rsec, reloc) {
 39		if (reloc->sym->sec->rodata)
 40			continue;
 41
 42		if (strcmp(insn->sec->name, reloc->sym->sec->name))
 43			continue;
 44
 45		orig_table = malloc(sizeof(struct table_info));
 46		if (!orig_table) {
 47			WARN("malloc failed");
 48			return;
 49		}
 50
 51		orig_table->insn_offset = reloc->sym->offset + reloc_addend(reloc);
 52		reloc++;
 53		orig_table->rodata_offset = reloc->sym->offset + reloc_addend(reloc);
 54
 55		list_add_tail(&orig_table->jump_info, &table_list);
 56
 57		if (reloc_idx(reloc) + 1 == sec_num_entries(rsec))
 58			break;
 59
 60		if (strcmp(insn->sec->name, (reloc + 1)->sym->sec->name)) {
 61			list_for_each_entry(orig_table, &table_list, jump_info) {
 62				if (orig_table->insn_offset == insn->offset) {
 63					is_valid_list = true;
 64					break;
 65				}
 66			}
 67
 68			if (!is_valid_list) {
 69				list_del_init(&table_list);
 70				continue;
 71			}
 72
 73			break;
 74		}
 75	}
 76
 77	list_for_each_entry(orig_table, &table_list, jump_info) {
 78		next_table = list_next_entry(orig_table, jump_info);
 79		list_for_each_entry_from(next_table, &table_list, jump_info) {
 80			if (next_table->rodata_offset < orig_table->rodata_offset) {
 81				tmp_insn_offset = next_table->insn_offset;
 82				tmp_rodata_offset = next_table->rodata_offset;
 83				next_table->insn_offset = orig_table->insn_offset;
 84				next_table->rodata_offset = orig_table->rodata_offset;
 85				orig_table->insn_offset = tmp_insn_offset;
 86				orig_table->rodata_offset = tmp_rodata_offset;
 87			}
 88		}
 89	}
 90
 91	list_for_each_entry(orig_table, &table_list, jump_info) {
 92		if (insn->offset == orig_table->insn_offset) {
 93			next_table = list_next_entry(orig_table, jump_info);
 94			if (&next_table->jump_info == &table_list) {
 95				*table_size = 0;
 96				return;
 97			}
 98
 99			while (next_table->rodata_offset == orig_table->rodata_offset) {
100				next_table = list_next_entry(next_table, jump_info);
101				if (&next_table->jump_info == &table_list) {
102					*table_size = 0;
103					return;
104				}
105			}
106
107			*table_size = next_table->rodata_offset - orig_table->rodata_offset;
108		}
109	}
110}
111
112static struct reloc *find_reloc_by_table_annotate(struct objtool_file *file,
113						  struct instruction *insn,
114						  unsigned long *table_size)
115{
116	struct section *rsec;
117	struct reloc *reloc;
118	unsigned long offset;
119
120	rsec = find_section_by_name(file->elf, ".rela.discard.tablejump_annotate");
121	if (!rsec)
122		return NULL;
123
124	for_each_reloc(rsec, reloc) {
125		if (reloc->sym->sec->rodata)
126			continue;
127
128		if (strcmp(insn->sec->name, reloc->sym->sec->name))
129			continue;
130
131		offset = reloc->sym->offset + reloc_addend(reloc);
132		if (insn->offset == offset) {
133			get_rodata_table_size_by_table_annotate(file, insn, table_size);
134			reloc++;
135			return reloc;
136		}
137	}
138
139	return NULL;
140}
141
142static struct reloc *find_reloc_of_rodata_c_jump_table(struct section *sec,
143						       unsigned long offset,
144						       unsigned long *table_size)
145{
146	struct section *rsec;
147	struct reloc *reloc;
148
149	rsec = sec->rsec;
150	if (!rsec)
151		return NULL;
152
153	for_each_reloc(rsec, reloc) {
154		if (reloc_offset(reloc) > offset)
155			break;
156
157		if (!strcmp(reloc->sym->sec->name, C_JUMP_TABLE_SECTION)) {
158			*table_size = 0;
159			return reloc;
160		}
161	}
162
163	return NULL;
164}
165
166struct reloc *arch_find_switch_table(struct objtool_file *file,
167				     struct instruction *insn,
168				     unsigned long *table_size)
169{
170	struct reloc *annotate_reloc;
171	struct reloc *rodata_reloc;
172	struct section *table_sec;
173	unsigned long table_offset;
174
175	annotate_reloc = find_reloc_by_table_annotate(file, insn, table_size);
176	if (!annotate_reloc) {
177		annotate_reloc = find_reloc_of_rodata_c_jump_table(
178				 insn->sec, insn->offset, table_size);
179		if (!annotate_reloc)
180			return NULL;
181	}
182
183	table_sec = annotate_reloc->sym->sec;
184	table_offset = annotate_reloc->sym->offset + reloc_addend(annotate_reloc);
185
186	/*
187	 * Each table entry has a rela associated with it.  The rela
188	 * should reference text in the same function as the original
189	 * instruction.
190	 */
191	rodata_reloc = find_reloc_by_dest(file->elf, table_sec, table_offset);
192	if (!rodata_reloc)
193		return NULL;
194
195	return rodata_reloc;
196}
197
198const char *arch_cpu_feature_name(int feature_number)
199{
200	return NULL;
201}
~/ Read-only file preview.