Blame view

tools/objtool/elf.c 21.5 KB
1ccea77e2   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
442f04c34   Josh Poimboeuf   objtool: Add tool...
2
3
4
5
6
7
  /*
   * elf.c - ELF access library
   *
   * Adapted from kpatch (https://github.com/dynup/kpatch):
   * Copyright (C) 2013-2015 Josh Poimboeuf <jpoimboe@redhat.com>
   * Copyright (C) 2014 Seth Jennings <sjenning@redhat.com>
442f04c34   Josh Poimboeuf   objtool: Add tool...
8
9
10
11
12
13
14
15
16
   */
  
  #include <sys/types.h>
  #include <sys/stat.h>
  #include <fcntl.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  #include <unistd.h>
385d11b15   Josh Poimboeuf   objtool: Improve ...
17
  #include <errno.h>
1e11f3fdc   Peter Zijlstra   objtool: Add a st...
18
  #include "builtin.h"
442f04c34   Josh Poimboeuf   objtool: Add tool...
19
20
21
  
  #include "elf.h"
  #include "warn.h"
22566c160   Artem Savkov   objtool: Fix segf...
22
  #define MAX_NAME_LEN 128
ae358196f   Peter Zijlstra   objtool: Optimize...
23
24
25
26
  static inline u32 str_hash(const char *str)
  {
  	return jhash(str, strlen(str), 0);
  }
34f7c96d9   Peter Zijlstra   objtool: Optimize...
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
  static inline int elf_hash_bits(void)
  {
  	return vmlinux ? ELF_HASH_BITS : 16;
  }
  
  #define elf_hash_add(hashtable, node, key) \
  	hlist_add_head(node, &hashtable[hash_min(key, elf_hash_bits())])
  
  static void elf_hash_init(struct hlist_head *table)
  {
  	__hash_init(table, 1U << elf_hash_bits());
  }
  
  #define elf_hash_for_each_possible(name, obj, member, key)			\
  	hlist_for_each_entry(obj, &name[hash_min(key, elf_hash_bits())], member)
2a362ecc3   Peter Zijlstra   objtool: Optimize...
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
  static void rb_add(struct rb_root *tree, struct rb_node *node,
  		   int (*cmp)(struct rb_node *, const struct rb_node *))
  {
  	struct rb_node **link = &tree->rb_node;
  	struct rb_node *parent = NULL;
  
  	while (*link) {
  		parent = *link;
  		if (cmp(node, parent) < 0)
  			link = &parent->rb_left;
  		else
  			link = &parent->rb_right;
  	}
  
  	rb_link_node(node, parent, link);
  	rb_insert_color(node, tree);
  }
b490f4536   Miroslav Benes   objtool: Move the...
59
  static struct rb_node *rb_find_first(const struct rb_root *tree, const void *key,
2a362ecc3   Peter Zijlstra   objtool: Optimize...
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
  			       int (*cmp)(const void *key, const struct rb_node *))
  {
  	struct rb_node *node = tree->rb_node;
  	struct rb_node *match = NULL;
  
  	while (node) {
  		int c = cmp(key, node);
  		if (c <= 0) {
  			if (!c)
  				match = node;
  			node = node->rb_left;
  		} else if (c > 0) {
  			node = node->rb_right;
  		}
  	}
  
  	return match;
  }
  
  static struct rb_node *rb_next_match(struct rb_node *node, const void *key,
  				    int (*cmp)(const void *key, const struct rb_node *))
  {
  	node = rb_next(node);
  	if (node && cmp(key, node))
  		node = NULL;
  	return node;
  }
  
  #define rb_for_each(tree, node, key, cmp) \
  	for ((node) = rb_find_first((tree), (key), (cmp)); \
  	     (node); (node) = rb_next_match((node), (key), (cmp)))
  
  static int symbol_to_offset(struct rb_node *a, const struct rb_node *b)
  {
  	struct symbol *sa = rb_entry(a, struct symbol, node);
  	struct symbol *sb = rb_entry(b, struct symbol, node);
  
  	if (sa->offset < sb->offset)
  		return -1;
  	if (sa->offset > sb->offset)
  		return 1;
  
  	if (sa->len < sb->len)
  		return -1;
  	if (sa->len > sb->len)
  		return 1;
  
  	sa->alias = sb;
  
  	return 0;
  }
  
  static int symbol_by_offset(const void *key, const struct rb_node *node)
  {
  	const struct symbol *s = rb_entry(node, struct symbol, node);
  	const unsigned long *o = key;
  
  	if (*o < s->offset)
  		return -1;
5377cae94   Julien Thierry   objtool: Fix off-...
119
  	if (*o >= s->offset + s->len)
2a362ecc3   Peter Zijlstra   objtool: Optimize...
120
121
122
123
  		return 1;
  
  	return 0;
  }
894e48cad   Ingo Molnar   objtool: Constify...
124
  struct section *find_section_by_name(const struct elf *elf, const char *name)
442f04c34   Josh Poimboeuf   objtool: Add tool...
125
126
  {
  	struct section *sec;
34f7c96d9   Peter Zijlstra   objtool: Optimize...
127
  	elf_hash_for_each_possible(elf->section_name_hash, sec, name_hash, str_hash(name))
442f04c34   Josh Poimboeuf   objtool: Add tool...
128
129
130
131
132
133
134
135
136
137
  		if (!strcmp(sec->name, name))
  			return sec;
  
  	return NULL;
  }
  
  static struct section *find_section_by_index(struct elf *elf,
  					     unsigned int idx)
  {
  	struct section *sec;
34f7c96d9   Peter Zijlstra   objtool: Optimize...
138
  	elf_hash_for_each_possible(elf->section_hash, sec, hash, idx)
442f04c34   Josh Poimboeuf   objtool: Add tool...
139
140
141
142
143
144
145
146
  		if (sec->idx == idx)
  			return sec;
  
  	return NULL;
  }
  
  static struct symbol *find_symbol_by_index(struct elf *elf, unsigned int idx)
  {
442f04c34   Josh Poimboeuf   objtool: Add tool...
147
  	struct symbol *sym;
34f7c96d9   Peter Zijlstra   objtool: Optimize...
148
  	elf_hash_for_each_possible(elf->symbol_hash, sym, hash, idx)
65fb11a7f   Peter Zijlstra   objtool: Optimize...
149
150
  		if (sym->idx == idx)
  			return sym;
442f04c34   Josh Poimboeuf   objtool: Add tool...
151
152
153
154
155
156
  
  	return NULL;
  }
  
  struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset)
  {
2a362ecc3   Peter Zijlstra   objtool: Optimize...
157
  	struct rb_node *node;
442f04c34   Josh Poimboeuf   objtool: Add tool...
158

2a362ecc3   Peter Zijlstra   objtool: Optimize...
159
160
161
162
163
164
  	rb_for_each(&sec->symbol_tree, node, &offset, symbol_by_offset) {
  		struct symbol *s = rb_entry(node, struct symbol, node);
  
  		if (s->offset == offset && s->type != STT_SECTION)
  			return s;
  	}
7acfe5315   Josh Poimboeuf   objtool: Improve ...
165
166
167
168
169
170
  
  	return NULL;
  }
  
  struct symbol *find_func_by_offset(struct section *sec, unsigned long offset)
  {
2a362ecc3   Peter Zijlstra   objtool: Optimize...
171
  	struct rb_node *node;
7acfe5315   Josh Poimboeuf   objtool: Improve ...
172

2a362ecc3   Peter Zijlstra   objtool: Optimize...
173
174
175
176
177
178
  	rb_for_each(&sec->symbol_tree, node, &offset, symbol_by_offset) {
  		struct symbol *s = rb_entry(node, struct symbol, node);
  
  		if (s->offset == offset && s->type == STT_FUNC)
  			return s;
  	}
442f04c34   Josh Poimboeuf   objtool: Add tool...
179
180
181
  
  	return NULL;
  }
