cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

orc_dump.c (4257B)


      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 <linux/objtool.h>
      8#include <asm/orc_types.h>
      9#include <objtool/objtool.h>
     10#include <objtool/warn.h>
     11#include <objtool/endianness.h>
     12
     13static const char *reg_name(unsigned int reg)
     14{
     15	switch (reg) {
     16	case ORC_REG_PREV_SP:
     17		return "prevsp";
     18	case ORC_REG_DX:
     19		return "dx";
     20	case ORC_REG_DI:
     21		return "di";
     22	case ORC_REG_BP:
     23		return "bp";
     24	case ORC_REG_SP:
     25		return "sp";
     26	case ORC_REG_R10:
     27		return "r10";
     28	case ORC_REG_R13:
     29		return "r13";
     30	case ORC_REG_BP_INDIRECT:
     31		return "bp(ind)";
     32	case ORC_REG_SP_INDIRECT:
     33		return "sp(ind)";
     34	default:
     35		return "?";
     36	}
     37}
     38
     39static const char *orc_type_name(unsigned int type)
     40{
     41	switch (type) {
     42	case UNWIND_HINT_TYPE_CALL:
     43		return "call";
     44	case UNWIND_HINT_TYPE_REGS:
     45		return "regs";
     46	case UNWIND_HINT_TYPE_REGS_PARTIAL:
     47		return "regs (partial)";
     48	default:
     49		return "?";
     50	}
     51}
     52
     53static void print_reg(unsigned int reg, int offset)
     54{
     55	if (reg == ORC_REG_BP_INDIRECT)
     56		printf("(bp%+d)", offset);
     57	else if (reg == ORC_REG_SP_INDIRECT)
     58		printf("(sp)%+d", offset);
     59	else if (reg == ORC_REG_UNDEFINED)
     60		printf("(und)");
     61	else
     62		printf("%s%+d", reg_name(reg), offset);
     63}
     64
     65int orc_dump(const char *_objname)
     66{
     67	int fd, nr_entries, i, *orc_ip = NULL, orc_size = 0;
     68	struct orc_entry *orc = NULL;
     69	char *name;
     70	size_t nr_sections;
     71	Elf64_Addr orc_ip_addr = 0;
     72	size_t shstrtab_idx, strtab_idx = 0;
     73	Elf *elf;
     74	Elf_Scn *scn;
     75	GElf_Shdr sh;
     76	GElf_Rela rela;
     77	GElf_Sym sym;
     78	Elf_Data *data, *symtab = NULL, *rela_orc_ip = NULL;
     79
     80
     81	objname = _objname;
     82
     83	elf_version(EV_CURRENT);
     84
     85	fd = open(objname, O_RDONLY);
     86	if (fd == -1) {
     87		perror("open");
     88		return -1;
     89	}
     90
     91	elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
     92	if (!elf) {
     93		WARN_ELF("elf_begin");
     94		return -1;
     95	}
     96
     97	if (elf_getshdrnum(elf, &nr_sections)) {
     98		WARN_ELF("elf_getshdrnum");
     99		return -1;
    100	}
    101
    102	if (elf_getshdrstrndx(elf, &shstrtab_idx)) {
    103		WARN_ELF("elf_getshdrstrndx");
    104		return -1;
    105	}
    106
    107	for (i = 0; i < nr_sections; i++) {
    108		scn = elf_getscn(elf, i);
    109		if (!scn) {
    110			WARN_ELF("elf_getscn");
    111			return -1;
    112		}
    113
    114		if (!gelf_getshdr(scn, &sh)) {
    115			WARN_ELF("gelf_getshdr");
    116			return -1;
    117		}
    118
    119		name = elf_strptr(elf, shstrtab_idx, sh.sh_name);
    120		if (!name) {
    121			WARN_ELF("elf_strptr");
    122			return -1;
    123		}
    124
    125		data = elf_getdata(scn, NULL);
    126		if (!data) {
    127			WARN_ELF("elf_getdata");
    128			return -1;
    129		}
    130
    131		if (!strcmp(name, ".symtab")) {
    132			symtab = data;
    133		} else if (!strcmp(name, ".strtab")) {
    134			strtab_idx = i;
    135		} else if (!strcmp(name, ".orc_unwind")) {
    136			orc = data->d_buf;
    137			orc_size = sh.sh_size;
    138		} else if (!strcmp(name, ".orc_unwind_ip")) {
    139			orc_ip = data->d_buf;
    140			orc_ip_addr = sh.sh_addr;
    141		} else if (!strcmp(name, ".rela.orc_unwind_ip")) {
    142			rela_orc_ip = data;
    143		}
    144	}
    145
    146	if (!symtab || !strtab_idx || !orc || !orc_ip)
    147		return 0;
    148
    149	if (orc_size % sizeof(*orc) != 0) {
    150		WARN("bad .orc_unwind section size");
    151		return -1;
    152	}
    153
    154	nr_entries = orc_size / sizeof(*orc);
    155	for (i = 0; i < nr_entries; i++) {
    156		if (rela_orc_ip) {
    157			if (!gelf_getrela(rela_orc_ip, i, &rela)) {
    158				WARN_ELF("gelf_getrela");
    159				return -1;
    160			}
    161
    162			if (!gelf_getsym(symtab, GELF_R_SYM(rela.r_info), &sym)) {
    163				WARN_ELF("gelf_getsym");
    164				return -1;
    165			}
    166
    167			if (GELF_ST_TYPE(sym.st_info) == STT_SECTION) {
    168				scn = elf_getscn(elf, sym.st_shndx);
    169				if (!scn) {
    170					WARN_ELF("elf_getscn");
    171					return -1;
    172				}
    173
    174				if (!gelf_getshdr(scn, &sh)) {
    175					WARN_ELF("gelf_getshdr");
    176					return -1;
    177				}
    178
    179				name = elf_strptr(elf, shstrtab_idx, sh.sh_name);
    180				if (!name) {
    181					WARN_ELF("elf_strptr");
    182					return -1;
    183				}
    184			} else {
    185				name = elf_strptr(elf, strtab_idx, sym.st_name);
    186				if (!name) {
    187					WARN_ELF("elf_strptr");
    188					return -1;
    189				}
    190			}
    191
    192			printf("%s+%llx:", name, (unsigned long long)rela.r_addend);
    193
    194		} else {
    195			printf("%llx:", (unsigned long long)(orc_ip_addr + (i * sizeof(int)) + orc_ip[i]));
    196		}
    197
    198
    199		printf(" sp:");
    200
    201		print_reg(orc[i].sp_reg, bswap_if_needed(orc[i].sp_offset));
    202
    203		printf(" bp:");
    204
    205		print_reg(orc[i].bp_reg, bswap_if_needed(orc[i].bp_offset));
    206
    207		printf(" type:%s end:%d\n",
    208		       orc_type_name(orc[i].type), orc[i].end);
    209	}
    210
    211	elf_end(elf);
    212	close(fd);
    213
    214	return 0;
    215}