1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 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 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
// SPDX-License-Identifier: LGPL-2.1-or-later
#include <byteswap.h>
#include <elf.h>
#include <stdlib.h>
#include <string.h>
#include "platform.h"
const struct drgn_register *drgn_register_by_name_unknown(const char *name)
{
return NULL;
}
const struct drgn_architecture_info arch_info_unknown = {
.name = "unknown",
.arch = DRGN_ARCH_UNKNOWN,
.register_by_name = drgn_register_by_name_unknown,
};
LIBDRGN_PUBLIC const struct drgn_platform drgn_host_platform = {
#if __x86_64__
.arch = &arch_info_x86_64,
#elif __i386__
.arch = &arch_info_i386,
#elif __aarch64__
.arch = &arch_info_aarch64,
#elif __arm__
.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
#elif __s390x__
.arch = &arch_info_s390x,
// __s390__ is also defined for s390x, so the order is important.
#elif __s390__
.arch = &arch_info_s390,
#else
.arch = &arch_info_unknown,
#endif
.flags = ((sizeof(void *) == 8 ? DRGN_PLATFORM_IS_64_BIT : 0) |
(HOST_LITTLE_ENDIAN ? DRGN_PLATFORM_IS_LITTLE_ENDIAN : 0)),
};
LIBDRGN_PUBLIC struct drgn_error *
drgn_platform_create(enum drgn_architecture arch,
enum drgn_platform_flags flags, struct drgn_platform **ret)
{
const struct drgn_architecture_info *arch_info;
struct drgn_platform *platform;
SWITCH_ENUM(arch) {
case DRGN_ARCH_UNKNOWN:
arch_info = &arch_info_unknown;
break;
case DRGN_ARCH_X86_64:
arch_info = &arch_info_x86_64;
break;
case DRGN_ARCH_I386:
arch_info = &arch_info_i386;
break;
case DRGN_ARCH_AARCH64:
arch_info = &arch_info_aarch64;
break;
case DRGN_ARCH_ARM:
arch_info = &arch_info_arm;
break;
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;
case DRGN_ARCH_S390X:
arch_info = &arch_info_s390x;
break;
case DRGN_ARCH_S390:
arch_info = &arch_info_s390;
break;
default:
return drgn_error_create(DRGN_ERROR_INVALID_ARGUMENT,
"invalid architecture");
}
if (flags == DRGN_PLATFORM_DEFAULT_FLAGS) {
if (arch == DRGN_ARCH_UNKNOWN) {
return drgn_error_create(DRGN_ERROR_INVALID_ARGUMENT,
"cannot get default platform flags of unknown architecture");
}
flags = arch_info->default_flags;
} else if (flags & ~DRGN_ALL_PLATFORM_FLAGS) {
return drgn_error_create(DRGN_ERROR_INVALID_ARGUMENT,
"invalid platform flags");
}
platform = malloc(sizeof(*platform));
if (!platform)
return &drgn_enomem;
platform->arch = arch_info;
platform->flags = flags;
*ret = platform;
return NULL;
}
LIBDRGN_PUBLIC void drgn_platform_destroy(struct drgn_platform *platform)
{
free(platform);
}
LIBDRGN_PUBLIC enum drgn_architecture
drgn_platform_arch(const struct drgn_platform *platform)
{
return platform->arch->arch;
}
LIBDRGN_PUBLIC enum drgn_platform_flags
drgn_platform_flags(const struct drgn_platform *platform)
{
return platform->flags;
}
LIBDRGN_PUBLIC bool drgn_platform_eq(struct drgn_platform *a,
struct drgn_platform *b)
{
return a->arch == b->arch && a->flags == b->flags;
}
void drgn_platform_from_arch(const struct drgn_architecture_info *arch,
bool is_64_bit, bool is_little_endian,
struct drgn_platform *ret)
{
ret->arch = arch;
ret->flags = (arch->default_flags &
~(DRGN_PLATFORM_IS_64_BIT | DRGN_PLATFORM_IS_LITTLE_ENDIAN));
if (is_64_bit)
ret->flags |= DRGN_PLATFORM_IS_64_BIT;
if (is_little_endian)
ret->flags |= DRGN_PLATFORM_IS_LITTLE_ENDIAN;
}
void drgn_platform_from_elf(GElf_Ehdr *ehdr, struct drgn_platform *ret)
{
const struct drgn_architecture_info *arch;
switch (ehdr->e_machine) {
case EM_X86_64:
arch = &arch_info_x86_64;
break;
case EM_386:
arch = &arch_info_i386;
break;
case EM_AARCH64:
arch = &arch_info_aarch64;
break;
case EM_ARM:
arch = &arch_info_arm;
break;
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;
case EM_S390:
if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
arch = &arch_info_s390x;
else
arch = &arch_info_s390;
break;
default:
arch = &arch_info_unknown;
break;
}
drgn_platform_from_arch(arch, ehdr->e_ident[EI_CLASS] == ELFCLASS64,
ehdr->e_ident[EI_DATA] == ELFDATA2LSB, ret);
}
LIBDRGN_PUBLIC size_t
drgn_platform_num_registers(const struct drgn_platform *platform)
{
return platform->arch->num_registers;
}
LIBDRGN_PUBLIC const struct drgn_register *
drgn_platform_register(const struct drgn_platform *platform, size_t n)
{
return &platform->arch->registers[n];
}
LIBDRGN_PUBLIC const struct drgn_register *
drgn_platform_register_by_name(const struct drgn_platform *platform,
const char *name)
{
return platform->arch->register_by_name(name);
}
LIBDRGN_PUBLIC const char * const *
drgn_register_names(const struct drgn_register *reg, size_t *num_names_ret)
{
*num_names_ret = reg->num_names;
return reg->names;
}
struct drgn_error drgn_invalid_relocation_offset = {
.code = DRGN_ERROR_OTHER,
.message = "invalid relocation offset",
};
#define DEFINE_DRGN_RELOC_ADD(bits) \
struct drgn_error * \
drgn_reloc_add##bits(const struct drgn_relocating_section *relocating, \
uint64_t r_offset, const int64_t *r_addend, \
uint##bits##_t addend) \
{ \
uint##bits##_t value; \
if (r_offset > relocating->buf_size || \
relocating->buf_size - r_offset < sizeof(value)) \
return &drgn_invalid_relocation_offset; \
if (r_addend) { \
value = *r_addend; \
} else { \
memcpy(&value, relocating->buf + r_offset, sizeof(value)); \
if (relocating->bswap) \
value = bswap_##bits(value); \
} \
value += addend; \
if (relocating->bswap) \
value = bswap_##bits(value); \
memcpy(relocating->buf + r_offset, &value, sizeof(value)); \
return NULL; \
}
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
|