b490f4536   Miroslav Benes   objtool: Move the...
182
  struct symbol *find_symbol_containing(const struct section *sec, unsigned long offset)
13810435b   Josh Poimboeuf   objtool: Support ...
183
  {
2a362ecc3   Peter Zijlstra   objtool: Optimize...
184
  	struct rb_node *node;
13810435b   Josh Poimboeuf   objtool: Support ...
185

2a362ecc3   Peter Zijlstra   objtool: Optimize...
186
187
188
189
190
191
  	rb_for_each(&sec->symbol_tree, node, &offset, symbol_by_offset) {
  		struct symbol *s = rb_entry(node, struct symbol, node);
  
  		if (s->type != STT_SECTION)
  			return s;
  	}
13810435b   Josh Poimboeuf   objtool: Support ...
192
193
194
  
  	return NULL;
  }
53d20720b   Peter Zijlstra   objtool: Rename f...
195
  struct symbol *find_func_containing(struct section *sec, unsigned long offset)
2a362ecc3   Peter Zijlstra   objtool: Optimize...
196
197
198
199
200
201
202
203
204
205
206
207
  {
  	struct rb_node *node;
  
  	rb_for_each(&sec->symbol_tree, node, &offset, symbol_by_offset) {
  		struct symbol *s = rb_entry(node, struct symbol, node);
  
  		if (s->type == STT_FUNC)
  			return s;
  	}
  
  	return NULL;
  }
894e48cad   Ingo Molnar   objtool: Constify...
208
  struct symbol *find_symbol_by_name(const struct elf *elf, const char *name)
5c51f4ae8   Josh Poimboeuf   objtool: Fix anot...
209
210
  {
  	struct symbol *sym;
34f7c96d9   Peter Zijlstra   objtool: Optimize...
211
  	elf_hash_for_each_possible(elf->symbol_name_hash, sym, name_hash, str_hash(name))
cdb3d057a   Peter Zijlstra   objtool: Optimize...
212
213
  		if (!strcmp(sym->name, name))
  			return sym;
5c51f4ae8   Josh Poimboeuf   objtool: Fix anot...
214
215
216
  
  	return NULL;
  }
f19742226   Matt Helsley   objtool: Rename r...
217
  struct reloc *find_reloc_by_dest_range(const struct elf *elf, struct section *sec,
8b5fa6bc3   Peter Zijlstra   objtool: Optimize...
218
  				     unsigned long offset, unsigned int len)
442f04c34   Josh Poimboeuf   objtool: Add tool...
219
  {
f19742226   Matt Helsley   objtool: Rename r...
220
  	struct reloc *reloc, *r = NULL;
042ba73fe   Josh Poimboeuf   objtool: Add seve...
221
  	unsigned long o;
442f04c34   Josh Poimboeuf   objtool: Add tool...
222

f19742226   Matt Helsley   objtool: Rename r...
223
  	if (!sec->reloc)
442f04c34   Josh Poimboeuf   objtool: Add tool...
224
  		return NULL;
f19742226   Matt Helsley   objtool: Rename r...
225
  	sec = sec->reloc;
8b5fa6bc3   Peter Zijlstra   objtool: Optimize...
226

74b873e49   Peter Zijlstra   objtool: Optimize...
227
  	for_offset_range(o, offset, offset + len) {
f19742226   Matt Helsley   objtool: Rename r...
228
  		elf_hash_for_each_possible(elf->reloc_hash, reloc, hash,
8b5fa6bc3   Peter Zijlstra   objtool: Optimize...
229
  				       sec_offset_hash(sec, o)) {
f19742226   Matt Helsley   objtool: Rename r...
230
  			if (reloc->sec != sec)
74b873e49   Peter Zijlstra   objtool: Optimize...
231
  				continue;
f19742226   Matt Helsley   objtool: Rename r...
232
233
234
  			if (reloc->offset >= offset && reloc->offset < offset + len) {
  				if (!r || reloc->offset < r->offset)
  					r = reloc;
74b873e49   Peter Zijlstra   objtool: Optimize...
235
  			}
8b5fa6bc3   Peter Zijlstra   objtool: Optimize...
236
  		}
74b873e49   Peter Zijlstra   objtool: Optimize...
237
238
  		if (r)
  			return r;
8b5fa6bc3   Peter Zijlstra   objtool: Optimize...
239
  	}
442f04c34   Josh Poimboeuf   objtool: Add tool...
240
241
242
  
  	return NULL;
  }
f19742226   Matt Helsley   objtool: Rename r...
243
  struct reloc *find_reloc_by_dest(const struct elf *elf, struct section *sec, unsigned long offset)
442f04c34   Josh Poimboeuf   objtool: Add tool...
244
  {
f19742226   Matt Helsley   objtool: Rename r...
245
  	return find_reloc_by_dest_range(elf, sec, offset, 1);
442f04c34   Josh Poimboeuf   objtool: Add tool...
246
  }
