Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
3028da4
libdrgn: compare language in drgn_type_eq()
osandov Jul 9, 2020
f1eaf5b
libdrgn: add load_debug_info example program
osandov Jul 10, 2020
fee716a
Merge branch 'refs/heads/upstream-HEAD' into repo-HEAD
Jul 11, 2020
c840072
libdrgn: make drgn_object_set_buffer() take a void *
osandov Jul 13, 2020
213c148
libdrgn: dwarf_info_cache: handle DW_AT_endianity
osandov Jul 13, 2020
6d4af7e
libdrgn: dwarf_info_cache: handle variables DW_AT_const_value
osandov Jul 13, 2020
e85d250
Merge branch 'refs/heads/upstream-HEAD' into repo-HEAD
Jul 14, 2020
209eaee
setup.py: import setuptools before distutils
osandov Jul 18, 2020
2409868
libdrgn: hash_table: define chunk alignment constant
osandov Jul 17, 2020
2eab47c
libdrgn: hash_table: use posix_memalign() instead of aligned_alloc()
osandov Jul 16, 2020
9ea11a7
libdrgn: hash_table: port reserve optimization
osandov Jul 16, 2020
f94b026
libdrgn: hash_table: implement vector storage policy
osandov Jul 18, 2020
e7f353c
libdrgn: hash_table: clean up coding style
osandov Jul 18, 2020
c774529
Merge branch 'refs/heads/upstream-HEAD' into repo-HEAD
Jul 19, 2020
27e73fb
docs: fix broken link to drgn.h
osandov Jul 27, 2020
d45aafe
vmtest: manage: remove 3.16 blacklist
osandov Jul 27, 2020
d118fda
vmtest: check that downloaded file is not truncated
osandov Jul 27, 2020
e330976
helpers: add kaslr_offset() and move pgtable_l5_enabled()
osandov Jul 27, 2020
0259898
drgn 0.0.6
osandov Jul 28, 2020
b22d151
Merge branch 'refs/heads/upstream-HEAD' into repo-HEAD
Jul 28, 2020
9f3fadd
README: use code-block instead of highlight
osandov Jul 28, 2020
20bcde1
drgn 0.0.7
osandov Jul 28, 2020
b8a657a
Merge branch 'refs/heads/upstream-HEAD' into repo-HEAD
Jul 29, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion libdrgn/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ drgn.h: configure.ac build-aux/gen_drgn_h.awk build-aux/parse_arch.awk $(ARCH_IN
-v version=@PACKAGE_VERSION@ \
$(wordlist 4, $(words $^), $^) > $@

elfutils_LIBS = elfutils/libdw/libdw.a elfutils/libelf/libelf.a -lz -llzma -lbz2
elfutils_LIBS = elfutils/libdw/libdw.a elfutils/libelf/libelf.a -lz -llzma -lbz2 -ldl

lib_LTLIBRARIES = libdrgn.la

Expand Down Expand Up @@ -142,3 +142,8 @@ python/docstrings.h: ../_drgn.pyi $(drgndoc_docstrings_deps)

EXTRA_DIST = $(ARCH_INS) build-aux/gen_arch.awk build-aux/gen_constants.py \
build-aux/gen_drgn_h.awk build-aux/parse_arch.awk

EXTRA_PROGRAMS = examples/load_debug_info

examples_load_debug_info_SOURCES = examples/load_debug_info.c
examples_load_debug_info_LDADD = libdrgnimpl.la $(elfutils_LIBS)
2 changes: 1 addition & 1 deletion libdrgn/drgn.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -1807,7 +1807,7 @@ drgn_object_set_float(struct drgn_object *res,
struct drgn_error *
drgn_object_set_buffer(struct drgn_object *res,
struct drgn_qualified_type qualified_type,
const char *buf, uint8_t bit_offset,
const void *buf, uint8_t bit_offset,
uint64_t bit_field_size,
enum drgn_byte_order byte_order);

Expand Down
168 changes: 143 additions & 25 deletions libdrgn/dwarf_info_cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "dwarf_index.h"
#include "dwarf_info_cache.h"
#include "hash_table.h"
#include "object.h"
#include "object_index.h"
#include "type_index.h"
#include "vector.h"
Expand Down Expand Up @@ -58,6 +59,63 @@ static void drgn_dwarf_type_free(struct drgn_dwarf_type *dwarf_type)
}
}

