mirror of
https://github.com/JakeHillion/drgn.git
synced 2024-12-22 17:23:06 +00:00
libdrgn: add stub RISC-V architecture with relocation implementation
The 32-bit and 64-bit variants have different register sizes, so they're different architectures in drgn. For now, put them in the same file so that they can share the relocation implementation. We'll need to figure out how to handle registers later. P.S. RISC-V has the weirdest relocations so far. /proc/kcore also appears to be broken. Signed-off-by: Omar Sandoval <osandov@osandov.com>
This commit is contained in:
parent
d27204260e
commit
14642fb3b6
@ -953,6 +953,12 @@ class Architecture(enum.Enum):
|
||||
PPC64 = ...
|
||||
"""The 64-bit PowerPC architecture."""
|
||||
|
||||
RISCV64 = ...
|
||||
"""The 64-bit RISC-V architecture."""
|
||||
|
||||
RISCV32 = ...
|
||||
"""The 32-bit RISC-V architecture."""
|
||||
|
||||
UNKNOWN = ...
|
||||
"""
|
||||
An architecture which is not known to drgn. Certain features are not
|
||||
|
@ -30,6 +30,7 @@ libdrgnimpl_la_SOURCES = $(ARCH_DEFS:.defs=.c) \
|
||||
arch_arm.c \
|
||||
arch_i386.c \
|
||||
arch_register_layout.h \
|
||||
arch_riscv.c \
|
||||
array.h \
|
||||
binary_buffer.c \
|
||||
binary_buffer.h \
|
||||
|
126
libdrgn/arch_riscv.c
Normal file
126
libdrgn/arch_riscv.c
Normal file
@ -0,0 +1,126 @@
|
||||
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include <byteswap.h>
|
||||
|
||||
#include "platform.h" // IWYU pragma: associated
|
||||
|
||||
/*
|
||||
* The ABI specification can be found at:
|
||||
* https://github.com/riscv-non-isa/riscv-elf-psabi-doc
|
||||
*/
|
||||
|
||||
static struct drgn_error drgn_invalid_rel = {
|
||||
.code = DRGN_ERROR_OTHER,
|
||||
.message = "invalid relocation type for SHT_REL",
|
||||
};
|
||||
|
||||
static struct drgn_error *
|
||||
apply_elf_reloc_riscv(const struct drgn_relocating_section *relocating,
|
||||
uint64_t r_offset, uint32_t r_type, const int64_t *r_addend,
|
||||
uint64_t sym_value)
|
||||
{
|
||||
switch (r_type) {
|
||||
case R_RISCV_NONE:
|
||||
return NULL;
|
||||
case R_RISCV_32:
|
||||
return drgn_reloc_add32(relocating, r_offset, r_addend,
|
||||
sym_value);
|
||||
case R_RISCV_64:
|
||||
return drgn_reloc_add64(relocating, r_offset, r_addend,
|
||||
sym_value);
|
||||
#define CASE_R_RISCV_ADD_SUB(bits) \
|
||||
case R_RISCV_ADD##bits: { \
|
||||
if (!r_addend) \
|
||||
return &drgn_invalid_rel; \
|
||||
uint##bits##_t value; \
|
||||
if (r_offset > relocating->buf_size || \
|
||||
relocating->buf_size - r_offset < sizeof(value)) \
|
||||
return &drgn_invalid_relocation_offset; \
|
||||
memcpy(&value, relocating->buf + r_offset, sizeof(value)); \
|
||||
if (relocating->bswap) \
|
||||
value = bswap_##bits(value); \
|
||||
value += sym_value + *r_addend; \
|
||||
if (relocating->bswap) \
|
||||
value = bswap_##bits(value); \
|
||||
memcpy(relocating->buf + r_offset, &value, sizeof(value)); \
|
||||
return NULL; \
|
||||
} \
|
||||
case R_RISCV_SUB##bits: { \
|
||||
if (!r_addend) \
|
||||
return &drgn_invalid_rel; \
|
||||
uint##bits##_t value; \
|
||||
if (r_offset > relocating->buf_size || \
|
||||
relocating->buf_size - r_offset < sizeof(value)) \
|
||||
return &drgn_invalid_relocation_offset; \
|
||||
memcpy(&value, relocating->buf + r_offset, sizeof(value)); \
|
||||
if (relocating->bswap) \
|
||||
value = bswap_##bits(value); \
|
||||
value -= sym_value + *r_addend; \
|
||||
if (relocating->bswap) \
|
||||
value = bswap_##bits(value); \
|
||||
memcpy(relocating->buf + r_offset, &value, sizeof(value)); \
|
||||
return NULL; \
|
||||
}
|
||||
#define bswap_8(x) (x)
|
||||
CASE_R_RISCV_ADD_SUB(8)
|
||||
#undef bswap_8
|
||||
CASE_R_RISCV_ADD_SUB(16)
|
||||
CASE_R_RISCV_ADD_SUB(32)
|
||||
CASE_R_RISCV_ADD_SUB(64)
|
||||
#undef CASE_R_RISCV_ADD_SUB
|
||||
case R_RISCV_SUB6: {
|
||||
if (!r_addend)
|
||||
return &drgn_invalid_rel;
|
||||
uint8_t value;
|
||||
if (r_offset > relocating->buf_size ||
|
||||
relocating->buf_size - r_offset < sizeof(value))
|
||||
return &drgn_invalid_relocation_offset;
|
||||
memcpy(&value, relocating->buf + r_offset, sizeof(value));
|
||||
value = ((value & 0xc0) |
|
||||
(((value & 0x3f) - (sym_value + *r_addend)) & 0x3f));
|
||||
memcpy(relocating->buf + r_offset, &value, sizeof(value));
|
||||
return NULL;
|
||||
}
|
||||
case R_RISCV_SET6: {
|
||||
if (!r_addend)
|
||||
return &drgn_invalid_rel;
|
||||
uint8_t value;
|
||||
if (r_offset > relocating->buf_size ||
|
||||
relocating->buf_size - r_offset < sizeof(value))
|
||||
return &drgn_invalid_relocation_offset;
|
||||
memcpy(&value, relocating->buf + r_offset, sizeof(value));
|
||||
value = (value & 0xc0) | ((sym_value + *r_addend) & 0x3f);
|
||||
memcpy(relocating->buf + r_offset, &value, sizeof(value));
|
||||
return NULL;
|
||||
}
|
||||
case R_RISCV_SET8:
|
||||
return drgn_reloc_add8(relocating, r_offset, r_addend,
|
||||
sym_value);
|
||||
case R_RISCV_SET16:
|
||||
return drgn_reloc_add16(relocating, r_offset, r_addend,
|
||||
sym_value);
|
||||
case R_RISCV_SET32:
|
||||
return drgn_reloc_add32(relocating, r_offset, r_addend,
|
||||
sym_value);
|
||||
default:
|
||||
return DRGN_UNKNOWN_RELOCATION_TYPE(r_type);
|
||||
}
|
||||
}
|
||||
|
||||
const struct drgn_architecture_info arch_info_riscv64 = {
|
||||
.name = "RISC-V 64",
|
||||
.arch = DRGN_ARCH_RISCV64,
|
||||
.default_flags = (DRGN_PLATFORM_IS_64_BIT |
|
||||
DRGN_PLATFORM_IS_LITTLE_ENDIAN),
|
||||
.register_by_name = drgn_register_by_name_unknown,
|
||||
.apply_elf_reloc = apply_elf_reloc_riscv,
|
||||
};
|
||||
|
||||
const struct drgn_architecture_info arch_info_riscv32 = {
|
||||
.name = "RISC-V 32",
|
||||
.arch = DRGN_ARCH_RISCV32,
|
||||
.default_flags = DRGN_PLATFORM_IS_LITTLE_ENDIAN,
|
||||
.register_by_name = drgn_register_by_name_unknown,
|
||||
.apply_elf_reloc = apply_elf_reloc_riscv,
|
||||
};
|
@ -365,6 +365,8 @@ enum drgn_architecture {
|
||||
DRGN_ARCH_AARCH64,
|
||||
DRGN_ARCH_ARM,
|
||||
DRGN_ARCH_PPC64,
|
||||
DRGN_ARCH_RISCV64,
|
||||
DRGN_ARCH_RISCV32,
|
||||
};
|
||||
|
||||
/** Flags describing a @ref drgn_platform. */
|
||||
|
@ -35,6 +35,7 @@ static struct drgn_error *drgn_platform_from_kdump(kdump_ctx_t *ctx,
|
||||
arch = &arch_info_arm;
|
||||
else if (strcmp(str, KDUMP_ARCH_PPC64) == 0)
|
||||
arch = &arch_info_ppc64;
|
||||
/* libkdumpfile doesn't support RISC-V */
|
||||
else
|
||||
arch = &arch_info_unknown;
|
||||
|
||||
|
@ -30,6 +30,14 @@ LIBDRGN_PUBLIC const struct drgn_platform drgn_host_platform = {
|
||||
.arch = &arch_info_arm,
|
||||
#elif __powerpc64__
|
||||
.arch = &arch_info_ppc64,
|
||||
#elif __riscv
|
||||
#if __riscv_xlen == 64
|
||||
.arch = &arch_info_riscv64,
|
||||
#elif __riscv_xlen == 32
|
||||
.arch = &arch_info_riscv32,
|
||||
#else
|
||||
#error "unknown __riscv_xlen"
|
||||
#endif
|
||||
#else
|
||||
.arch = &arch_info_unknown,
|
||||
#endif
|
||||
@ -63,6 +71,12 @@ drgn_platform_create(enum drgn_architecture arch,
|
||||
case DRGN_ARCH_PPC64:
|
||||
arch_info = &arch_info_ppc64;
|
||||
break;
|
||||
case DRGN_ARCH_RISCV64:
|
||||
arch_info = &arch_info_riscv64;
|
||||
break;
|
||||
case DRGN_ARCH_RISCV32:
|
||||
arch_info = &arch_info_riscv32;
|
||||
break;
|
||||
default:
|
||||
return drgn_error_create(DRGN_ERROR_INVALID_ARGUMENT,
|
||||
"invalid architecture");
|
||||
@ -142,6 +156,12 @@ void drgn_platform_from_elf(GElf_Ehdr *ehdr, struct drgn_platform *ret)
|
||||
case EM_PPC64:
|
||||
arch = &arch_info_ppc64;
|
||||
break;
|
||||
case EM_RISCV:
|
||||
if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
|
||||
arch = &arch_info_riscv64;
|
||||
else
|
||||
arch = &arch_info_riscv32;
|
||||
break;
|
||||
default:
|
||||
arch = &arch_info_unknown;
|
||||
break;
|
||||
@ -176,7 +196,7 @@ drgn_register_names(const struct drgn_register *reg, size_t *num_names_ret)
|
||||
return reg->names;
|
||||
}
|
||||
|
||||
static struct drgn_error drgn_invalid_relocation_offset = {
|
||||
struct drgn_error drgn_invalid_relocation_offset = {
|
||||
.code = DRGN_ERROR_OTHER,
|
||||
.message = "invalid relocation offset",
|
||||
};
|
||||
@ -207,4 +227,7 @@ drgn_reloc_add##bits(const struct drgn_relocating_section *relocating, \
|
||||
DEFINE_DRGN_RELOC_ADD(64)
|
||||
DEFINE_DRGN_RELOC_ADD(32)
|
||||
DEFINE_DRGN_RELOC_ADD(16)
|
||||
#define bswap_8(x) (x)
|
||||
DEFINE_DRGN_RELOC_ADD(8)
|
||||
#undef bswap_8
|
||||
#undef DEFINE_DRGN_RELOC_ADD
|
||||
|
@ -34,6 +34,8 @@ struct drgn_relocating_section {
|
||||
bool bswap;
|
||||
};
|
||||
|
||||
extern struct drgn_error drgn_invalid_relocation_offset;
|
||||
|
||||
/*
|
||||
* Apply an ELF relocation as:
|
||||
*
|
||||
@ -54,6 +56,9 @@ drgn_reloc_add32(const struct drgn_relocating_section *relocating,
|
||||
struct drgn_error *
|
||||
drgn_reloc_add16(const struct drgn_relocating_section *relocating,
|
||||
uint64_t r_offset, const int64_t *r_addend, uint16_t addend);
|
||||
struct drgn_error *
|
||||
drgn_reloc_add8(const struct drgn_relocating_section *relocating,
|
||||
uint64_t r_offset, const int64_t *r_addend, uint8_t addend);
|
||||
|
||||
#define DRGN_UNKNOWN_RELOCATION_TYPE(r_type) \
|
||||
drgn_error_format(DRGN_ERROR_OTHER, \
|
||||
@ -160,6 +165,8 @@ extern const struct drgn_architecture_info arch_info_i386;
|
||||
extern const struct drgn_architecture_info arch_info_aarch64;
|
||||
extern const struct drgn_architecture_info arch_info_arm;
|
||||
extern const struct drgn_architecture_info arch_info_ppc64;
|
||||
extern const struct drgn_architecture_info arch_info_riscv64;
|
||||
extern const struct drgn_architecture_info arch_info_riscv32;
|
||||
|
||||
struct drgn_platform {
|
||||
const struct drgn_architecture_info *arch;
|
||||
|
Loading…
Reference in New Issue
Block a user