Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
18 changes: 12 additions & 6 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -56,23 +56,27 @@ Installation

.. start-install-dependencies

.. highlight:: console

Install dependencies:

Arch Linux::
Arch Linux:

.. code-block:: console

$ sudo pacman -S --needed autoconf automake bison bzip2 flex gawk gcc libtool make pkgconf python python-setuptools xz zlib

Debian/Ubuntu::
Debian/Ubuntu:

.. code-block:: console

$ sudo apt-get install autoconf automake bison flex gawk gcc libbz2-dev liblzma-dev libtool make pkgconf python3 python3-dev python3-setuptools zlib1g-dev

Note that Debian Stretch, Ubuntu Trusty, and Ubuntu Xenial (and older) ship
Python versions which are too old. Python 3.6 or newer must be installed
manually.

Fedora::
Fedora:

.. code-block:: console

$ sudo dnf install autoconf automake bison bzip2-devel flex gawk gcc libtool make pkgconf python3 python3-devel python3-setuptools xz-devel zlib-devel

Expand All @@ -83,7 +87,9 @@ Optionally, install:

.. end-install-dependencies

Then, run::
Then, run:

.. code-block:: console

$ sudo pip3 install drgn

Expand Down
1 change: 1 addition & 0 deletions _drgn.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -1643,4 +1643,5 @@ def _linux_helper_find_pid(ns, pid): ...
def _linux_helper_pid_task(pid, pid_type): ...
def _linux_helper_find_task(ns, pid): ...
def _linux_helper_task_state_to_char(task): ...
def _linux_helper_kaslr_offset(prog): ...
def _linux_helper_pgtable_l5_enabled(prog): ...
2 changes: 1 addition & 1 deletion docs/advanced_usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ The core functionality of drgn is implemented in C and is available as a C
library, ``libdrgn``. See |drgn.h|_.

.. |drgn.h| replace:: ``drgn.h``
.. _drgn.h: https://github.com/osandov/drgn/blob/master/libdrgn/drgn.h
.. _drgn.h: https://github.com/osandov/drgn/blob/master/libdrgn/drgn.h.in

Full documentation can be generated by running ``doxygen`` in the ``libdrgn``
directory of the source code. Note that the API and ABI are not yet stable.
Expand Down
37 changes: 37 additions & 0 deletions drgn/helpers/linux/boot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Copyright (c) Facebook, Inc. and its affiliates.
# SPDX-License-Identifier: GPL-3.0+

"""
Boot
----

The ``drgn.helpers.linux.boot`` module provides helpers for inspecting the
Linux kernel boot configuration.
"""

from _drgn import _linux_helper_kaslr_offset, _linux_helper_pgtable_l5_enabled


__all__ = (
"kaslr_offset",
"pgtable_l5_enabled",
)


def kaslr_offset(prog):
"""
.. c:function:: unsigned long kaslr_offset(void)

Get the kernel address space layout randomization offset (zero if it is
disabled).
"""
return _linux_helper_kaslr_offset(prog)


def pgtable_l5_enabled(prog):
"""
.. c:function:: bool pgtable_l5_enabled(void)

Return whether 5-level paging is enabled.
"""
return _linux_helper_pgtable_l5_enabled(prog)
12 changes: 1 addition & 11 deletions drgn/helpers/linux/mm.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

from typing import List

from _drgn import _linux_helper_read_vm, _linux_helper_pgtable_l5_enabled
from _drgn import _linux_helper_read_vm
from drgn import Object, cast


Expand All @@ -26,21 +26,11 @@
"page_to_virt",
"pfn_to_page",
"pfn_to_virt",
"pgtable_l5_enabled",
"virt_to_page",
"virt_to_pfn",
)


def pgtable_l5_enabled(prog):
"""
.. c:function:: bool pgtable_l5_enabled(void)

Return whether 5-level paging is enabled.
"""
return _linux_helper_pgtable_l5_enabled(prog)


def for_each_page(prog):
"""
Iterate over all pages in the system.
Expand Down
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/configure.ac
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
dnl Copyright (c) Facebook, Inc. and its affiliates.
dnl SPDX-License-Identifier: GPL-3.0+

AC_INIT([drgn], [0.0.5],
AC_INIT([drgn], [0.0.7],
[https://github.com/osandov/drgn/issues],,
[https://github.com/osandov/drgn])

Expand Down
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
Loading