/**
* Return whether a DWARF DIE is little-endian.
*
* @param[in] check_attr Whether to check the DW_AT_endianity attribute. If @c
* false, only the ELF header is checked and this function cannot fail.
* @return @c NULL on success, non-@c NULL on error.
*/
static struct drgn_error *dwarf_die_is_little_endian(Dwarf_Die *die,
bool check_attr, bool *ret)
{
Dwarf_Attribute endianity_attr_mem, *endianity_attr;
Dwarf_Word endianity;
if (check_attr &&
(endianity_attr = dwarf_attr_integrate(die, DW_AT_endianity,
&endianity_attr_mem))) {
if (dwarf_formudata(endianity_attr, &endianity)) {
return drgn_error_create(DRGN_ERROR_OTHER,
"invalid DW_AT_endianity");
}
} else {
endianity = DW_END_default;
}
switch (endianity) {
case DW_END_default: {
Elf *elf = dwarf_getelf(dwarf_cu_getdwarf(die->cu));
*ret = elf_getident(elf, NULL)[EI_DATA] == ELFDATA2LSB;
return NULL;
}
case DW_END_little:
*ret = true;
return NULL;
case DW_END_big:
*ret = false;
return NULL;
default:
return drgn_error_create(DRGN_ERROR_OTHER,
"unknown DW_AT_endianity");
}
}

/** Like dwarf_die_is_little_endian(), but returns a @ref drgn_byte_order. */
static struct drgn_error *dwarf_die_byte_order(Dwarf_Die *die,
bool check_attr,
enum drgn_byte_order *ret)
{
bool little_endian;
struct drgn_error *err = dwarf_die_is_little_endian(die, check_attr,
&little_endian);
/*
* dwarf_die_is_little_endian() can't fail if check_attr is false, so
* the !check_attr test suppresses maybe-uninitialized warnings.
*/
if (!err || !check_attr)
*ret = little_endian ? DRGN_LITTLE_ENDIAN : DRGN_BIG_ENDIAN;
return err;
}

