mirror of
https://github.com/torvalds/linux.git
synced 2024-11-26 06:02:05 +00:00
7786032e52
Currently objtool headers are being included either by their base name or included via ../ from a parent directory. In case of a base name usage: #include "warn.h" #include "arch_elf.h" it does not make it apparent from which directory the file comes from. To make it slightly better, and actually to avoid name clashes some arch specific files have "arch_" suffix. And files from an arch folder have to revert to including via ../ e.g: #include "../../elf.h" With additional architectures support and the code base growth there is a need for clearer headers naming scheme for multiple reasons: 1. to make it instantly obvious where these files come from (objtool itself / objtool arch|generic folders / some other external files), 2. to avoid name clashes of objtool arch specific headers, potential obtool arch generic headers and the system header files (there is /usr/include/elf.h already), 3. to avoid ../ includes and improve code readability. 4. to give a warm fuzzy feeling to developers who are mostly kernel developers and are accustomed to linux kernel headers arranging scheme. Doesn't this make it instantly obvious where are these files come from? #include <objtool/warn.h> #include <arch/elf.h> And doesn't it look nicer to avoid ugly ../ includes? Which also guarantees this is elf.h from the objtool and not /usr/include/elf.h. #include <objtool/elf.h> This patch defines and implements new objtool headers arranging scheme. Which is: - all generic headers go to include/objtool (similar to include/linux) - all arch headers go to arch/$(SRCARCH)/include/arch (to get arch prefix). This is similar to linux arch specific "asm/*" headers but we are not abusing "asm" name and calling it what it is. This also helps to prevent name clashes (arch is not used in system headers or kernel exports). To bring objtool to this state the following things are done: 1. current top level tools/objtool/ headers are moved into include/objtool/ subdirectory, 2. arch specific headers, currently only arch/x86/include/ are moved into arch/x86/include/arch/ and were stripped of "arch_" suffix, 3. new -I$(srctree)/tools/objtool/include include path to make includes like <objtool/warn.h> possible, 4. rewriting file includes, 5. make git not to ignore include/objtool/ subdirectory. Signed-off-by: Vasily Gorbik <gor@linux.ibm.com> Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> Acked-by: Masami Hiramatsu <mhiramat@kernel.org> Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
216 lines
4.2 KiB
C
216 lines
4.2 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com>
|
|
*/
|
|
|
|
#include <unistd.h>
|
|
#include <linux/objtool.h>
|
|
#include <asm/orc_types.h>
|
|
#include <objtool/objtool.h>
|
|
#include <objtool/warn.h>
|
|
#include <objtool/endianness.h>
|
|
|
|
static const char *reg_name(unsigned int reg)
|
|
{
|
|
switch (reg) {
|
|
case ORC_REG_PREV_SP:
|
|
return "prevsp";
|
|
case ORC_REG_DX:
|
|
return "dx";
|
|
case ORC_REG_DI:
|
|
return "di";
|
|
case ORC_REG_BP:
|
|
return "bp";
|
|
case ORC_REG_SP:
|
|
return "sp";
|
|
case ORC_REG_R10:
|
|
return "r10";
|
|
case ORC_REG_R13:
|
|
return "r13";
|
|
case ORC_REG_BP_INDIRECT:
|
|
return "bp(ind)";
|
|
case ORC_REG_SP_INDIRECT:
|
|
return "sp(ind)";
|
|
default:
|
|
return "?";
|
|
}
|
|
}
|
|
|
|
static const char *orc_type_name(unsigned int type)
|
|
{
|
|
switch (type) {
|
|
case UNWIND_HINT_TYPE_CALL:
|
|
return "call";
|
|
case UNWIND_HINT_TYPE_REGS:
|
|
return "regs";
|
|
case UNWIND_HINT_TYPE_REGS_PARTIAL:
|
|
return "regs (partial)";
|
|
default:
|
|
return "?";
|
|
}
|
|
}
|
|
|
|
static void print_reg(unsigned int reg, int offset)
|
|
{
|
|
if (reg == ORC_REG_BP_INDIRECT)
|
|
printf("(bp%+d)", offset);
|
|
else if (reg == ORC_REG_SP_INDIRECT)
|
|
printf("(sp%+d)", offset);
|
|
else if (reg == ORC_REG_UNDEFINED)
|
|
printf("(und)");
|
|
else
|
|
printf("%s%+d", reg_name(reg), offset);
|
|
}
|
|
|
|
int orc_dump(const char *_objname)
|
|
{
|
|
int fd, nr_entries, i, *orc_ip = NULL, orc_size = 0;
|
|
struct orc_entry *orc = NULL;
|
|
char *name;
|
|
size_t nr_sections;
|
|
Elf64_Addr orc_ip_addr = 0;
|
|
size_t shstrtab_idx, strtab_idx = 0;
|
|
Elf *elf;
|
|
Elf_Scn *scn;
|
|
GElf_Shdr sh;
|
|
GElf_Rela rela;
|
|
GElf_Sym sym;
|
|
Elf_Data *data, *symtab = NULL, *rela_orc_ip = NULL;
|
|
|
|
|
|
objname = _objname;
|
|
|
|
elf_version(EV_CURRENT);
|
|
|
|
fd = open(objname, O_RDONLY);
|
|
if (fd == -1) {
|
|
perror("open");
|
|
return -1;
|
|
}
|
|
|
|
elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
|
|
if (!elf) {
|
|
WARN_ELF("elf_begin");
|
|
return -1;
|
|
}
|
|
|
|
if (elf_getshdrnum(elf, &nr_sections)) {
|
|
WARN_ELF("elf_getshdrnum");
|
|
return -1;
|
|
}
|
|
|
|
if (elf_getshdrstrndx(elf, &shstrtab_idx)) {
|
|
WARN_ELF("elf_getshdrstrndx");
|
|
return -1;
|
|
}
|
|
|
|
for (i = 0; i < nr_sections; i++) {
|
|
scn = elf_getscn(elf, i);
|
|
if (!scn) {
|
|
WARN_ELF("elf_getscn");
|
|
return -1;
|
|
}
|
|
|
|
if (!gelf_getshdr(scn, &sh)) {
|
|
WARN_ELF("gelf_getshdr");
|
|
return -1;
|
|
}
|
|
|
|
name = elf_strptr(elf, shstrtab_idx, sh.sh_name);
|
|
if (!name) {
|
|
WARN_ELF("elf_strptr");
|
|
return -1;
|
|
}
|
|
|
|
data = elf_getdata(scn, NULL);
|
|
if (!data) {
|
|
WARN_ELF("elf_getdata");
|
|
return -1;
|
|
}
|
|
|
|
if (!strcmp(name, ".symtab")) {
|
|
symtab = data;
|
|
} else if (!strcmp(name, ".strtab")) {
|
|
strtab_idx = i;
|
|
} else if (!strcmp(name, ".orc_unwind")) {
|
|
orc = data->d_buf;
|
|
orc_size = sh.sh_size;
|
|
} else if (!strcmp(name, ".orc_unwind_ip")) {
|
|
orc_ip = data->d_buf;
|
|
orc_ip_addr = sh.sh_addr;
|
|
} else if (!strcmp(name, ".rela.orc_unwind_ip")) {
|
|
rela_orc_ip = data;
|
|
}
|
|
}
|
|
|
|
if (!symtab || !strtab_idx || !orc || !orc_ip)
|
|
return 0;
|
|
|
|
if (orc_size % sizeof(*orc) != 0) {
|
|
WARN("bad .orc_unwind section size");
|
|
return -1;
|
|
}
|
|
|
|
nr_entries = orc_size / sizeof(*orc);
|
|
for (i = 0; i < nr_entries; i++) {
|
|
if (rela_orc_ip) {
|
|
if (!gelf_getrela(rela_orc_ip, i, &rela)) {
|
|
WARN_ELF("gelf_getrela");
|
|
return -1;
|
|
}
|
|
|
|
if (!gelf_getsym(symtab, GELF_R_SYM(rela.r_info), &sym)) {
|
|
WARN_ELF("gelf_getsym");
|
|
return -1;
|
|
}
|
|
|
|
if (GELF_ST_TYPE(sym.st_info) == STT_SECTION) {
|
|
scn = elf_getscn(elf, sym.st_shndx);
|
|
if (!scn) {
|
|
WARN_ELF("elf_getscn");
|
|
return -1;
|
|
}
|
|
|
|
if (!gelf_getshdr(scn, &sh)) {
|
|
WARN_ELF("gelf_getshdr");
|
|
return -1;
|
|
}
|
|
|
|
name = elf_strptr(elf, shstrtab_idx, sh.sh_name);
|
|
if (!name) {
|
|
WARN_ELF("elf_strptr");
|
|
return -1;
|
|
}
|
|
} else {
|
|
name = elf_strptr(elf, strtab_idx, sym.st_name);
|
|
if (!name) {
|
|
WARN_ELF("elf_strptr");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
printf("%s+%llx:", name, (unsigned long long)rela.r_addend);
|
|
|
|
} else {
|
|
printf("%llx:", (unsigned long long)(orc_ip_addr + (i * sizeof(int)) + orc_ip[i]));
|
|
}
|
|
|
|
|
|
printf(" sp:");
|
|
|
|
print_reg(orc[i].sp_reg, bswap_if_needed(orc[i].sp_offset));
|
|
|
|
printf(" bp:");
|
|
|
|
print_reg(orc[i].bp_reg, bswap_if_needed(orc[i].bp_offset));
|
|
|
|
printf(" type:%s end:%d\n",
|
|
orc_type_name(orc[i].type), orc[i].end);
|
|
}
|
|
|
|
elf_end(elf);
|
|
close(fd);
|
|
|
|
return 0;
|
|
}
|