File Index
Files and directories
Sign in
FILE

orc_dump.c

File preview with syntax highlighting.

linux-6.19.14/tools/objtool/orc_dump.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com>
  4 */
  5
  6#include <unistd.h>
  7#include <asm/orc_types.h>
  8#include <objtool/objtool.h>
  9#include <objtool/orc.h>
 10#include <objtool/warn.h>
 11
 12int orc_dump(const char *filename)
 13{
 14	int fd, nr_entries, i, *orc_ip = NULL, orc_size = 0;
 15	struct orc_entry *orc = NULL;
 16	char *name;
 17	size_t nr_sections;
 18	Elf64_Addr orc_ip_addr = 0;
 19	size_t shstrtab_idx, strtab_idx = 0;
 20	Elf *elf;
 21	Elf_Scn *scn;
 22	GElf_Shdr sh;
 23	GElf_Rela rela;
 24	GElf_Sym sym;
 25	Elf_Data *data, *symtab = NULL, *rela_orc_ip = NULL;
 26	struct elf dummy_elf = {};
 27
 28	elf_version(EV_CURRENT);
 29
 30	fd = open(filename, O_RDONLY);
 31	if (fd == -1) {
 32		perror("open");
 33		return -1;
 34	}
 35
 36	elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
 37	if (!elf) {
 38		ERROR_ELF("elf_begin");
 39		return -1;
 40	}
 41
 42	if (!elf64_getehdr(elf)) {
 43		ERROR_ELF("elf64_getehdr");
 44		return -1;
 45	}
 46	memcpy(&dummy_elf.ehdr, elf64_getehdr(elf), sizeof(dummy_elf.ehdr));
 47
 48	if (elf_getshdrnum(elf, &nr_sections)) {
 49		ERROR_ELF("elf_getshdrnum");
 50		return -1;
 51	}
 52
 53	if (elf_getshdrstrndx(elf, &shstrtab_idx)) {
 54		ERROR_ELF("elf_getshdrstrndx");
 55		return -1;
 56	}
 57
 58	for (i = 0; i < nr_sections; i++) {
 59		scn = elf_getscn(elf, i);
 60		if (!scn) {
 61			ERROR_ELF("elf_getscn");
 62			return -1;
 63		}
 64
 65		if (!gelf_getshdr(scn, &sh)) {
 66			ERROR_ELF("gelf_getshdr");
 67			return -1;
 68		}
 69
 70		name = elf_strptr(elf, shstrtab_idx, sh.sh_name);
 71		if (!name) {
 72			ERROR_ELF("elf_strptr");
 73			return -1;
 74		}
 75
 76		data = elf_getdata(scn, NULL);
 77		if (!data) {
 78			ERROR_ELF("elf_getdata");
 79			return -1;
 80		}
 81
 82		if (!strcmp(name, ".symtab")) {
 83			symtab = data;
 84		} else if (!strcmp(name, ".strtab")) {
 85			strtab_idx = i;
 86		} else if (!strcmp(name, ".orc_unwind")) {
 87			orc = data->d_buf;
 88			orc_size = sh.sh_size;
 89		} else if (!strcmp(name, ".orc_unwind_ip")) {
 90			orc_ip = data->d_buf;
 91			orc_ip_addr = sh.sh_addr;
 92		} else if (!strcmp(name, ".rela.orc_unwind_ip")) {
 93			rela_orc_ip = data;
 94		}
 95	}
 96
 97	if (!symtab || !strtab_idx || !orc || !orc_ip)
 98		return 0;
 99
100	if (orc_size % sizeof(*orc) != 0) {
101		ERROR("bad .orc_unwind section size");
102		return -1;
103	}
104
105	nr_entries = orc_size / sizeof(*orc);
106	for (i = 0; i < nr_entries; i++) {
107		if (rela_orc_ip) {
108			if (!gelf_getrela(rela_orc_ip, i, &rela)) {
109				ERROR_ELF("gelf_getrela");
110				return -1;
111			}
112
113			if (!gelf_getsym(symtab, GELF_R_SYM(rela.r_info), &sym)) {
114				ERROR_ELF("gelf_getsym");
115				return -1;
116			}
117
118			if (GELF_ST_TYPE(sym.st_info) == STT_SECTION) {
119				scn = elf_getscn(elf, sym.st_shndx);
120				if (!scn) {
121					ERROR_ELF("elf_getscn");
122					return -1;
123				}
124
125				if (!gelf_getshdr(scn, &sh)) {
126					ERROR_ELF("gelf_getshdr");
127					return -1;
128				}
129
130				name = elf_strptr(elf, shstrtab_idx, sh.sh_name);
131				if (!name) {
132					ERROR_ELF("elf_strptr");
133					return -1;
134				}
135			} else {
136				name = elf_strptr(elf, strtab_idx, sym.st_name);
137				if (!name) {
138					ERROR_ELF("elf_strptr");
139					return -1;
140				}
141			}
142
143			printf("%s+%llx:", name, (unsigned long long)rela.r_addend);
144
145		} else {
146			printf("%llx:", (unsigned long long)(orc_ip_addr + (i * sizeof(int)) + orc_ip[i]));
147		}
148
149		orc_print_dump(&dummy_elf, orc, i);
150	}
151
152	elf_end(elf);
153	close(fd);
154
155	return 0;
156}
~/ Read-only file preview.