442f04c34   Josh Poimboeuf   objtool: Add tool...
247
248
249
250
251
252
253
254
  static int read_sections(struct elf *elf)
  {
  	Elf_Scn *s = NULL;
  	struct section *sec;
  	size_t shstrndx, sections_nr;
  	int i;
  
  	if (elf_getshdrnum(elf->elf, &sections_nr)) {
baa41469a   Josh Poimboeuf   objtool: Implemen...
255
  		WARN_ELF("elf_getshdrnum");
442f04c34   Josh Poimboeuf   objtool: Add tool...
256
257
258
259
  		return -1;
  	}
  
  	if (elf_getshdrstrndx(elf->elf, &shstrndx)) {
baa41469a   Josh Poimboeuf   objtool: Implemen...
260
  		WARN_ELF("elf_getshdrstrndx");
442f04c34   Josh Poimboeuf   objtool: Add tool...
261
262
263
264
265
266
267
268
269
270
  		return -1;
  	}
  
  	for (i = 0; i < sections_nr; i++) {
  		sec = malloc(sizeof(*sec));
  		if (!sec) {
  			perror("malloc");
  			return -1;
  		}
  		memset(sec, 0, sizeof(*sec));
a196e1719   Josh Poimboeuf   objtool: Rename s...
271
  		INIT_LIST_HEAD(&sec->symbol_list);
f19742226   Matt Helsley   objtool: Rename r...
272
  		INIT_LIST_HEAD(&sec->reloc_list);
442f04c34   Josh Poimboeuf   objtool: Add tool...
273

442f04c34   Josh Poimboeuf   objtool: Add tool...
274
275
  		s = elf_getscn(elf->elf, i);
  		if (!s) {
baa41469a   Josh Poimboeuf   objtool: Implemen...
276
  			WARN_ELF("elf_getscn");
442f04c34   Josh Poimboeuf   objtool: Add tool...
277
278
279
280
281
282
  			return -1;
  		}
  
  		sec->idx = elf_ndxscn(s);
  
  		if (!gelf_getshdr(s, &sec->sh)) {
baa41469a   Josh Poimboeuf   objtool: Implemen...
283
  			WARN_ELF("gelf_getshdr");
442f04c34   Josh Poimboeuf   objtool: Add tool...
284
285
286
287
288
  			return -1;
  		}
  
  		sec->name = elf_strptr(elf->elf, shstrndx, sec->sh.sh_name);
  		if (!sec->name) {
baa41469a   Josh Poimboeuf   objtool: Implemen...
289
  			WARN_ELF("elf_strptr");
442f04c34   Josh Poimboeuf   objtool: Add tool...
290
291
  			return -1;
  		}
df968c932   Petr Vandrovec   objtool: Do not r...
292
293
294
295
296
297
298
299
300
301
302
303
  		if (sec->sh.sh_size != 0) {
  			sec->data = elf_getdata(s, NULL);
  			if (!sec->data) {
  				WARN_ELF("elf_getdata");
  				return -1;
  			}
  			if (sec->data->d_off != 0 ||
  			    sec->data->d_size != sec->sh.sh_size) {
  				WARN("unexpected data attributes for %s",
  				     sec->name);
  				return -1;
  			}
442f04c34   Josh Poimboeuf   objtool: Add tool...
304
  		}
df968c932   Petr Vandrovec   objtool: Do not r...
305
  		sec->len = sec->sh.sh_size;
530389968   Peter Zijlstra   objtool: Optimize...
306
307
  
  		list_add_tail(&sec->list, &elf->sections);
34f7c96d9   Peter Zijlstra   objtool: Optimize...
308
309
  		elf_hash_add(elf->section_hash, &sec->hash, sec->idx);
  		elf_hash_add(elf->section_name_hash, &sec->name_hash, str_hash(sec->name));
442f04c34   Josh Poimboeuf   objtool: Add tool...
310
  	}
1e11f3fdc   Peter Zijlstra   objtool: Add a st...
311
312
313
  	if (stats)
  		printf("nr_sections: %lu
  ", (unsigned long)sections_nr);
442f04c34   Josh Poimboeuf   objtool: Add tool...
314
315
316
317
318
319
320
321
322
323
324
  	/* sanity check, one more call to elf_nextscn() should return NULL */
  	if (elf_nextscn(elf->elf, s)) {
  		WARN("section entry mismatch");
  		return -1;
  	}
  
  	return 0;
  }
  
  static int read_symbols(struct elf *elf)
  {
28fe1d7bf   Sami Tolvanen   objtool: use gelf...
325
  	struct section *symtab, *symtab_shndx, *sec;
2a362ecc3   Peter Zijlstra   objtool: Optimize...
326
327
328
  	struct symbol *sym, *pfunc;
  	struct list_head *entry;
  	struct rb_node *pnode;
442f04c34   Josh Poimboeuf   objtool: Add tool...
329
  	int symbols_nr, i;
13810435b   Josh Poimboeuf   objtool: Support ...
330
  	char *coldstr;
28fe1d7bf   Sami Tolvanen   objtool: use gelf...
331
332
  	Elf_Data *shndx_data = NULL;
  	Elf32_Word shndx;
442f04c34   Josh Poimboeuf   objtool: Add tool...
333
334
335
336
337
338
  
  	symtab = find_section_by_name(elf, ".symtab");
  	if (!symtab) {
  		WARN("missing symbol table");
  		return -1;
  	}
28fe1d7bf   Sami Tolvanen   objtool: use gelf...
339
340
341
  	symtab_shndx = find_section_by_name(elf, ".symtab_shndx");
  	if (symtab_shndx)
  		shndx_data = symtab_shndx->data;
442f04c34   Josh Poimboeuf   objtool: Add tool...
342
343
344
345
346
347
348
349
350
  	symbols_nr = symtab->sh.sh_size / symtab->sh.sh_entsize;
  
  	for (i = 0; i < symbols_nr; i++) {
  		sym = malloc(sizeof(*sym));
  		if (!sym) {
  			perror("malloc");
  			return -1;
  		}
  		memset(sym, 0, sizeof(*sym));
2a362ecc3   Peter Zijlstra   objtool: Optimize...
351
  		sym->alias = sym;
442f04c34   Josh Poimboeuf   objtool: Add tool...
352
353
  
  		sym->idx = i;
28fe1d7bf   Sami Tolvanen   objtool: use gelf...
354
355
356
  		if (!gelf_getsymshndx(symtab->data, shndx_data, i, &sym->sym,
  				      &shndx)) {
  			WARN_ELF("gelf_getsymshndx");
442f04c34   Josh Poimboeuf   objtool: Add tool...
357
358
359
360
361
362
  			goto err;
  		}
  
  		sym->name = elf_strptr(elf->elf, symtab->sh.sh_link,
  				       sym->sym.st_name);
  		if (!sym->name) {
baa41469a   Josh Poimboeuf   objtool: Implemen...
363
  			WARN_ELF("elf_strptr");
442f04c34   Josh Poimboeuf   objtool: Add tool...
364
365
366
367
368
  			goto err;
  		}
  
  		sym->type = GELF_ST_TYPE(sym->sym.st_info);
  		sym->bind = GELF_ST_BIND(sym->sym.st_info);
28fe1d7bf   Sami Tolvanen   objtool: use gelf...
369
370
371
372
373
374
375
  		if ((sym->sym.st_shndx > SHN_UNDEF &&
  		     sym->sym.st_shndx < SHN_LORESERVE) ||
  		    (shndx_data && sym->sym.st_shndx == SHN_XINDEX)) {
  			if (sym->sym.st_shndx != SHN_XINDEX)
  				shndx = sym->sym.st_shndx;
  
  			sym->sec = find_section_by_index(elf, shndx);
442f04c34   Josh Poimboeuf   objtool: Add tool...
376
377
378
379
380
381
382
383
384
385
386
387
388
389
  			if (!sym->sec) {
  				WARN("couldn't find section for symbol %s",
  				     sym->name);
  				goto err;
  			}
  			if (sym->type == STT_SECTION) {
  				sym->name = sym->sec->name;
  				sym->sec->sym = sym;
  			}
  		} else
  			sym->sec = find_section_by_index(elf, 0);
  
  		sym->offset = sym->sym.st_value;
  		sym->len = sym->sym.st_size;
2a362ecc3   Peter Zijlstra   objtool: Optimize...
390
391
392
393
394
395
  		rb_add(&sym->sec->symbol_tree, &sym->node, symbol_to_offset);
  		pnode = rb_prev(&sym->node);
  		if (pnode)
  			entry = &rb_entry(pnode, struct symbol, node)->list;
  		else
  			entry = &sym->sec->symbol_list;
442f04c34   Josh Poimboeuf   objtool: Add tool...
396
  		list_add(&sym->list, entry);
34f7c96d9   Peter Zijlstra   objtool: Optimize...
397
398
  		elf_hash_add(elf->symbol_hash, &sym->hash, sym->idx);
  		elf_hash_add(elf->symbol_name_hash, &sym->name_hash, str_hash(sym->name));
442f04c34   Josh Poimboeuf   objtool: Add tool...
399
  	}
1e11f3fdc   Peter Zijlstra   objtool: Add a st...
400
401
402
  	if (stats)
  		printf("nr_symbols: %lu
  ", (unsigned long)symbols_nr);
13810435b   Josh Poimboeuf   objtool: Support ...
403
404
405
  	/* Create parent/child links for any cold subfunctions */
  	list_for_each_entry(sec, &elf->sections, list) {
  		list_for_each_entry(sym, &sec->symbol_list, list) {
22566c160   Artem Savkov   objtool: Fix segf...
406
407
  			char pname[MAX_NAME_LEN + 1];
  			size_t pnamelen;
13810435b   Josh Poimboeuf   objtool: Support ...
408
409
  			if (sym->type != STT_FUNC)
  				continue;
e000acc14   Kristen Carlson Accardi   objtool: Do not a...
410
411
412
413
414
415
  
  			if (sym->pfunc == NULL)
  				sym->pfunc = sym;
  
  			if (sym->cfunc == NULL)
  				sym->cfunc = sym;
bcb6fb5da   Josh Poimboeuf   objtool: Support ...
416
  			coldstr = strstr(sym->name, ".cold");
08b393d01   Josh Poimboeuf   objtool: Support ...
417
418
  			if (!coldstr)
  				continue;
22566c160   Artem Savkov   objtool: Fix segf...
419
420
421
422
423
424
425
426
427
428
  			pnamelen = coldstr - sym->name;
  			if (pnamelen > MAX_NAME_LEN) {
  				WARN("%s(): parent function name exceeds maximum length of %d characters",
  				     sym->name, MAX_NAME_LEN);
  				return -1;
  			}
  
  			strncpy(pname, sym->name, pnamelen);
  			pname[pnamelen] = '\0';
  			pfunc = find_symbol_by_name(elf, pname);
08b393d01   Josh Poimboeuf   objtool: Support ...
429
430
431
432
  
  			if (!pfunc) {
  				WARN("%s(): can't find parent function",
  				     sym->name);
0b9301fb6   Artem Savkov   objtool: Fix doub...
433
  				return -1;
08b393d01   Josh Poimboeuf   objtool: Support ...
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
  			}
  
  			sym->pfunc = pfunc;
  			pfunc->cfunc = sym;
  
  			/*
  			 * Unfortunately, -fnoreorder-functions puts the child
  			 * inside the parent.  Remove the overlap so we can
  			 * have sane assumptions.
  			 *
  			 * Note that pfunc->len now no longer matches
  			 * pfunc->sym.st_size.
  			 */
  			if (sym->sec == pfunc->sec &&
  			    sym->offset >= pfunc->offset &&
  			    sym->offset + sym->len == pfunc->offset + pfunc->len) {
  				pfunc->len -= sym->len;
13810435b   Josh Poimboeuf   objtool: Support ...
451
452
453
  			}
  		}
  	}
442f04c34   Josh Poimboeuf   objtool: Add tool...
454
455
456
457
458
459
  	return 0;
  
  err:
  	free(sym);
  	return -1;
  }
f19742226   Matt Helsley   objtool: Rename r...
460
  void elf_add_reloc(struct elf *elf, struct reloc *reloc)
34f7c96d9   Peter Zijlstra   objtool: Optimize...
461
  {
f19742226   Matt Helsley   objtool: Rename r...
462
  	struct section *sec = reloc->sec;
34f7c96d9   Peter Zijlstra   objtool: Optimize...
463

f19742226   Matt Helsley   objtool: Rename r...
464
465
  	list_add_tail(&reloc->list, &sec->reloc_list);
  	elf_hash_add(elf->reloc_hash, &reloc->hash, reloc_hash(reloc));
34f7c96d9   Peter Zijlstra   objtool: Optimize...
466
  }
fb414783b   Matt Helsley   objtool: Add supp...
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
  static int read_rel_reloc(struct section *sec, int i, struct reloc *reloc, unsigned int *symndx)
  {
  	if (!gelf_getrel(sec->data, i, &reloc->rel)) {
  		WARN_ELF("gelf_getrel");
  		return -1;
  	}
  	reloc->type = GELF_R_TYPE(reloc->rel.r_info);
  	reloc->addend = 0;
  	reloc->offset = reloc->rel.r_offset;
  	*symndx = GELF_R_SYM(reloc->rel.r_info);
  	return 0;
  }
  
  static int read_rela_reloc(struct section *sec, int i, struct reloc *reloc, unsigned int *symndx)
  {
  	if (!gelf_getrela(sec->data, i, &reloc->rela)) {
  		WARN_ELF("gelf_getrela");
  		return -1;
  	}
  	reloc->type = GELF_R_TYPE(reloc->rela.r_info);
  	reloc->addend = reloc->rela.r_addend;
  	reloc->offset = reloc->rela.r_offset;
  	*symndx = GELF_R_SYM(reloc->rela.r_info);
  	return 0;
  }
f19742226   Matt Helsley   objtool: Rename r...
492
  static int read_relocs(struct elf *elf)
442f04c34   Josh Poimboeuf   objtool: Add tool...
493
494
  {
  	struct section *sec;
f19742226   Matt Helsley   objtool: Rename r...
495
  	struct reloc *reloc;
442f04c34   Josh Poimboeuf   objtool: Add tool...
496
497
  	int i;
  	unsigned int symndx;
f19742226   Matt Helsley   objtool: Rename r...
498
  	unsigned long nr_reloc, max_reloc = 0, tot_reloc = 0;
442f04c34   Josh Poimboeuf   objtool: Add tool...
499
500
  
  	list_for_each_entry(sec, &elf->sections, list) {
fb414783b   Matt Helsley   objtool: Add supp...
501
502
  		if ((sec->sh.sh_type != SHT_RELA) &&
  		    (sec->sh.sh_type != SHT_REL))
442f04c34   Josh Poimboeuf   objtool: Add tool...
503
  			continue;
1e968bf5c   Sami Tolvanen   objtool: Use sh_i...
504
  		sec->base = find_section_by_index(elf, sec->sh.sh_info);
442f04c34   Josh Poimboeuf   objtool: Add tool...
505
  		if (!sec->base) {
f19742226   Matt Helsley   objtool: Rename r...
506
  			WARN("can't find base section for reloc section %s",
442f04c34   Josh Poimboeuf   objtool: Add tool...
507
508
509
  			     sec->name);
  			return -1;
  		}
f19742226   Matt Helsley   objtool: Rename r...
510
  		sec->base->reloc = sec;
442f04c34   Josh Poimboeuf   objtool: Add tool...
511

f19742226   Matt Helsley   objtool: Rename r...
512
  		nr_reloc = 0;
442f04c34   Josh Poimboeuf   objtool: Add tool...
513
  		for (i = 0; i < sec->sh.sh_size / sec->sh.sh_entsize; i++) {
f19742226   Matt Helsley   objtool: Rename r...
514
515
  			reloc = malloc(sizeof(*reloc));
  			if (!reloc) {
442f04c34   Josh Poimboeuf   objtool: Add tool...
516
517
518
  				perror("malloc");
  				return -1;
  			}
f19742226   Matt Helsley   objtool: Rename r...
519
  			memset(reloc, 0, sizeof(*reloc));
fb414783b   Matt Helsley   objtool: Add supp...
520
521
522
523
524
525
526
527
528
529
  			switch (sec->sh.sh_type) {
  			case SHT_REL:
  				if (read_rel_reloc(sec, i, reloc, &symndx))
  					return -1;
  				break;
  			case SHT_RELA:
  				if (read_rela_reloc(sec, i, reloc, &symndx))
  					return -1;
  				break;
  			default: return -1;
442f04c34   Josh Poimboeuf   objtool: Add tool...
530
  			}
f19742226   Matt Helsley   objtool: Rename r...
531
  			reloc->sec = sec;
d832c0051   Peter Zijlstra   Merge branch 'obj...
532
533
  			reloc->idx = i;
  			reloc->sym = find_symbol_by_index(elf, symndx);
f19742226   Matt Helsley   objtool: Rename r...
534
535
  			if (!reloc->sym) {
  				WARN("can't find reloc entry symbol %d for %s",
442f04c34   Josh Poimboeuf   objtool: Add tool...
536
537
538
  				     symndx, sec->name);
  				return -1;
  			}
042ba73fe   Josh Poimboeuf   objtool: Add seve...
539

f19742226   Matt Helsley   objtool: Rename r...
540
541
  			elf_add_reloc(elf, reloc);
  			nr_reloc++;
442f04c34   Josh Poimboeuf   objtool: Add tool...
542
  		}
f19742226   Matt Helsley   objtool: Rename r...
543
544
  		max_reloc = max(max_reloc, nr_reloc);
  		tot_reloc += nr_reloc;
1e11f3fdc   Peter Zijlstra   objtool: Add a st...
545
546
547
  	}
  
  	if (stats) {
f19742226   Matt Helsley   objtool: Rename r...
548
549
550
551
  		printf("max_reloc: %lu
  ", max_reloc);
  		printf("tot_reloc: %lu
  ", tot_reloc);
442f04c34   Josh Poimboeuf   objtool: Add tool...
552
553
554
555
  	}
  
  	return 0;
  }
bc359ff2f   Ingo Molnar   objtool: Rename e...
556
  struct elf *elf_open_read(const char *name, int flags)
442f04c34   Josh Poimboeuf   objtool: Add tool...
557
558
  {
  	struct elf *elf;
627fce148   Josh Poimboeuf   objtool: Add ORC ...
559
  	Elf_Cmd cmd;
442f04c34   Josh Poimboeuf   objtool: Add tool...
560
561
562
563
564
565
566
567
  
  	elf_version(EV_CURRENT);
  
  	elf = malloc(sizeof(*elf));
  	if (!elf) {
  		perror("malloc");
  		return NULL;
  	}
34f7c96d9   Peter Zijlstra   objtool: Optimize...
568
  	memset(elf, 0, offsetof(struct elf, sections));
442f04c34   Josh Poimboeuf   objtool: Add tool...
569
570
  
  	INIT_LIST_HEAD(&elf->sections);
34f7c96d9   Peter Zijlstra   objtool: Optimize...
571
572
573
574
  	elf_hash_init(elf->symbol_hash);
  	elf_hash_init(elf->symbol_name_hash);
  	elf_hash_init(elf->section_hash);
  	elf_hash_init(elf->section_name_hash);
f19742226   Matt Helsley   objtool: Rename r...
575
  	elf_hash_init(elf->reloc_hash);
34f7c96d9   Peter Zijlstra   objtool: Optimize...
576

627fce148   Josh Poimboeuf   objtool: Add ORC ...
577
  	elf->fd = open(name, flags);
442f04c34   Josh Poimboeuf   objtool: Add tool...
578
  	if (elf->fd == -1) {
385d11b15   Josh Poimboeuf   objtool: Improve ...
579
580
581
  		fprintf(stderr, "objtool: Can't open '%s': %s
  ",
  			name, strerror(errno));
442f04c34   Josh Poimboeuf   objtool: Add tool...
582
583
  		goto err;
  	}
627fce148   Josh Poimboeuf   objtool: Add ORC ...
584
585
586
587
588
589
590
591
  	if ((flags & O_ACCMODE) == O_RDONLY)
  		cmd = ELF_C_READ_MMAP;
  	else if ((flags & O_ACCMODE) == O_RDWR)
  		cmd = ELF_C_RDWR;
  	else /* O_WRONLY */
  		cmd = ELF_C_WRITE;
  
  	elf->elf = elf_begin(elf->fd, cmd, NULL);
442f04c34   Josh Poimboeuf   objtool: Add tool...
592
  	if (!elf->elf) {
baa41469a   Josh Poimboeuf   objtool: Implemen...
593
  		WARN_ELF("elf_begin");
442f04c34   Josh Poimboeuf   objtool: Add tool...
594
595
596
597
  		goto err;
  	}
  
  	if (!gelf_getehdr(elf->elf, &elf->ehdr)) {
baa41469a   Josh Poimboeuf   objtool: Implemen...
598
  		WARN_ELF("gelf_getehdr");
442f04c34   Josh Poimboeuf   objtool: Add tool...
599
600
601
602
603
604
605
606
  		goto err;
  	}
  
  	if (read_sections(elf))
  		goto err;
  
  	if (read_symbols(elf))
  		goto err;
f19742226   Matt Helsley   objtool: Rename r...
607
  	if (read_relocs(elf))
442f04c34   Josh Poimboeuf   objtool: Add tool...
608
609
610
611
612
613
614
615
  		goto err;
  
  	return elf;
  
  err:
  	elf_close(elf);
  	return NULL;
  }
627fce148   Josh Poimboeuf   objtool: Add ORC ...
616
  struct section *elf_create_section(struct elf *elf, const char *name,
1e7e47883   Josh Poimboeuf   x86/static_call: ...
617
  				   unsigned int sh_flags, size_t entsize, int nr)
627fce148   Josh Poimboeuf   objtool: Add ORC ...
618
619
620
  {
  	struct section *sec, *shstrtab;
  	size_t size = entsize * nr;
3c3ea5031   Michael Forney   objtool: Use Elf_...
621
  	Elf_Scn *s;
627fce148   Josh Poimboeuf   objtool: Add ORC ...
622
623
624
625
626
627
628
629
630
631
  	Elf_Data *data;
  
  	sec = malloc(sizeof(*sec));
  	if (!sec) {
  		perror("malloc");
  		return NULL;
  	}
  	memset(sec, 0, sizeof(*sec));
  
  	INIT_LIST_HEAD(&sec->symbol_list);
f19742226   Matt Helsley   objtool: Rename r...
632
  	INIT_LIST_HEAD(&sec->reloc_list);
627fce148   Josh Poimboeuf   objtool: Add ORC ...
633

627fce148   Josh Poimboeuf   objtool: Add ORC ...
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
  	s = elf_newscn(elf->elf);
  	if (!s) {
  		WARN_ELF("elf_newscn");
  		return NULL;
  	}
  
  	sec->name = strdup(name);
  	if (!sec->name) {
  		perror("strdup");
  		return NULL;
  	}
  
  	sec->idx = elf_ndxscn(s);
  	sec->len = size;
  	sec->changed = true;
  
  	sec->data = elf_newdata(s);
  	if (!sec->data) {
  		WARN_ELF("elf_newdata");
  		return NULL;
  	}
  
  	sec->data->d_size = size;
  	sec->data->d_align = 1;
  
  	if (size) {
  		sec->data->d_buf = malloc(size);
  		if (!sec->data->d_buf) {
  			perror("malloc");
  			return NULL;
  		}
  		memset(sec->data->d_buf, 0, size);
  	}
  
  	if (!gelf_getshdr(s, &sec->sh)) {
  		WARN_ELF("gelf_getshdr");
  		return NULL;
  	}
  
  	sec->sh.sh_size = size;
  	sec->sh.sh_entsize = entsize;
  	sec->sh.sh_type = SHT_PROGBITS;
  	sec->sh.sh_addralign = 1;
1e7e47883   Josh Poimboeuf   x86/static_call: ...
677
  	sec->sh.sh_flags = SHF_ALLOC | sh_flags;
627fce148   Josh Poimboeuf   objtool: Add ORC ...
678

6d77d3b43   Simon Ser   objtool: Use '.st...
679
  	/* Add section name to .shstrtab (or .strtab for Clang) */
627fce148   Josh Poimboeuf   objtool: Add ORC ...
680
  	shstrtab = find_section_by_name(elf, ".shstrtab");
6d77d3b43   Simon Ser   objtool: Use '.st...
681
682
  	if (!shstrtab)
  		shstrtab = find_section_by_name(elf, ".strtab");
627fce148   Josh Poimboeuf   objtool: Add ORC ...
683
  	if (!shstrtab) {
6d77d3b43   Simon Ser   objtool: Use '.st...
684
  		WARN("can't find .shstrtab or .strtab section");
627fce148   Josh Poimboeuf   objtool: Add ORC ...
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
  		return NULL;
  	}
  
  	s = elf_getscn(elf->elf, shstrtab->idx);
  	if (!s) {
  		WARN_ELF("elf_getscn");
  		return NULL;
  	}
  
  	data = elf_newdata(s);
  	if (!data) {
  		WARN_ELF("elf_newdata");
  		return NULL;
  	}
  
  	data->d_buf = sec->name;
  	data->d_size = strlen(name) + 1;
  	data->d_align = 1;
  
  	sec->sh.sh_name = shstrtab->len;
  
  	shstrtab->len += strlen(name) + 1;
  	shstrtab->changed = true;
530389968   Peter Zijlstra   objtool: Optimize...
708
  	list_add_tail(&sec->list, &elf->sections);
34f7c96d9   Peter Zijlstra   objtool: Optimize...
709
710
  	elf_hash_add(elf->section_hash, &sec->hash, sec->idx);
  	elf_hash_add(elf->section_name_hash, &sec->name_hash, str_hash(sec->name));
530389968   Peter Zijlstra   objtool: Optimize...
711

2b10be23a   Peter Zijlstra   objtool: Clean up...
712
  	elf->changed = true;
627fce148   Josh Poimboeuf   objtool: Add ORC ...
713
714
  	return sec;
  }
fb414783b   Matt Helsley   objtool: Add supp...
715
716
717
718
719
720
721
722
723
724
725
726
  static struct section *elf_create_rel_reloc_section(struct elf *elf, struct section *base)
  {
  	char *relocname;
  	struct section *sec;
  
  	relocname = malloc(strlen(base->name) + strlen(".rel") + 1);
  	if (!relocname) {
  		perror("malloc");
  		return NULL;
  	}
  	strcpy(relocname, ".rel");
  	strcat(relocname, base->name);
1e7e47883   Josh Poimboeuf   x86/static_call: ...
727
  	sec = elf_create_section(elf, relocname, 0, sizeof(GElf_Rel), 0);
fb414783b   Matt Helsley   objtool: Add supp...
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
  	free(relocname);
  	if (!sec)
  		return NULL;
  
  	base->reloc = sec;
  	sec->base = base;
  
  	sec->sh.sh_type = SHT_REL;
  	sec->sh.sh_addralign = 8;
  	sec->sh.sh_link = find_section_by_name(elf, ".symtab")->idx;
  	sec->sh.sh_info = base->idx;
  	sec->sh.sh_flags = SHF_INFO_LINK;
  
  	return sec;
  }
  
  static struct section *elf_create_rela_reloc_section(struct elf *elf, struct section *base)
627fce148   Josh Poimboeuf   objtool: Add ORC ...
745
  {
f19742226   Matt Helsley   objtool: Rename r...
746
  	char *relocname;
627fce148   Josh Poimboeuf   objtool: Add ORC ...
747
  	struct section *sec;
f19742226   Matt Helsley   objtool: Rename r...
748
749
  	relocname = malloc(strlen(base->name) + strlen(".rela") + 1);
  	if (!relocname) {
627fce148   Josh Poimboeuf   objtool: Add ORC ...
750
751
752
  		perror("malloc");
  		return NULL;
  	}
f19742226   Matt Helsley   objtool: Rename r...
753
754
  	strcpy(relocname, ".rela");
  	strcat(relocname, base->name);
627fce148   Josh Poimboeuf   objtool: Add ORC ...
755

1e7e47883   Josh Poimboeuf   x86/static_call: ...
756
  	sec = elf_create_section(elf, relocname, 0, sizeof(GElf_Rela), 0);
f19742226   Matt Helsley   objtool: Rename r...
757
  	free(relocname);
627fce148   Josh Poimboeuf   objtool: Add ORC ...
758
759
  	if (!sec)
  		return NULL;
f19742226   Matt Helsley   objtool: Rename r...
760
  	base->reloc = sec;
627fce148   Josh Poimboeuf   objtool: Add ORC ...
761
762
763
764
765
766
767
768
769
770
  	sec->base = base;
  
  	sec->sh.sh_type = SHT_RELA;
  	sec->sh.sh_addralign = 8;
  	sec->sh.sh_link = find_section_by_name(elf, ".symtab")->idx;
  	sec->sh.sh_info = base->idx;
  	sec->sh.sh_flags = SHF_INFO_LINK;
  
  	return sec;
  }
fb414783b   Matt Helsley   objtool: Add supp...
771
772
773
774
775
776
777
778
779
780
781
782
  struct section *elf_create_reloc_section(struct elf *elf,
  					 struct section *base,
  					 int reltype)
  {
  	switch (reltype) {
  	case SHT_REL:  return elf_create_rel_reloc_section(elf, base);
  	case SHT_RELA: return elf_create_rela_reloc_section(elf, base);
  	default:       return NULL;
  	}
  }
  
  static int elf_rebuild_rel_reloc_section(struct section *sec, int nr)
627fce148   Josh Poimboeuf   objtool: Add ORC ...
783
  {
f19742226   Matt Helsley   objtool: Rename r...
784
  	struct reloc *reloc;
fb414783b   Matt Helsley   objtool: Add supp...
785
786
  	int idx = 0, size;
  	GElf_Rel *relocs;
627fce148   Josh Poimboeuf   objtool: Add ORC ...
787

fb414783b   Matt Helsley   objtool: Add supp...
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
  	/* Allocate a buffer for relocations */
  	size = nr * sizeof(*relocs);
  	relocs = malloc(size);
  	if (!relocs) {
  		perror("malloc");
  		return -1;
  	}
  
  	sec->data->d_buf = relocs;
  	sec->data->d_size = size;
  
  	sec->sh.sh_size = size;
  
  	idx = 0;
  	list_for_each_entry(reloc, &sec->reloc_list, list) {
  		relocs[idx].r_offset = reloc->offset;
  		relocs[idx].r_info = GELF_R_INFO(reloc->sym->idx, reloc->type);
  		idx++;
  	}
  
  	return 0;
  }
627fce148   Josh Poimboeuf   objtool: Add ORC ...
810

fb414783b   Matt Helsley   objtool: Add supp...
811
812
813
814
815
816
817
  static int elf_rebuild_rela_reloc_section(struct section *sec, int nr)
  {
  	struct reloc *reloc;
  	int idx = 0, size;
  	GElf_Rela *relocs;
  
  	/* Allocate a buffer for relocations with addends */
f19742226   Matt Helsley   objtool: Rename r...
818
819
820
  	size = nr * sizeof(*relocs);
  	relocs = malloc(size);
  	if (!relocs) {
627fce148   Josh Poimboeuf   objtool: Add ORC ...
821
822
823
  		perror("malloc");
  		return -1;
  	}
f19742226   Matt Helsley   objtool: Rename r...
824
  	sec->data->d_buf = relocs;
627fce148   Josh Poimboeuf   objtool: Add ORC ...
825
826
827
828
829
  	sec->data->d_size = size;
  
  	sec->sh.sh_size = size;
  
  	idx = 0;
f19742226   Matt Helsley   objtool: Rename r...
830
831
832
833
  	list_for_each_entry(reloc, &sec->reloc_list, list) {
  		relocs[idx].r_offset = reloc->offset;
  		relocs[idx].r_addend = reloc->addend;
  		relocs[idx].r_info = GELF_R_INFO(reloc->sym->idx, reloc->type);
627fce148   Josh Poimboeuf   objtool: Add ORC ...
834
835
836
837
838
  		idx++;
  	}
  
  	return 0;
  }
d832c0051   Peter Zijlstra   Merge branch 'obj...
839
  int elf_rebuild_reloc_section(struct elf *elf, struct section *sec)
fb414783b   Matt Helsley   objtool: Add supp...
840
841
842
  {
  	struct reloc *reloc;
  	int nr;
d832c0051   Peter Zijlstra   Merge branch 'obj...
843
844
  	sec->changed = true;
  	elf->changed = true;
fb414783b   Matt Helsley   objtool: Add supp...
845
846
847
848
849
850
851
852
853
854
  	nr = 0;
  	list_for_each_entry(reloc, &sec->reloc_list, list)
  		nr++;
  
  	switch (sec->sh.sh_type) {
  	case SHT_REL:  return elf_rebuild_rel_reloc_section(sec, nr);
  	case SHT_RELA: return elf_rebuild_rela_reloc_section(sec, nr);
  	default:       return -1;
  	}
  }
fdabdd0b0   Peter Zijlstra   objtool: Provide ...
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
  int elf_write_insn(struct elf *elf, struct section *sec,
  		   unsigned long offset, unsigned int len,
  		   const char *insn)
  {
  	Elf_Data *data = sec->data;
  
  	if (data->d_type != ELF_T_BYTE || data->d_off) {
  		WARN("write to unexpected data for section: %s", sec->name);
  		return -1;
  	}
  
  	memcpy(data->d_buf + offset, insn, len);
  	elf_flagdata(data, ELF_C_SET, ELF_F_DIRTY);
  
  	elf->changed = true;
  
  	return 0;
  }
d832c0051   Peter Zijlstra   Merge branch 'obj...
873
  int elf_write_reloc(struct elf *elf, struct reloc *reloc)
fdabdd0b0   Peter Zijlstra   objtool: Provide ...
874
  {
d832c0051   Peter Zijlstra   Merge branch 'obj...
875
  	struct section *sec = reloc->sec;
fdabdd0b0   Peter Zijlstra   objtool: Provide ...
876

d832c0051   Peter Zijlstra   Merge branch 'obj...
877
878
879
  	if (sec->sh.sh_type == SHT_REL) {
  		reloc->rel.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type);
  		reloc->rel.r_offset = reloc->offset;
fdabdd0b0   Peter Zijlstra   objtool: Provide ...
880

d832c0051   Peter Zijlstra   Merge branch 'obj...
881
882
883
884
885
886
887
888
889
890
891
892
893
  		if (!gelf_update_rel(sec->data, reloc->idx, &reloc->rel)) {
  			WARN_ELF("gelf_update_rel");
  			return -1;
  		}
  	} else {
  		reloc->rela.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type);
  		reloc->rela.r_addend = reloc->addend;
  		reloc->rela.r_offset = reloc->offset;
  
  		if (!gelf_update_rela(sec->data, reloc->idx, &reloc->rela)) {
  			WARN_ELF("gelf_update_rela");
  			return -1;
  		}
fdabdd0b0   Peter Zijlstra   objtool: Provide ...
894
895
896
897
898
899
  	}
  
  	elf->changed = true;
  
  	return 0;
  }
2b10be23a   Peter Zijlstra   objtool: Clean up...
900
  int elf_write(struct elf *elf)
627fce148   Josh Poimboeuf   objtool: Add ORC ...
901
902
903
  {
  	struct section *sec;
  	Elf_Scn *s;
97dab2ae7   Josh Poimboeuf   objtool: Fix obje...
904
  	/* Update section headers for changed sections: */
627fce148   Josh Poimboeuf   objtool: Add ORC ...
905
906
907
908
909
910
911
  	list_for_each_entry(sec, &elf->sections, list) {
  		if (sec->changed) {
  			s = elf_getscn(elf->elf, sec->idx);
  			if (!s) {
  				WARN_ELF("elf_getscn");
  				return -1;
  			}
97dab2ae7   Josh Poimboeuf   objtool: Fix obje...
912
  			if (!gelf_update_shdr(s, &sec->sh)) {
627fce148   Josh Poimboeuf   objtool: Add ORC ...
913
914
915
  				WARN_ELF("gelf_update_shdr");
  				return -1;
  			}
2b10be23a   Peter Zijlstra   objtool: Clean up...
916
917
  
  			sec->changed = false;
627fce148   Josh Poimboeuf   objtool: Add ORC ...
918
919
  		}
  	}
97dab2ae7   Josh Poimboeuf   objtool: Fix obje...
920
921
922
923
  	/* Make sure the new section header entries get updated properly. */
  	elf_flagelf(elf->elf, ELF_C_SET, ELF_F_DIRTY);
  
  	/* Write all changes to the file. */
627fce148   Josh Poimboeuf   objtool: Add ORC ...
924
925
926
927
  	if (elf_update(elf->elf, ELF_C_WRITE) < 0) {
  		WARN_ELF("elf_update");
  		return -1;
  	}
2b10be23a   Peter Zijlstra   objtool: Clean up...
928
  	elf->changed = false;
627fce148   Josh Poimboeuf   objtool: Add ORC ...
929
930
  	return 0;
  }
442f04c34   Josh Poimboeuf   objtool: Add tool...
931
932
933
934
  void elf_close(struct elf *elf)
  {
  	struct section *sec, *tmpsec;
  	struct symbol *sym, *tmpsym;
f19742226   Matt Helsley   objtool: Rename r...
935
  	struct reloc *reloc, *tmpreloc;
442f04c34   Josh Poimboeuf   objtool: Add tool...
936

baa41469a   Josh Poimboeuf   objtool: Implemen...
937
938
939
940
941
  	if (elf->elf)
  		elf_end(elf->elf);
  
  	if (elf->fd > 0)
  		close(elf->fd);
442f04c34   Josh Poimboeuf   objtool: Add tool...
942
  	list_for_each_entry_safe(sec, tmpsec, &elf->sections, list) {
a196e1719   Josh Poimboeuf   objtool: Rename s...
943
  		list_for_each_entry_safe(sym, tmpsym, &sec->symbol_list, list) {
442f04c34   Josh Poimboeuf   objtool: Add tool...
944
  			list_del(&sym->list);
042ba73fe   Josh Poimboeuf   objtool: Add seve...
945
  			hash_del(&sym->hash);
442f04c34   Josh Poimboeuf   objtool: Add tool...
946
947
  			free(sym);
  		}
f19742226   Matt Helsley   objtool: Rename r...
948
949
950
951
  		list_for_each_entry_safe(reloc, tmpreloc, &sec->reloc_list, list) {
  			list_del(&reloc->list);
  			hash_del(&reloc->hash);
  			free(reloc);
442f04c34   Josh Poimboeuf   objtool: Add tool...
952
953
954
955
  		}
  		list_del(&sec->list);
  		free(sec);
  	}
baa41469a   Josh Poimboeuf   objtool: Implemen...
956

442f04c34   Josh Poimboeuf   objtool: Add tool...
957
958
  	free(elf);
  }