static int dwarf_type(Dwarf_Die *die, Dwarf_Die *ret)
{
Dwarf_Attribute attr_mem;
Expand Down Expand Up @@ -618,7 +676,8 @@ drgn_compound_type_from_dwarf(struct drgn_dwarf_info_cache *dicache,
goto err;
}

bool little_endian = dwarf_die_is_little_endian(die);
bool little_endian;
dwarf_die_is_little_endian(die, false, &little_endian);
Dwarf_Die child;
int r = dwarf_child(die, &child);
while (r == 0) {
Expand Down Expand Up @@ -1453,52 +1512,111 @@ drgn_object_from_dwarf_subprogram(struct drgn_dwarf_info_cache *dicache,
Dwarf_Die *die, uint64_t bias,
const char *name, struct drgn_object *ret)
{
struct drgn_error *err;
struct drgn_qualified_type qualified_type;
Dwarf_Addr low_pc;

err = drgn_type_from_dwarf(dicache, die, &qualified_type);
struct drgn_error *err = drgn_type_from_dwarf(dicache, die,
&qualified_type);
if (err)
return err;
Dwarf_Addr low_pc;
if (dwarf_lowpc(die, &low_pc) == -1) {
return drgn_error_format(DRGN_ERROR_LOOKUP,
"could not find address of '%s'",
name);
}
enum drgn_byte_order byte_order;
dwarf_die_byte_order(die, false, &byte_order);
return drgn_object_set_reference(ret, qualified_type, low_pc + bias, 0,
0, dwarf_die_byte_order(die));
0, byte_order);
}

static struct drgn_error *
drgn_object_from_dwarf_constant(struct drgn_dwarf_info_cache *dicache,
Dwarf_Die *die,
struct drgn_qualified_type qualified_type,
Dwarf_Attribute *attr, struct drgn_object *ret)
{
struct drgn_object_type type;
enum drgn_object_kind kind;
uint64_t bit_size;
struct drgn_error *err = drgn_object_set_common(qualified_type, 0,
&type, &kind,
&bit_size);
if (err)
return err;
Dwarf_Block block;
if (dwarf_formblock(attr, &block) == 0) {
bool little_endian;
err = dwarf_die_is_little_endian(die, true, &little_endian);
if (err)
return err;
if (block.length < drgn_value_size(bit_size, 0)) {
return drgn_error_create(DRGN_ERROR_OTHER,
"DW_AT_const_value block is too small");
}
return drgn_object_set_buffer_internal(ret, &type, kind,
bit_size, block.data, 0,
little_endian);
} else if (kind == DRGN_OBJECT_SIGNED) {
Dwarf_Sword svalue;
if (dwarf_formsdata(attr, &svalue)) {
return drgn_error_create(DRGN_ERROR_OTHER,
"invalid DW_AT_const_value");
}
return drgn_object_set_signed_internal(ret, &type, bit_size,
svalue);
} else if (kind == DRGN_OBJECT_UNSIGNED) {
Dwarf_Word uvalue;
if (dwarf_formudata(attr, &uvalue)) {
return drgn_error_create(DRGN_ERROR_OTHER,
"invalid DW_AT_const_value");
}
return drgn_object_set_unsigned_internal(ret, &type, bit_size,
uvalue);
} else {
return drgn_error_create(DRGN_ERROR_OTHER,
"unknown DW_AT_const_value form");
}
}

static struct drgn_error *
drgn_object_from_dwarf_variable(struct drgn_dwarf_info_cache *dicache,
Dwarf_Die *die, uint64_t bias, const char *name,
struct drgn_object *ret)
{
struct drgn_error *err;
struct drgn_qualified_type qualified_type;
Dwarf_Attribute attr_mem;
Dwarf_Attribute *attr;
Dwarf_Op *loc;
size_t nloc;

err = drgn_type_from_dwarf_child(dicache, die, NULL, "DW_TAG_variable",
true, true, NULL, &qualified_type);
struct drgn_error *err = drgn_type_from_dwarf_child(dicache, die, NULL,
"DW_TAG_variable",
true, true, NULL,
&qualified_type);
if (err)
return err;
if (!(attr = dwarf_attr_integrate(die, DW_AT_location, &attr_mem))) {
Dwarf_Attribute attr_mem, *attr;
if ((attr = dwarf_attr_integrate(die, DW_AT_location, &attr_mem))) {
Dwarf_Op *loc;
size_t nloc;
if (dwarf_getlocation(attr, &loc, &nloc))
return drgn_error_libdw();
if (nloc != 1 || loc[0].atom != DW_OP_addr) {
return drgn_error_create(DRGN_ERROR_OTHER,
"DW_AT_location has unimplemented operation");
}
enum drgn_byte_order byte_order;
err = dwarf_die_byte_order(die, true, &byte_order);
if (err)
return err;
return drgn_object_set_reference(ret, qualified_type,
loc[0].number + bias, 0, 0,
byte_order);
} else if ((attr = dwarf_attr_integrate(die, DW_AT_const_value,
&attr_mem))) {
return drgn_object_from_dwarf_constant(dicache, die,
qualified_type, attr,
ret);
} else {
return drgn_error_format(DRGN_ERROR_LOOKUP,
"could not find address of '%s'",
"could not find address or value of '%s'",
name);
}
if (dwarf_getlocation(attr, &loc, &nloc))
return drgn_error_libdw();
if (nloc != 1 || loc[0].atom != DW_OP_addr) {
return drgn_error_create(DRGN_ERROR_OTHER,
"DW_AT_location has unimplemented operation");
}
return drgn_object_set_reference(ret, qualified_type,
loc[0].number + bias, 0, 0,
dwarf_die_byte_order(die));
}

struct drgn_error *
Expand Down
90 changes: 90 additions & 0 deletions libdrgn/examples/load_debug_info.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include "drgn.h"

static void usage(bool error)
{
fprintf(error ? stderr : stdout,
"usage: load_debug_info [-k|-c CORE|-p PID]\n"
"\n"
"Example libdrgn program that loads default debug information\n"
"\n"
"Options:\n"
" -k, --kernel debug the running kernel (default)\n"
" -c PATH, --core PATH debug the given core dump\n"
" -p PID, --pid PID debug the running process with the given PID\n"
" -h, --help display this help message and exit\n");
exit(error ? EXIT_FAILURE : EXIT_SUCCESS);
}

int main(int argc, char **argv)
{
struct option long_options[] = {
{"kernel", no_argument, NULL, 'k'},
{"core", required_argument, NULL, 'c'},
{"pid", required_argument, NULL, 'p'},
{"help", no_argument, NULL, 'h'},
{},
};
bool kernel = false;
const char *core = NULL;
const char *pid = NULL;
for (;;) {
int c = getopt_long(argc, argv, "kc:p:h", long_options, NULL);
if (c == -1)
break;
switch (c) {
case 'k':
kernel = true;
break;
case 'c':
core = optarg;
break;
case 'p':
pid = optarg;
break;
case 'h':
usage(false);
default:
usage(true);
}
}
if (optind != argc || kernel + !!core + !!pid > 1)
usage(true);

struct drgn_program *prog;
struct drgn_error *err = drgn_program_create(NULL, &prog);
if (err) {
prog = NULL;
goto out;
}

if (core)
err = drgn_program_set_core_dump(prog, core);
else if (pid)
err = drgn_program_set_pid(prog, atoi(pid) ?: getpid());
else
err = drgn_program_set_kernel(prog);
if (err)
goto out;

err = drgn_program_load_debug_info(prog, NULL, 0, true, true);

out:;
int status;
if (err) {
if (err->code == DRGN_ERROR_MISSING_DEBUG_INFO)
status = EXIT_SUCCESS;
else
status = EXIT_FAILURE;
drgn_error_fwrite(stderr, err);
drgn_error_destroy(err);
} else {
status = EXIT_SUCCESS;
}
drgn_program_destroy(prog);
return status;
}
Loading