diff --git a/README.rst b/README.rst index 3f6d8edc3..6fc8d8330 100644 --- a/README.rst +++ b/README.rst @@ -125,7 +125,7 @@ License .. start-license -Copyright 2018-2020 Omar Sandoval +Copyright (c) Facebook, Inc. and its affiliates. drgn is licensed under the `GPLv3 `_ or later. diff --git a/_drgn.pyi b/_drgn.pyi index 0e1c69aa3..2d9de196f 100644 --- a/_drgn.pyi +++ b/_drgn.pyi @@ -1,4 +1,4 @@ -# Copyright 2018-2020 - Omar Sandoval +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ """ @@ -611,14 +611,14 @@ class Object: language. For example, adding two objects from a program written in C results in an object with a type and value according to the rules of C: - >>> Object(prog, 'unsigned long', value=2**64 - 1) + Object(prog, 'int', value=1) + >>> Object(prog, 'unsigned long', 2**64 - 1) + Object(prog, 'int', 1) Object(prog, 'unsigned long', value=0) If only one operand to a binary operator is an object, the other operand will be converted to an object according to the language's rules for literals: - >>> Object(prog, 'char', value=0) - 1 + >>> Object(prog, 'char', 0) - 1 Object(prog, 'int', value=-1) The standard :class:`int() `, :class:`float() `, and @@ -640,9 +640,9 @@ class Object: :param prog: The program to create this object in. :param type: The type of the object. If omitted, this is deduced from *value* according to the language's rules for literals. + :param value: The value of this object. See :meth:`value_()`. :param address: The address of this object in the program. Either this or *value* must be given, but not both. - :param value: The value of this object. See :meth:`value_()`. :param byteorder: Byte order of the object. This should be ``'little'`` or ``'big'``. The default is ``None``, which indicates the program byte order. This must be ``None`` for primitive values. @@ -657,9 +657,9 @@ class Object: self, prog: Program, type: Union[str, Type, None] = None, + value: Any = None, *, address: Optional[int] = None, - value: Any = None, byteorder: Optional[str] = None, bit_offset: Optional[int] = None, bit_field_size: Optional[int] = None, @@ -935,7 +935,7 @@ def NULL(prog: Program, type: Union[str, Type]) -> Object: """ Get an object representing ``NULL`` casted to the given type. - This is equivalent to ``Object(prog, type, value=0)``. + This is equivalent to ``Object(prog, type, 0)``. :param prog: The program. :param type: The type. diff --git a/docs/exts/drgndoc/docstrings.py b/docs/exts/drgndoc/docstrings.py index ef2b2012e..a5a6d7270 100644 --- a/docs/exts/drgndoc/docstrings.py +++ b/docs/exts/drgndoc/docstrings.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# Copyright 2018-2020 - Omar Sandoval +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ import argparse diff --git a/docs/exts/drgndoc/ext.py b/docs/exts/drgndoc/ext.py index a19ef8f52..5d6779f75 100644 --- a/docs/exts/drgndoc/ext.py +++ b/docs/exts/drgndoc/ext.py @@ -1,4 +1,4 @@ -# Copyright 2020 - Omar Sandoval +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ """ diff --git a/docs/exts/drgndoc/format.py b/docs/exts/drgndoc/format.py index fb7e6fa2d..efa162887 100644 --- a/docs/exts/drgndoc/format.py +++ b/docs/exts/drgndoc/format.py @@ -1,4 +1,4 @@ -# Copyright 2020 - Omar Sandoval +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ import ast diff --git a/docs/exts/drgndoc/namespace.py b/docs/exts/drgndoc/namespace.py index af2d04e7f..cf2602853 100644 --- a/docs/exts/drgndoc/namespace.py +++ b/docs/exts/drgndoc/namespace.py @@ -1,4 +1,4 @@ -# Copyright 2020 - Omar Sandoval +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ import itertools diff --git a/docs/exts/drgndoc/parse.py b/docs/exts/drgndoc/parse.py index 72436919f..4b272cfbc 100644 --- a/docs/exts/drgndoc/parse.py +++ b/docs/exts/drgndoc/parse.py @@ -1,4 +1,4 @@ -# Copyright 2020 - Omar Sandoval +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ import ast diff --git a/docs/exts/drgndoc/util.py b/docs/exts/drgndoc/util.py index 5fef80818..7c0f2b8e3 100644 --- a/docs/exts/drgndoc/util.py +++ b/docs/exts/drgndoc/util.py @@ -1,4 +1,4 @@ -# Copyright 2020 - Omar Sandoval +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ from typing import Optional diff --git a/docs/exts/drgndoc/visitor.py b/docs/exts/drgndoc/visitor.py index d2c0cb3ec..e8a5085b4 100644 --- a/docs/exts/drgndoc/visitor.py +++ b/docs/exts/drgndoc/visitor.py @@ -1,4 +1,4 @@ -# Copyright 2020 - Omar Sandoval +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ import ast diff --git a/drgn/__init__.py b/drgn/__init__.py index 7bf30ba2e..69f87611d 100644 --- a/drgn/__init__.py +++ b/drgn/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2018-2020 - Omar Sandoval +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ """ diff --git a/drgn/__main__.py b/drgn/__main__.py index f9e207a93..f8898c636 100644 --- a/drgn/__main__.py +++ b/drgn/__main__.py @@ -1,4 +1,4 @@ -# Copyright 2018-2019 - Omar Sandoval +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ """ diff --git a/drgn/helpers/__init__.py b/drgn/helpers/__init__.py index 3321a868f..e60a5683a 100644 --- a/drgn/helpers/__init__.py +++ b/drgn/helpers/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2018-2020 - Omar Sandoval +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ """ diff --git a/drgn/helpers/linux/__init__.py b/drgn/helpers/linux/__init__.py index d8715ce93..cbdd6ee7a 100644 --- a/drgn/helpers/linux/__init__.py +++ b/drgn/helpers/linux/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2018-2019 - Omar Sandoval +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ """ diff --git a/drgn/helpers/linux/block.py b/drgn/helpers/linux/block.py index 1dbee7156..061c8af1c 100644 --- a/drgn/helpers/linux/block.py +++ b/drgn/helpers/linux/block.py @@ -1,4 +1,4 @@ -# Copyright 2018-2020 - Omar Sandoval +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ """ diff --git a/drgn/helpers/linux/bpf.py b/drgn/helpers/linux/bpf.py index 1d9bd1357..291c28cba 100644 --- a/drgn/helpers/linux/bpf.py +++ b/drgn/helpers/linux/bpf.py @@ -1,3 +1,4 @@ +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ """ diff --git a/drgn/helpers/linux/cgroup.py b/drgn/helpers/linux/cgroup.py index 6c3d37d06..c492136e0 100644 --- a/drgn/helpers/linux/cgroup.py +++ b/drgn/helpers/linux/cgroup.py @@ -1,3 +1,4 @@ +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ """ diff --git a/drgn/helpers/linux/cpumask.py b/drgn/helpers/linux/cpumask.py index d4a003e6b..4d9a55508 100644 --- a/drgn/helpers/linux/cpumask.py +++ b/drgn/helpers/linux/cpumask.py @@ -1,4 +1,4 @@ -# Copyright 2018-2019 - Omar Sandoval +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ """ diff --git a/drgn/helpers/linux/device.py b/drgn/helpers/linux/device.py index e6bfd14cf..f339ec2d6 100644 --- a/drgn/helpers/linux/device.py +++ b/drgn/helpers/linux/device.py @@ -1,4 +1,4 @@ -# Copyright 2018-2019 - Omar Sandoval +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ """ diff --git a/drgn/helpers/linux/fs.py b/drgn/helpers/linux/fs.py index dd9741ed5..5d30a7205 100644 --- a/drgn/helpers/linux/fs.py +++ b/drgn/helpers/linux/fs.py @@ -1,4 +1,4 @@ -# Copyright 2018-2020 - Omar Sandoval +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ """ diff --git a/drgn/helpers/linux/idr.py b/drgn/helpers/linux/idr.py index 3cdcd4f76..76bd521c5 100644 --- a/drgn/helpers/linux/idr.py +++ b/drgn/helpers/linux/idr.py @@ -1,4 +1,4 @@ -# Copyright 2018-2019 - Omar Sandoval +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ """ diff --git a/drgn/helpers/linux/kconfig.py b/drgn/helpers/linux/kconfig.py index 406152297..5baf58b27 100644 --- a/drgn/helpers/linux/kconfig.py +++ b/drgn/helpers/linux/kconfig.py @@ -1,3 +1,4 @@ +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ """ diff --git a/drgn/helpers/linux/kernfs.py b/drgn/helpers/linux/kernfs.py index ce795b200..33c68d4a1 100644 --- a/drgn/helpers/linux/kernfs.py +++ b/drgn/helpers/linux/kernfs.py @@ -1,3 +1,4 @@ +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ """ diff --git a/drgn/helpers/linux/list.py b/drgn/helpers/linux/list.py index 3c0012678..d29e06f66 100644 --- a/drgn/helpers/linux/list.py +++ b/drgn/helpers/linux/list.py @@ -1,4 +1,4 @@ -# Copyright 2018-2019 - Omar Sandoval +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ """ diff --git a/drgn/helpers/linux/list_nulls.py b/drgn/helpers/linux/list_nulls.py index 39fa4400e..51a490762 100644 --- a/drgn/helpers/linux/list_nulls.py +++ b/drgn/helpers/linux/list_nulls.py @@ -1,3 +1,4 @@ +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ """ diff --git a/drgn/helpers/linux/mm.py b/drgn/helpers/linux/mm.py index 78f64fc65..38d5ed712 100644 --- a/drgn/helpers/linux/mm.py +++ b/drgn/helpers/linux/mm.py @@ -1,4 +1,4 @@ -# Copyright 2018-2020 - Omar Sandoval +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ """ diff --git a/drgn/helpers/linux/net.py b/drgn/helpers/linux/net.py index fb01f5a4f..4a8e406e4 100644 --- a/drgn/helpers/linux/net.py +++ b/drgn/helpers/linux/net.py @@ -1,3 +1,4 @@ +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ """ diff --git a/drgn/helpers/linux/percpu.py b/drgn/helpers/linux/percpu.py index 896f595a0..1b97d7b3e 100644 --- a/drgn/helpers/linux/percpu.py +++ b/drgn/helpers/linux/percpu.py @@ -1,4 +1,4 @@ -# Copyright 2018-2019 - Omar Sandoval +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ """ diff --git a/drgn/helpers/linux/pid.py b/drgn/helpers/linux/pid.py index d9c98967b..1ff744f19 100644 --- a/drgn/helpers/linux/pid.py +++ b/drgn/helpers/linux/pid.py @@ -1,4 +1,4 @@ -# Copyright 2018-2019 - Omar Sandoval +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ """ diff --git a/drgn/helpers/linux/radixtree.py b/drgn/helpers/linux/radixtree.py index 78ef42555..2796c6bbc 100644 --- a/drgn/helpers/linux/radixtree.py +++ b/drgn/helpers/linux/radixtree.py @@ -1,4 +1,4 @@ -# Copyright 2018-2019 - Omar Sandoval +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ """ diff --git a/drgn/helpers/linux/rbtree.py b/drgn/helpers/linux/rbtree.py index a70555f72..ee33e468b 100644 --- a/drgn/helpers/linux/rbtree.py +++ b/drgn/helpers/linux/rbtree.py @@ -1,4 +1,4 @@ -# Copyright 2018-2019 - Omar Sandoval +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ """ diff --git a/drgn/helpers/linux/sched.py b/drgn/helpers/linux/sched.py index d746c3a6b..85fdd74e9 100644 --- a/drgn/helpers/linux/sched.py +++ b/drgn/helpers/linux/sched.py @@ -1,4 +1,4 @@ -# Copyright 2019 - Omar Sandoval +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ """ diff --git a/drgn/helpers/linux/tcp.py b/drgn/helpers/linux/tcp.py index f1f82e438..63c32ced2 100644 --- a/drgn/helpers/linux/tcp.py +++ b/drgn/helpers/linux/tcp.py @@ -1,3 +1,4 @@ +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ """ diff --git a/drgn/helpers/linux/user.py b/drgn/helpers/linux/user.py index a91555979..d6edfc57e 100644 --- a/drgn/helpers/linux/user.py +++ b/drgn/helpers/linux/user.py @@ -1,4 +1,4 @@ -# Copyright 2020 - Omar Sandoval +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ """ diff --git a/drgn/internal/__init__.py b/drgn/internal/__init__.py index 2f38da76c..300b85ebc 100644 --- a/drgn/internal/__init__.py +++ b/drgn/internal/__init__.py @@ -1,4 +1,4 @@ -# Copyright 2018-2019 - Omar Sandoval +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ """ diff --git a/drgn/internal/cli.py b/drgn/internal/cli.py index 3c8fd9d07..de6dd93c3 100644 --- a/drgn/internal/cli.py +++ b/drgn/internal/cli.py @@ -1,4 +1,4 @@ -# Copyright 2018-2019 - Omar Sandoval +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ """drgn command line interface""" diff --git a/drgn/internal/rlcompleter.py b/drgn/internal/rlcompleter.py index a117ad92e..0684276c2 100644 --- a/drgn/internal/rlcompleter.py +++ b/drgn/internal/rlcompleter.py @@ -1,4 +1,4 @@ -# Copyright 2018-2019 - Omar Sandoval +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ """Improved readline completer""" diff --git a/examples/linux/cgroup.py b/examples/linux/cgroup.py index 6859f2a81..3d85bb1d1 100755 --- a/examples/linux/cgroup.py +++ b/examples/linux/cgroup.py @@ -1,3 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ + """List the paths of all descendants of a cgroup v2""" import os diff --git a/examples/linux/fs_inodes.py b/examples/linux/fs_inodes.py index fb25a8333..081c6854b 100755 --- a/examples/linux/fs_inodes.py +++ b/examples/linux/fs_inodes.py @@ -1,3 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ + """List the paths of all inodes cached in a given filesystem""" from drgn.helpers.linux.fs import for_each_mount, inode_path diff --git a/examples/linux/lsmod.py b/examples/linux/lsmod.py index 3036ab5f5..b7fef922a 100755 --- a/examples/linux/lsmod.py +++ b/examples/linux/lsmod.py @@ -1,3 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ + """An implementation of lsmod(8) using drgn""" from drgn.helpers.linux.list import list_for_each_entry diff --git a/examples/linux/ps.py b/examples/linux/ps.py index e5644426d..45adfc7c8 100755 --- a/examples/linux/ps.py +++ b/examples/linux/ps.py @@ -1,3 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ + """A simplified implementation of ps(1) using drgn""" from drgn.helpers.linux.pid import for_each_task diff --git a/examples/linux/tcp_sock.py b/examples/linux/tcp_sock.py index 76220c25c..438146908 100755 --- a/examples/linux/tcp_sock.py +++ b/examples/linux/tcp_sock.py @@ -1,3 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ + """List all TCP sockets and their cgroup v2 paths""" import ipaddress diff --git a/libdrgn/Makefile.am b/libdrgn/Makefile.am index 0a86f2e28..74a0128ad 100644 --- a/libdrgn/Makefile.am +++ b/libdrgn/Makefile.am @@ -1,3 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ + ACLOCAL_AMFLAGS = -I m4 SUBDIRS = elfutils include diff --git a/libdrgn/arch_x86_64.c.in b/libdrgn/arch_x86_64.c.in index e0a41ddd1..a64a5d15d 100644 --- a/libdrgn/arch_x86_64.c.in +++ b/libdrgn/arch_x86_64.c.in @@ -1,5 +1,5 @@ %{ -// Copyright 2019-2020 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #include @@ -107,25 +107,76 @@ bnd2 bnd3 %% -static const struct drgn_frame_register frame_registers_x86_64[] = { - { DRGN_REGISTER_X86_64_rax, 8, 192, "ax", "rax", }, - { DRGN_REGISTER_X86_64_rdx, 8, 208, "dx", "rdx", }, - { DRGN_REGISTER_X86_64_rcx, 8, 200, "cx", "rcx", }, - { DRGN_REGISTER_X86_64_rbx, 8, 152, "bx", "rbx", }, - { DRGN_REGISTER_X86_64_rsi, 8, 216, "si", "rsi", }, - { DRGN_REGISTER_X86_64_rdi, 8, 224, "di", "rdi", }, - { DRGN_REGISTER_X86_64_rbp, 8, 144, "bp", "rbp", }, - { DRGN_REGISTER_X86_64_rsp, 8, 264, "sp", "rsp", }, - { DRGN_REGISTER_X86_64_r8, 8, 184, "r8", }, - { DRGN_REGISTER_X86_64_r9, 8, 176, "r9", }, - { DRGN_REGISTER_X86_64_r10, 8, 168, "r10", }, - { DRGN_REGISTER_X86_64_r11, 8, 160, "r11", }, - { DRGN_REGISTER_X86_64_r12, 8, 136, "r12", }, - { DRGN_REGISTER_X86_64_r13, 8, 128, "r13", }, - { DRGN_REGISTER_X86_64_r14, 8, 120, "r14", }, - { DRGN_REGISTER_X86_64_r15, 8, 112, "r15", }, - { DRGN_REGISTER_X86_64_rip, 8, 240, "ip", "rip", }, -}; +/* + * The in-kernel struct pt_regs, UAPI struct pt_regs, elf_gregset_t, and struct + * user_regs_struct all have the same layout. + */ +static struct drgn_error * +set_initial_registers_from_struct_x86_64(Dwfl_Thread *thread, const void *regs, + size_t size, bool bswap) +{ + Dwarf_Word dwarf_regs[17]; + + if (size < 160) { + return drgn_error_create(DRGN_ERROR_INVALID_ARGUMENT, + "registers are truncated"); + } + +#define READ_REGISTER(n) ({ \ + uint64_t reg; \ + memcpy(®, (uint64_t *)regs + n, sizeof(reg)); \ + bswap ? bswap_64(reg) : reg; \ +}) + dwarf_regs[0] = READ_REGISTER(10); /* rax */ + dwarf_regs[1] = READ_REGISTER(12); /* rdx */ + dwarf_regs[2] = READ_REGISTER(11); /* rcx */ + dwarf_regs[3] = READ_REGISTER(5); /* rbx */ + dwarf_regs[4] = READ_REGISTER(13); /* rsi */ + dwarf_regs[5] = READ_REGISTER(14); /* rdi */ + dwarf_regs[6] = READ_REGISTER(4); /* rbp */ + dwarf_regs[7] = READ_REGISTER(19); /* rsp */ + dwarf_regs[8] = READ_REGISTER(9); /* r8 */ + dwarf_regs[9] = READ_REGISTER(8); /* r9 */ + dwarf_regs[10] = READ_REGISTER(7); /* r10 */ + dwarf_regs[11] = READ_REGISTER(6); /* r11 */ + dwarf_regs[12] = READ_REGISTER(3); /* r12 */ + dwarf_regs[13] = READ_REGISTER(2); /* r13 */ + dwarf_regs[14] = READ_REGISTER(1); /* r14 */ + dwarf_regs[15] = READ_REGISTER(0); /* r15 */ + dwarf_regs[16] = READ_REGISTER(16); /* rip */ +#undef READ_REGISTER + + if (!dwfl_thread_state_registers(thread, 0, 17, dwarf_regs)) + return drgn_error_libdwfl(); + return NULL; +} + +static struct drgn_error * +pt_regs_set_initial_registers_x86_64(Dwfl_Thread *thread, + const struct drgn_object *obj) +{ + bool bswap = (obj->value.little_endian != + (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)); + return set_initial_registers_from_struct_x86_64(thread, + drgn_object_buffer(obj), + drgn_buffer_object_size(obj), + bswap); +} + +static struct drgn_error * +prstatus_set_initial_registers_x86_64(struct drgn_program *prog, + Dwfl_Thread *thread, const void *prstatus, + size_t size) +{ + if (size < 112) { + return drgn_error_create(DRGN_ERROR_INVALID_ARGUMENT, + "NT_PRSTATUS is truncated"); + } + return set_initial_registers_from_struct_x86_64(thread, + (char *)prstatus + 112, + size - 112, + drgn_program_bswap(prog)); +} static inline struct drgn_error *read_register(struct drgn_object *reg_obj, struct drgn_object *frame_obj, @@ -206,7 +257,9 @@ out: static struct drgn_error * linux_kernel_set_initial_registers_x86_64(Dwfl_Thread *thread, - const struct drgn_object *task_obj) + const struct drgn_object *task_obj, + const void *prstatus, + size_t prstatus_size) { struct drgn_error *err; struct drgn_program *prog = task_obj->prog; @@ -217,8 +270,44 @@ linux_kernel_set_initial_registers_x86_64(Dwfl_Thread *thread, drgn_object_init(&sp_obj, prog); - /* - */ + if (prstatus) { + /* + * If the stack pointer in PRSTATUS is within this task's stack, + * then we can use it. Otherwise, the task either wasn't running + * or was in the middle of context switching. Either way, we + * should use the saved registers instead. + */ + uint64_t thread_size; + uint64_t stack; + + err = linux_kernel_get_thread_size(prog, &thread_size); + if (err) + goto out; + err = drgn_object_member_dereference(&sp_obj, task_obj, + "stack"); + if (err) + goto out; + err = drgn_object_read_unsigned(&sp_obj, &stack); + if (err) + goto out; + + if (prstatus_size < 272) { + err = drgn_error_create(DRGN_ERROR_INVALID_ARGUMENT, + "registers are truncated"); + goto out; + } + memcpy(&sp, (char *)prstatus + 264, sizeof(sp)); + if (drgn_program_bswap(prog)) + sp = bswap_64(sp); + if (sp > stack && sp <= stack + thread_size) { + err = prstatus_set_initial_registers_x86_64(prog, + thread, + prstatus, + prstatus_size); + goto out; + } + } + err = drgn_object_member_dereference(&sp_obj, task_obj, "thread"); if (err) goto out; @@ -485,8 +574,8 @@ const struct drgn_architecture_info arch_info_x86_64 = { ARCHITECTURE_INFO, .default_flags = (DRGN_PLATFORM_IS_64_BIT | DRGN_PLATFORM_IS_LITTLE_ENDIAN), - .frame_registers = frame_registers_x86_64, - .num_frame_registers = ARRAY_SIZE(frame_registers_x86_64), + .pt_regs_set_initial_registers = pt_regs_set_initial_registers_x86_64, + .prstatus_set_initial_registers = prstatus_set_initial_registers_x86_64, .linux_kernel_set_initial_registers = linux_kernel_set_initial_registers_x86_64, .linux_kernel_get_page_offset = linux_kernel_get_page_offset_x86_64, diff --git a/libdrgn/binary_search_tree.h b/libdrgn/binary_search_tree.h index 09f261295..0fa378435 100644 --- a/libdrgn/binary_search_tree.h +++ b/libdrgn/binary_search_tree.h @@ -1,4 +1,4 @@ -// Copyright 2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ /** diff --git a/libdrgn/build-aux/gen_arch.awk b/libdrgn/build-aux/gen_arch.awk index fcae8f91b..b808c5225 100644 --- a/libdrgn/build-aux/gen_arch.awk +++ b/libdrgn/build-aux/gen_arch.awk @@ -1,4 +1,4 @@ -# Copyright 2019 - Omar Sandoval +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ # This script generates "arch_foo.c" from "arch_foo.c.in". It uses diff --git a/libdrgn/build-aux/gen_constants.py b/libdrgn/build-aux/gen_constants.py index ba5b6b6bd..354ae78f5 100644 --- a/libdrgn/build-aux/gen_constants.py +++ b/libdrgn/build-aux/gen_constants.py @@ -1,4 +1,4 @@ -# Copyright 2018-2019 - Omar Sandoval +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ import os.path diff --git a/libdrgn/build-aux/gen_drgn_h.awk b/libdrgn/build-aux/gen_drgn_h.awk index 3aa1d41ce..e06690b15 100644 --- a/libdrgn/build-aux/gen_drgn_h.awk +++ b/libdrgn/build-aux/gen_drgn_h.awk @@ -1,4 +1,4 @@ -# Copyright 2019 - Omar Sandoval +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ # This script generates "drgn.h" from "drgn.h.in" and all of the diff --git a/libdrgn/build-aux/parse_arch.awk b/libdrgn/build-aux/parse_arch.awk index 0148fbac8..d23d40a8b 100644 --- a/libdrgn/build-aux/parse_arch.awk +++ b/libdrgn/build-aux/parse_arch.awk @@ -1,4 +1,4 @@ -# Copyright 2019 - Omar Sandoval +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ # This script parses the architecture support files in drgn (arch_foo.c.in). diff --git a/libdrgn/cityhash.h b/libdrgn/cityhash.h index c2bb4fb3b..95b2dbf67 100644 --- a/libdrgn/cityhash.h +++ b/libdrgn/cityhash.h @@ -1,4 +1,4 @@ -// Copyright 2018-2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #ifndef DRGN_CITYHASH_H diff --git a/libdrgn/configure.ac b/libdrgn/configure.ac index b4ed56c10..e13ea2242 100644 --- a/libdrgn/configure.ac +++ b/libdrgn/configure.ac @@ -1,3 +1,6 @@ +dnl Copyright (c) Facebook, Inc. and its affiliates. +dnl SPDX-License-Identifier: GPL-3.0+ + AC_INIT([drgn], [0.0.4], [https://github.com/osandov/drgn/issues],, [https://github.com/osandov/drgn]) diff --git a/libdrgn/drgn.h.in b/libdrgn/drgn.h.in index da0596139..cc435c46a 100644 --- a/libdrgn/drgn.h.in +++ b/libdrgn/drgn.h.in @@ -1,4 +1,4 @@ -// Copyright 2018-2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ /** diff --git a/libdrgn/dwarf_index.c b/libdrgn/dwarf_index.c index 9b0ba5502..92d8798a7 100644 --- a/libdrgn/dwarf_index.c +++ b/libdrgn/dwarf_index.c @@ -1,4 +1,4 @@ -// Copyright 2018-2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #include diff --git a/libdrgn/dwarf_index.h b/libdrgn/dwarf_index.h index 86e6bdc10..da7a4f9f2 100644 --- a/libdrgn/dwarf_index.h +++ b/libdrgn/dwarf_index.h @@ -1,4 +1,4 @@ -// Copyright 2018-2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ /** diff --git a/libdrgn/dwarf_info_cache.c b/libdrgn/dwarf_info_cache.c index 1a97a3ef1..2292fe5bf 100644 --- a/libdrgn/dwarf_info_cache.c +++ b/libdrgn/dwarf_info_cache.c @@ -1,4 +1,4 @@ -// Copyright 2018-2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #include diff --git a/libdrgn/dwarf_info_cache.h b/libdrgn/dwarf_info_cache.h index 5b70a92b3..2d8a871c3 100644 --- a/libdrgn/dwarf_info_cache.h +++ b/libdrgn/dwarf_info_cache.h @@ -1,4 +1,4 @@ -// Copyright 2018-2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ /** diff --git a/libdrgn/elfutils/PATCHES b/libdrgn/elfutils/PATCHES index f7dbbb1ba..551dff7dd 100644 --- a/libdrgn/elfutils/PATCHES +++ b/libdrgn/elfutils/PATCHES @@ -1,4 +1,4 @@ -commit c26c6ddb435d87ceafdd8fb36fa99011119d6e3a +commit eaa481f284524d7f5d14f88dcf6cb62faeae5713 Author: Omar Sandoval Date: Mon Oct 7 01:30:35 2019 -0700 @@ -9,23 +9,23 @@ Date: Mon Oct 7 01:30:35 2019 -0700 pieces are in place, add dwfl_frame_eval_expr to provide this feature. diff --git a/libdw/libdw.map b/libdw/libdw.map -index 5f5946cb1..b4fa63631 100644 +index f4134e318a..25ae8b6e6c 100644 --- a/libdw/libdw.map +++ b/libdw/libdw.map @@ -377,4 +377,5 @@ ELFUTILS_0.180 { + dwfl_frame_register; dwfl_frame_module; dwfl_frame_dwarf_frame; - dwfl_frame_register; + dwfl_frame_eval_expr; } ELFUTILS_0.177; diff --git a/libdwfl/frame_unwind.c b/libdwfl/frame_unwind.c -index 3984c65ce..4885caa13 100644 +index bbbd73add4..a6df269763 100644 --- a/libdwfl/frame_unwind.c +++ b/libdwfl/frame_unwind.c -@@ -814,3 +814,14 @@ out: - return state->frame; +@@ -837,3 +837,14 @@ __libdwfl_frame_unwind (Dwfl_Frame *state) + assert (state->unwound->pc_state == DWFL_FRAME_STATE_PC_SET); + state->unwound->signal_frame = signal_frame; } - INTDEF (dwfl_frame_dwarf_frame) + +bool +dwfl_frame_eval_expr (Dwfl_Frame *state, const Dwarf_Op *ops, size_t nops, @@ -38,7 +38,7 @@ index 3984c65ce..4885caa13 100644 + return expr_eval (state, frame, ops, nops, result, bias); +} diff --git a/libdwfl/libdwfl.h b/libdwfl/libdwfl.h -index fb261698e..1dc080c01 100644 +index fb261698ed..1dc080c01e 100644 --- a/libdwfl/libdwfl.h +++ b/libdwfl/libdwfl.h @@ -822,6 +822,12 @@ bool dwfl_frame_pc (Dwfl_Frame *state, Dwarf_Addr *pc, bool *isactivation) @@ -54,136 +54,7 @@ index fb261698e..1dc080c01 100644 #ifdef __cplusplus } #endif -commit b32da5a9a88543f144afd50a213afe6fe1d9b25d -Author: Omar Sandoval -Date: Thu Feb 20 11:44:38 2020 -0800 - - libdwfl: export __libdwfl_frame_reg_get as dwfl_frame_register - - This is useful for debuggers that want to dump register values. - -diff --git a/libdw/libdw.map b/libdw/libdw.map -index e0fe21156..5f5946cb1 100644 ---- a/libdw/libdw.map -+++ b/libdw/libdw.map -@@ -376,4 +376,5 @@ ELFUTILS_0.180 { - dwfl_detach_thread; - dwfl_frame_module; - dwfl_frame_dwarf_frame; -+ dwfl_frame_register; - } ELFUTILS_0.177; -diff --git a/libdwfl/frame_unwind.c b/libdwfl/frame_unwind.c -index 9ada2e550..3984c65ce 100644 ---- a/libdwfl/frame_unwind.c -+++ b/libdwfl/frame_unwind.c -@@ -44,8 +44,7 @@ - #define DWARF_EXPR_STEPS_MAX 0x1000 - - bool --internal_function --__libdwfl_frame_reg_get (Dwfl_Frame *state, unsigned regno, Dwarf_Addr *val) -+dwfl_frame_register (Dwfl_Frame *state, unsigned regno, Dwarf_Addr *val) - { - Ebl *ebl = state->thread->process->ebl; - if (! ebl_dwarf_to_regno (ebl, ®no)) -@@ -59,6 +58,7 @@ __libdwfl_frame_reg_get (Dwfl_Frame *state, unsigned regno, Dwarf_Addr *val) - *val = state->regs[regno]; - return true; - } -+INTDEF (dwfl_frame_register) - - bool - internal_function -@@ -81,7 +81,7 @@ __libdwfl_frame_reg_set (Dwfl_Frame *state, unsigned regno, Dwarf_Addr val) - static bool - state_get_reg (Dwfl_Frame *state, unsigned regno, Dwarf_Addr *val) - { -- if (! __libdwfl_frame_reg_get (state, regno, val)) -+ if (! INTUSE(dwfl_frame_register) (state, regno, val)) - { - __libdwfl_seterrno (DWFL_E_INVALID_REGISTER); - return false; -@@ -628,9 +628,9 @@ handle_cfi (Dwfl_Frame *state, Dwarf_Frame *frame, Dwarf_Addr bias) - } - if (unwound->pc_state == DWFL_FRAME_STATE_ERROR) - { -- if (__libdwfl_frame_reg_get (unwound, -- frame->fde->cie->return_address_register, -- &unwound->pc)) -+ if (INTUSE(dwfl_frame_register) (unwound, -+ frame->fde->cie->return_address_register, -+ &unwound->pc)) - { - /* PPC32 __libc_start_main properly CFI-unwinds PC as zero. - Currently none of the archs supported for unwinding have -@@ -687,7 +687,7 @@ getfunc (int firstreg, unsigned nregs, Dwarf_Word *regs, void *arg) - Dwfl_Frame *state = arg; - assert (firstreg >= 0); - while (nregs--) -- if (! __libdwfl_frame_reg_get (state, firstreg++, regs++)) -+ if (! INTUSE(dwfl_frame_register) (state, firstreg++, regs++)) - return false; - return true; - } -diff --git a/libdwfl/libdwfl.h b/libdwfl/libdwfl.h -index b494d4582..fb261698e 100644 ---- a/libdwfl/libdwfl.h -+++ b/libdwfl/libdwfl.h -@@ -817,6 +817,11 @@ int dwfl_getthread_frames (Dwfl *dwfl, pid_t tid, - bool dwfl_frame_pc (Dwfl_Frame *state, Dwarf_Addr *pc, bool *isactivation) - __nonnull_attribute__ (1, 2); - -+/* Return the *VALUE of register REGNO in frame STATE. VALUE may be NULL. -+ Returns false if the register value is unknown. */ -+bool dwfl_frame_register (Dwfl_Frame *state, unsigned regno, Dwarf_Addr *value) -+ __nonnull_attribute__ (1); -+ - #ifdef __cplusplus - } - #endif -diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h -index 90d509ece..613ccf016 100644 ---- a/libdwfl/libdwflP.h -+++ b/libdwfl/libdwflP.h -@@ -283,12 +283,6 @@ struct Dwfl_Frame - Dwarf_Addr regs[]; - }; - --/* Fetch value from Dwfl_Frame->regs indexed by DWARF REGNO. -- No error code is set if the function returns FALSE. */ --bool __libdwfl_frame_reg_get (Dwfl_Frame *state, unsigned regno, -- Dwarf_Addr *val) -- internal_function; -- - /* Store value to Dwfl_Frame->regs indexed by DWARF REGNO. - No error code is set if the function returns FALSE. */ - bool __libdwfl_frame_reg_set (Dwfl_Frame *state, unsigned regno, -@@ -788,6 +782,7 @@ INTDECL (dwfl_getthread_frames) - INTDECL (dwfl_getthreads) - INTDECL (dwfl_thread_getframes) - INTDECL (dwfl_frame_pc) -+INTDECL (dwfl_frame_register) - - /* Leading arguments standard to callbacks passed a Dwfl_Module. */ - #define MODCB_ARGS(mod) (mod), &(mod)->userdata, (mod)->name, (mod)->low_addr -diff --git a/libdwfl/linux-core-attach.c b/libdwfl/linux-core-attach.c -index c0f1b0d00..d55312b6c 100644 ---- a/libdwfl/linux-core-attach.c -+++ b/libdwfl/linux-core-attach.c -@@ -253,10 +253,9 @@ core_set_initial_registers (Dwfl_Thread *thread, void *thread_arg_voidp) - /* PPC provides DWARF register 65 irrelevant for - CFI which clashes with register 108 (LR) we need. - LR (108) is provided earlier (in NT_PRSTATUS) than the # 65. -- FIXME: It depends now on their order in core notes. -- FIXME: It uses private function. */ -+ FIXME: It depends now on their order in core notes. */ - if (regno < nregs -- && __libdwfl_frame_reg_get (thread->unwound, regno, NULL)) -+ && INTUSE(dwfl_frame_register) (thread->unwound, regno, NULL)) - continue; - Dwarf_Word val; - switch (regloc->bits) -commit 1426c2a70c1748cd5a6f4e38410ae4e9796d3037 +commit 5a6524c0b89a71bc712ccab7fc801d12c429bcd5 Author: Omar Sandoval Date: Thu Feb 20 11:18:28 2020 -0800 @@ -199,18 +70,18 @@ Date: Thu Feb 20 11:18:28 2020 -0800 frame, so add dwfl_frame_module. diff --git a/libdw/libdw.map b/libdw/libdw.map -index c8961b3a6..e0fe21156 100644 +index 73f592c03e..f4134e318a 100644 --- a/libdw/libdw.map +++ b/libdw/libdw.map -@@ -374,4 +374,6 @@ ELFUTILS_0.180 { - global: +@@ -375,4 +375,6 @@ ELFUTILS_0.180 { dwfl_attach_thread; dwfl_detach_thread; + dwfl_frame_register; + dwfl_frame_module; + dwfl_frame_dwarf_frame; } ELFUTILS_0.177; diff --git a/libdwfl/dwfl_frame.c b/libdwfl/dwfl_frame.c -index 0ad28e0f5..046f6c2ba 100644 +index 61fad8b9cf..80f2bc1466 100644 --- a/libdwfl/dwfl_frame.c +++ b/libdwfl/dwfl_frame.c @@ -68,6 +68,13 @@ state_fetch_pc (Dwfl_Frame *state) @@ -244,10 +115,10 @@ index 0ad28e0f5..046f6c2ba 100644 + state->frame = NULL; + state->moderr = DWFL_E_NOERROR; + state->frameerr = DWFL_E_NOERROR; - state->isactivation = true; + state->signal_frame = false; + state->initial_frame = true; state->pc_state = DWFL_FRAME_STATE_ERROR; - memset (state->regs_set, 0, sizeof (state->regs_set)); -@@ -485,7 +496,7 @@ dwfl_thread_getframes (Dwfl_Thread *thread, +@@ -486,7 +497,7 @@ dwfl_thread_getframes (Dwfl_Thread *thread, if (! cache) { /* The old frame is no longer needed. */ @@ -257,7 +128,7 @@ index 0ad28e0f5..046f6c2ba 100644 state = next; } diff --git a/libdwfl/frame_unwind.c b/libdwfl/frame_unwind.c -index df755975e..9ada2e550 100644 +index f7459b283d..bbbd73add4 100644 --- a/libdwfl/frame_unwind.c +++ b/libdwfl/frame_unwind.c @@ -523,6 +523,10 @@ new_unwound (Dwfl_Frame *state) @@ -268,10 +139,10 @@ index df755975e..9ada2e550 100644 + unwound->frame = NULL; + unwound->moderr = DWFL_E_NOERROR; + unwound->frameerr = DWFL_E_NOERROR; - unwound->isactivation = false; + unwound->signal_frame = false; + unwound->initial_frame = false; unwound->pc_state = DWFL_FRAME_STATE_ERROR; - memset (unwound->regs_set, 0, sizeof (unwound->regs_set)); -@@ -535,22 +539,9 @@ new_unwound (Dwfl_Frame *state) +@@ -536,22 +540,9 @@ new_unwound (Dwfl_Frame *state) later. Therefore we continue unwinding leaving the registers undefined. */ static void @@ -293,10 +164,10 @@ index df755975e..9ada2e550 100644 - } - + Dwfl_Frame *unwound = state->unwound; - if (frame->fde->cie->signal_frame) - { - state->isactivation = true; -@@ -668,7 +659,6 @@ handle_cfi (Dwfl_Frame *state, Dwarf_Addr pc, Dwarf_CFI *cfi, Dwarf_Addr bias) + unwound->signal_frame = frame->fde->cie->signal_frame; + Dwfl_Thread *thread = state->thread; + Dwfl_Process *process = thread->process; +@@ -665,7 +656,6 @@ handle_cfi (Dwfl_Frame *state, Dwarf_Addr pc, Dwarf_CFI *cfi, Dwarf_Addr bias) unwound->pc_state = DWFL_FRAME_STATE_PC_UNDEFINED; } } @@ -304,60 +175,18 @@ index df755975e..9ada2e550 100644 } static bool -@@ -724,28 +714,16 @@ __libdwfl_frame_unwind (Dwfl_Frame *state) - assert (ok); - if (! isactivation) - pc--; -- Dwfl_Module *mod = INTUSE(dwfl_addrmodule) (state->thread->process->dwfl, pc); -- if (mod == NULL) -- __libdwfl_seterrno (DWFL_E_NO_DWARF); -- else -+ Dwarf_Addr bias; -+ Dwarf_Frame *frame = INTUSE(dwfl_frame_dwarf_frame) (state, &bias); -+ if (frame != NULL) - { -- Dwarf_Addr bias; -- Dwarf_CFI *cfi_eh = INTUSE(dwfl_module_eh_cfi) (mod, &bias); -- if (cfi_eh) -- { -- handle_cfi (state, pc - bias, cfi_eh, bias); -- if (state->unwound) -- return; -- } -- Dwarf_CFI *cfi_dwarf = INTUSE(dwfl_module_dwarf_cfi) (mod, &bias); -- if (cfi_dwarf) -- { -- handle_cfi (state, pc - bias, cfi_dwarf, bias); -- if (state->unwound) -- return; -- } -+ if (new_unwound (state) == NULL) -+ __libdwfl_seterrno (DWFL_E_NOMEM); -+ else -+ handle_cfi (state, frame, bias); -+ return; - } -- assert (state->unwound == NULL); - Dwfl_Thread *thread = state->thread; - Dwfl_Process *process = thread->process; - Ebl *ebl = process->ebl; -@@ -773,3 +751,66 @@ __libdwfl_frame_unwind (Dwfl_Frame *state) - state->unwound->isactivation = true; - } +@@ -709,6 +699,95 @@ readfunc (Dwarf_Addr addr, Dwarf_Word *datap, void *arg) + process->callbacks_arg); } -+ -+Dwfl_Module * -+dwfl_frame_module (Dwfl_Frame *state) + ++/* Internal version of dwfl_frame_module when we already know the PC. */ ++static Dwfl_Module * ++dwfl_frame_module_pc (Dwfl_Frame *state, Dwarf_Addr pc) +{ + if (state->mod != NULL) + return state->mod; + if (state->moderr == DWFL_E_NOERROR) + { -+ Dwarf_Addr pc; -+ bool isactivation; -+ INTUSE(dwfl_frame_pc) (state, &pc, &isactivation); -+ if (! isactivation) -+ pc--; + state->mod = INTUSE(dwfl_addrmodule) (state->thread->process->dwfl, pc); + if (state->mod != NULL) + return state->mod; @@ -366,33 +195,28 @@ index df755975e..9ada2e550 100644 + __libdwfl_seterrno (state->moderr); + return NULL; +} -+INTDEF (dwfl_frame_module) + -+Dwarf_Frame * -+dwfl_frame_dwarf_frame (Dwfl_Frame *state, Dwarf_Addr *bias) ++/* Internal version of dwfl_frame_dwarf_frame when we already know the PC. */ ++static Dwarf_Frame * ++dwfl_frame_dwarf_frame_pc (Dwfl_Frame *state, Dwarf_Addr pc, Dwarf_Addr *bias) +{ + if (state->frame == NULL) + { + if (state->frameerr == DWFL_E_NOERROR) + { -+ Dwfl_Module *mod = INTUSE(dwfl_frame_module) (state); ++ Dwfl_Module *mod = dwfl_frame_module_pc (state, pc); + if (mod == NULL) + { + state->frameerr = state->moderr; ++ /* errno is already set. */ + return NULL; + } -+ Dwarf_Addr pc; -+ bool isactivation; -+ INTUSE(dwfl_frame_pc) (state, &pc, &isactivation); -+ if (! isactivation) -+ pc--; -+ Dwarf_CFI *cfi = INTUSE(dwfl_module_eh_cfi) (state->mod, -+ &state->bias); ++ Dwarf_CFI *cfi = INTUSE(dwfl_module_eh_cfi) (mod, &state->bias); + if (cfi + && INTUSE(dwarf_cfi_addrframe) (cfi, pc - state->bias, + &state->frame) == 0) + goto out; -+ cfi = INTUSE(dwfl_module_dwarf_cfi) (state->mod, &state->bias); ++ cfi = INTUSE(dwfl_module_dwarf_cfi) (mod, &state->bias); + if (cfi + && INTUSE(dwarf_cfi_addrframe) (cfi, pc - state->bias, + &state->frame) == 0) @@ -407,9 +231,85 @@ index df755975e..9ada2e550 100644 + *bias = state->bias; + return state->frame; +} -+INTDEF (dwfl_frame_dwarf_frame) ++ ++Dwfl_Module * ++dwfl_frame_module (Dwfl_Frame *state) ++{ ++ if (state->mod != NULL) ++ return state->mod; ++ if (state->moderr == DWFL_E_NOERROR) ++ { ++ Dwarf_Addr pc; ++ bool isactivation; ++ INTUSE(dwfl_frame_pc) (state, &pc, &isactivation); ++ if (! isactivation) ++ pc--; ++ return dwfl_frame_module_pc (state, pc); ++ } ++ __libdwfl_seterrno (state->moderr); ++ return NULL; ++} ++ ++Dwarf_Frame * ++dwfl_frame_dwarf_frame (Dwfl_Frame *state, Dwarf_Addr *bias) ++{ ++ if (state->frame != NULL) ++ return state->frame; ++ if (state->frameerr == DWFL_E_NOERROR) ++ { ++ Dwarf_Addr pc; ++ bool isactivation; ++ INTUSE(dwfl_frame_pc) (state, &pc, &isactivation); ++ if (! isactivation) ++ pc--; ++ return dwfl_frame_dwarf_frame_pc (state, pc, bias); ++ } ++ __libdwfl_seterrno (state->frameerr); ++ return NULL; ++} ++ + void + internal_function + __libdwfl_frame_unwind (Dwfl_Frame *state) +@@ -724,28 +803,16 @@ __libdwfl_frame_unwind (Dwfl_Frame *state) + Then we need to unwind from the original, unadjusted PC. */ + if (! state->initial_frame && ! state->signal_frame) + pc--; +- Dwfl_Module *mod = INTUSE(dwfl_addrmodule) (state->thread->process->dwfl, pc); +- if (mod == NULL) +- __libdwfl_seterrno (DWFL_E_NO_DWARF); +- else ++ Dwarf_Addr bias; ++ Dwarf_Frame *frame = dwfl_frame_dwarf_frame_pc (state, pc, &bias); ++ if (frame != NULL) + { +- Dwarf_Addr bias; +- Dwarf_CFI *cfi_eh = INTUSE(dwfl_module_eh_cfi) (mod, &bias); +- if (cfi_eh) +- { +- handle_cfi (state, pc - bias, cfi_eh, bias); +- if (state->unwound) +- return; +- } +- Dwarf_CFI *cfi_dwarf = INTUSE(dwfl_module_dwarf_cfi) (mod, &bias); +- if (cfi_dwarf) +- { +- handle_cfi (state, pc - bias, cfi_dwarf, bias); +- if (state->unwound) +- return; +- } ++ if (new_unwound (state) == NULL) ++ __libdwfl_seterrno (DWFL_E_NOMEM); ++ else ++ handle_cfi (state, frame, bias); ++ return; + } +- assert (state->unwound == NULL); + Dwfl_Thread *thread = state->thread; + Dwfl_Process *process = thread->process; + Ebl *ebl = process->ebl; diff --git a/libdwfl/libdwfl.h b/libdwfl/libdwfl.h -index 4167ef7ad..b494d4582 100644 +index 639ed186b6..fb261698ed 100644 --- a/libdwfl/libdwfl.h +++ b/libdwfl/libdwfl.h @@ -738,6 +738,16 @@ pid_t dwfl_thread_tid (Dwfl_Thread *thread) @@ -430,7 +330,7 @@ index 4167ef7ad..b494d4582 100644 For every known continuous block of registers +Date: Thu Feb 20 11:44:38 2020 -0800 + + libdwfl: export __libdwfl_frame_reg_get as dwfl_frame_register + + This is useful for debuggers that want to dump register values. + +diff --git a/libdw/libdw.map b/libdw/libdw.map +index c8961b3a6a..73f592c03e 100644 +--- a/libdw/libdw.map ++++ b/libdw/libdw.map +@@ -374,4 +374,5 @@ ELFUTILS_0.180 { + global: + dwfl_attach_thread; + dwfl_detach_thread; ++ dwfl_frame_register; + } ELFUTILS_0.177; +diff --git a/libdwfl/frame_unwind.c b/libdwfl/frame_unwind.c +index d7dfa5a94b..f7459b283d 100644 +--- a/libdwfl/frame_unwind.c ++++ b/libdwfl/frame_unwind.c +@@ -44,8 +44,7 @@ + #define DWARF_EXPR_STEPS_MAX 0x1000 + + bool +-internal_function +-__libdwfl_frame_reg_get (Dwfl_Frame *state, unsigned regno, Dwarf_Addr *val) ++dwfl_frame_register (Dwfl_Frame *state, unsigned regno, Dwarf_Addr *val) + { + Ebl *ebl = state->thread->process->ebl; + if (! ebl_dwarf_to_regno (ebl, ®no)) +@@ -59,6 +58,7 @@ __libdwfl_frame_reg_get (Dwfl_Frame *state, unsigned regno, Dwarf_Addr *val) + *val = state->regs[regno]; + return true; + } ++INTDEF (dwfl_frame_register) + + bool + internal_function +@@ -81,7 +81,7 @@ __libdwfl_frame_reg_set (Dwfl_Frame *state, unsigned regno, Dwarf_Addr val) + static bool + state_get_reg (Dwfl_Frame *state, unsigned regno, Dwarf_Addr *val) + { +- if (! __libdwfl_frame_reg_get (state, regno, val)) ++ if (! INTUSE(dwfl_frame_register) (state, regno, val)) + { + __libdwfl_seterrno (DWFL_E_INVALID_REGISTER); + return false; +@@ -634,9 +634,9 @@ handle_cfi (Dwfl_Frame *state, Dwarf_Addr pc, Dwarf_CFI *cfi, Dwarf_Addr bias) + } + if (unwound->pc_state == DWFL_FRAME_STATE_ERROR) + { +- if (__libdwfl_frame_reg_get (unwound, +- frame->fde->cie->return_address_register, +- &unwound->pc)) ++ if (INTUSE(dwfl_frame_register) (unwound, ++ frame->fde->cie->return_address_register, ++ &unwound->pc)) + { + /* PPC32 __libc_start_main properly CFI-unwinds PC as zero. + Currently none of the archs supported for unwinding have +@@ -694,7 +694,7 @@ getfunc (int firstreg, unsigned nregs, Dwarf_Word *regs, void *arg) + Dwfl_Frame *state = arg; + assert (firstreg >= 0); + while (nregs--) +- if (! __libdwfl_frame_reg_get (state, firstreg++, regs++)) ++ if (! INTUSE(dwfl_frame_register) (state, firstreg++, regs++)) + return false; + return true; + } +diff --git a/libdwfl/libdwfl.h b/libdwfl/libdwfl.h +index 4167ef7ad8..639ed186b6 100644 +--- a/libdwfl/libdwfl.h ++++ b/libdwfl/libdwfl.h +@@ -807,6 +807,11 @@ int dwfl_getthread_frames (Dwfl *dwfl, pid_t tid, + bool dwfl_frame_pc (Dwfl_Frame *state, Dwarf_Addr *pc, bool *isactivation) + __nonnull_attribute__ (1, 2); + ++/* Return the *VALUE of register REGNO in frame STATE. VALUE may be NULL. ++ Returns false if the register value is unknown. */ ++bool dwfl_frame_register (Dwfl_Frame *state, unsigned regno, Dwarf_Addr *value) ++ __nonnull_attribute__ (1); ++ + #ifdef __cplusplus + } + #endif +diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h +index bc088861ff..4ae7c0b3ba 100644 +--- a/libdwfl/libdwflP.h ++++ b/libdwfl/libdwflP.h +@@ -275,12 +275,6 @@ struct Dwfl_Frame + Dwarf_Addr regs[]; + }; + +-/* Fetch value from Dwfl_Frame->regs indexed by DWARF REGNO. +- No error code is set if the function returns FALSE. */ +-bool __libdwfl_frame_reg_get (Dwfl_Frame *state, unsigned regno, +- Dwarf_Addr *val) +- internal_function; +- + /* Store value to Dwfl_Frame->regs indexed by DWARF REGNO. + No error code is set if the function returns FALSE. */ + bool __libdwfl_frame_reg_set (Dwfl_Frame *state, unsigned regno, +@@ -778,6 +772,7 @@ INTDECL (dwfl_getthread_frames) + INTDECL (dwfl_getthreads) + INTDECL (dwfl_thread_getframes) + INTDECL (dwfl_frame_pc) ++INTDECL (dwfl_frame_register) + + /* Leading arguments standard to callbacks passed a Dwfl_Module. */ + #define MODCB_ARGS(mod) (mod), &(mod)->userdata, (mod)->name, (mod)->low_addr +diff --git a/libdwfl/linux-core-attach.c b/libdwfl/linux-core-attach.c +index c0f1b0d004..d55312b6cd 100644 +--- a/libdwfl/linux-core-attach.c ++++ b/libdwfl/linux-core-attach.c +@@ -253,10 +253,9 @@ core_set_initial_registers (Dwfl_Thread *thread, void *thread_arg_voidp) + /* PPC provides DWARF register 65 irrelevant for + CFI which clashes with register 108 (LR) we need. + LR (108) is provided earlier (in NT_PRSTATUS) than the # 65. +- FIXME: It depends now on their order in core notes. +- FIXME: It uses private function. */ ++ FIXME: It depends now on their order in core notes. */ + if (regno < nregs +- && __libdwfl_frame_reg_get (thread->unwound, regno, NULL)) ++ && INTUSE(dwfl_frame_register) (thread->unwound, regno, NULL)) + continue; + Dwarf_Word val; + switch (regloc->bits) +commit 5ea774858ed9d25f308ccb147f3f430e2b0f8599 Author: Omar Sandoval Date: Mon Oct 7 01:22:39 2019 -0700 @@ -474,7 +494,7 @@ Date: Mon Oct 7 01:22:39 2019 -0700 possible to use the frames after dwfl_thread_getframes returns. diff --git a/libdw/libdw.map b/libdw/libdw.map -index decac05c7..c8961b3a6 100644 +index decac05c7c..c8961b3a6a 100644 --- a/libdw/libdw.map +++ b/libdw/libdw.map @@ -370,3 +370,8 @@ ELFUTILS_0.177 { @@ -487,10 +507,10 @@ index decac05c7..c8961b3a6 100644 + dwfl_detach_thread; +} ELFUTILS_0.177; diff --git a/libdwfl/dwfl_frame.c b/libdwfl/dwfl_frame.c -index d5043cbbe..0ad28e0f5 100644 +index 5bbf850e8e..61fad8b9cf 100644 --- a/libdwfl/dwfl_frame.c +++ b/libdwfl/dwfl_frame.c -@@ -102,6 +102,29 @@ state_alloc (Dwfl_Thread *thread) +@@ -103,6 +103,29 @@ state_alloc (Dwfl_Thread *thread) return state; } @@ -520,7 +540,7 @@ index d5043cbbe..0ad28e0f5 100644 void internal_function __libdwfl_process_free (Dwfl_Process *process) -@@ -365,6 +388,45 @@ getthread (Dwfl *dwfl, pid_t tid, +@@ -366,6 +389,45 @@ getthread (Dwfl *dwfl, pid_t tid, return err; } @@ -566,7 +586,7 @@ index d5043cbbe..0ad28e0f5 100644 struct one_thread { int (*callback) (Dwfl_Frame *frame, void *arg); -@@ -393,63 +455,55 @@ dwfl_thread_getframes (Dwfl_Thread *thread, +@@ -394,63 +456,55 @@ dwfl_thread_getframes (Dwfl_Thread *thread, int (*callback) (Dwfl_Frame *state, void *arg), void *arg) { @@ -664,7 +684,7 @@ index d5043cbbe..0ad28e0f5 100644 } INTDEF(dwfl_thread_getframes) diff --git a/libdwfl/libdwfl.h b/libdwfl/libdwfl.h -index d5fa06d47..4167ef7ad 100644 +index d5fa06d476..4167ef7ad8 100644 --- a/libdwfl/libdwfl.h +++ b/libdwfl/libdwfl.h @@ -763,6 +763,18 @@ int dwfl_getthreads (Dwfl *dwfl, @@ -687,7 +707,7 @@ index d5fa06d47..4167ef7ad 100644 have been processed by the callback, returns -1 on error, or the value of the callback when not DWARF_CB_OK. -1 returned on error will diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h -index 332349d32..ed8239c92 100644 +index 25753de2f8..bc088861ff 100644 --- a/libdwfl/libdwflP.h +++ b/libdwfl/libdwflP.h @@ -239,7 +239,8 @@ struct Dwfl_Thread @@ -700,213 +720,7 @@ index 332349d32..ed8239c92 100644 Dwfl_Frame *unwound; void *callbacks_arg; }; -commit a1f60f2e2794859c7767b0b003efb20e3e018904 -Author: Omar Sandoval -Date: Wed May 13 14:18:12 2020 -0700 - - libdwfl: simplify activation frame logic - - When calling a noreturn function, the compiler may omit any code after - the call instruction. As a result, the return address on the stack may - not lie in the FDE for the caller. It might even lie in another symbol. - In the following example, the return address for the _Exit call in foo - is actually the first instruction of bar. - - 0000000000001149 : - 1149: 50 push %rax - 114a: bf 01 00 00 00 mov $0x1,%edi - 114f: e8 dc fe ff ff callq 1030 <_Exit@plt> - - 0000000000001154 : - 1154: b8 37 13 00 00 mov $0x1337,%eax - 1159: c3 retq - - To handle this, libdwfl (and GDB, for that matter) decrements the - program counter when looking up the debugging information for a frame. - - There are two important exceptions. The first is the initial (i.e., - innermost) frame. This is typically supplied by ptrace or a PRSTATUS - note, which contains the exact trapped PC. libdwfl calls this case an - "activation" and doesn't decrement the PC. - - The second exception is signal handling. When a signal is received, the - kernel creates a special signal stack frame so that when the signal - handler returns, it returns to the signal trampoline code responsible - for resuming execution (see sigreturn(2)). - - The return address from the signal frame is the exact interrupted - instruction. Therefore, the interrupted frame (that is, the outer frame - of a signal frame) is also considered an activation. - - The signal frame itself is also considered an activation frame, since - the return address points directly to the signal trampoline. However, - determining that a frame is a signal frame requires looking up the FDE. - To solve this chicken and egg problem, the signal trampoline is padded - so that the debugger can still find the FDE even if it decrements PC - (see [1]). This means that during the initial lookup, we can assume it's - not an activation, and then fix it up after the fact. - - libdwfl annotates the interrupted frame (NB, not the signal frame) with - Dwfl_Frame::signal_frame. dwfl_frame_pc returns that a frame is an - activation if it is the interrupted frame, or if its outer frame is the - interrupted frame (which means it is the signal frame). This requires - unwinding the frame, so when the unwinding code calls dwfl_frame_pc, it - has to open-code the logic for determining whether the activation frame - check. - - This can all be made a lot simpler by instead directly tracking whether - a Dwfl_Frame is an activation frame. This replaces - Dwfl_Frame::initial_frame and Dwfl_Frame::signal_frame with - Dwfl_Frame::isactivation. We set isactivation to true for the initial - frame, the signal frame, and the interrupted frame. - - 1: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/entry/vdso/vdso32/sigreturn.S?h=v5.6#n54 - -diff --git a/libdwfl/dwfl_frame.c b/libdwfl/dwfl_frame.c -index 5bbf850e8..d5043cbbe 100644 ---- a/libdwfl/dwfl_frame.c -+++ b/libdwfl/dwfl_frame.c -@@ -94,8 +94,7 @@ state_alloc (Dwfl_Thread *thread) - if (state == NULL) - return NULL; - state->thread = thread; -- state->signal_frame = false; -- state->initial_frame = true; -+ state->isactivation = true; - state->pc_state = DWFL_FRAME_STATE_ERROR; - memset (state->regs_set, 0, sizeof (state->regs_set)); - thread->unwound = state; -diff --git a/libdwfl/dwfl_frame_pc.c b/libdwfl/dwfl_frame_pc.c -index 296c815b9..a955d995a 100644 ---- a/libdwfl/dwfl_frame_pc.c -+++ b/libdwfl/dwfl_frame_pc.c -@@ -39,26 +39,7 @@ dwfl_frame_pc (Dwfl_Frame *state, Dwarf_Addr *pc, bool *isactivation) - *pc = state->pc; - ebl_normalize_pc (state->thread->process->ebl, pc); - if (isactivation) -- { -- /* Bottom frame? */ -- if (state->initial_frame) -- *isactivation = true; -- /* *ISACTIVATION is logical union of whether current or previous frame -- state is SIGNAL_FRAME. */ -- else if (state->signal_frame) -- *isactivation = true; -- else -- { -- /* If the previous frame has unwound unsuccessfully just silently do -- not consider it could be a SIGNAL_FRAME. */ -- __libdwfl_frame_unwind (state); -- if (state->unwound == NULL -- || state->unwound->pc_state != DWFL_FRAME_STATE_PC_SET) -- *isactivation = false; -- else -- *isactivation = state->unwound->signal_frame; -- } -- } -+ *isactivation = state->isactivation; - return true; - } - INTDEF (dwfl_frame_pc) -diff --git a/libdwfl/dwfl_frame_regs.c b/libdwfl/dwfl_frame_regs.c -index 83b1abef1..d013dc966 100644 ---- a/libdwfl/dwfl_frame_regs.c -+++ b/libdwfl/dwfl_frame_regs.c -@@ -38,7 +38,6 @@ dwfl_thread_state_registers (Dwfl_Thread *thread, int firstreg, - { - Dwfl_Frame *state = thread->unwound; - assert (state && state->unwound == NULL); -- assert (state->initial_frame); - for (unsigned regno = firstreg; regno < firstreg + nregs; regno++) - if (! __libdwfl_frame_reg_set (state, regno, regs[regno - firstreg])) - { -@@ -54,7 +53,6 @@ dwfl_thread_state_register_pc (Dwfl_Thread *thread, Dwarf_Word pc) - { - Dwfl_Frame *state = thread->unwound; - assert (state && state->unwound == NULL); -- assert (state->initial_frame); - state->pc = pc; - state->pc_state = DWFL_FRAME_STATE_PC_SET; - } -diff --git a/libdwfl/frame_unwind.c b/libdwfl/frame_unwind.c -index d7dfa5a94..df755975e 100644 ---- a/libdwfl/frame_unwind.c -+++ b/libdwfl/frame_unwind.c -@@ -523,8 +523,7 @@ new_unwound (Dwfl_Frame *state) - state->unwound = unwound; - unwound->thread = thread; - unwound->unwound = NULL; -- unwound->signal_frame = false; -- unwound->initial_frame = false; -+ unwound->isactivation = false; - unwound->pc_state = DWFL_FRAME_STATE_ERROR; - memset (unwound->regs_set, 0, sizeof (unwound->regs_set)); - return unwound; -@@ -552,7 +551,11 @@ handle_cfi (Dwfl_Frame *state, Dwarf_Addr pc, Dwarf_CFI *cfi, Dwarf_Addr bias) - return; - } - -- unwound->signal_frame = frame->fde->cie->signal_frame; -+ if (frame->fde->cie->signal_frame) -+ { -+ state->isactivation = true; -+ unwound->isactivation = true; -+ } - Dwfl_Thread *thread = state->thread; - Dwfl_Process *process = thread->process; - Ebl *ebl = process->ebl; -@@ -715,14 +718,11 @@ __libdwfl_frame_unwind (Dwfl_Frame *state) - { - if (state->unwound) - return; -- /* Do not ask dwfl_frame_pc for ISACTIVATION, it would try to unwind STATE -- which would deadlock us. */ - Dwarf_Addr pc; -- bool ok = INTUSE(dwfl_frame_pc) (state, &pc, NULL); -+ bool isactivation; -+ bool ok = INTUSE(dwfl_frame_pc) (state, &pc, &isactivation); - assert (ok); -- /* Check whether this is the initial frame or a signal frame. -- Then we need to unwind from the original, unadjusted PC. */ -- if (! state->initial_frame && ! state->signal_frame) -+ if (! isactivation) - pc--; - Dwfl_Module *mod = INTUSE(dwfl_addrmodule) (state->thread->process->dwfl, pc); - if (mod == NULL) -@@ -755,7 +755,6 @@ __libdwfl_frame_unwind (Dwfl_Frame *state) - return; - } - state->unwound->pc_state = DWFL_FRAME_STATE_PC_UNDEFINED; -- // &Dwfl_Frame.signal_frame cannot be passed as it is a bitfield. - bool signal_frame = false; - if (! ebl_unwind (ebl, pc, setfunc, getfunc, readfunc, state, &signal_frame)) - { -@@ -768,5 +767,9 @@ __libdwfl_frame_unwind (Dwfl_Frame *state) - return; - } - assert (state->unwound->pc_state == DWFL_FRAME_STATE_PC_SET); -- state->unwound->signal_frame = signal_frame; -+ if (signal_frame) -+ { -+ state->isactivation = true; -+ state->unwound->isactivation = true; -+ } - } -diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h -index 25753de2f..332349d32 100644 ---- a/libdwfl/libdwflP.h -+++ b/libdwfl/libdwflP.h -@@ -251,8 +251,7 @@ struct Dwfl_Frame - Dwfl_Thread *thread; - /* Previous (outer) frame. */ - Dwfl_Frame *unwound; -- bool signal_frame : 1; -- bool initial_frame : 1; -+ bool isactivation; - enum - { - /* This structure is still being initialized or there was an error -commit 148c39884329b1279c2fc4c63500f95b95205651 +commit 75ceb320352708c76a2f9a1c71e99d12322f75ea Author: Omar Sandoval Date: Wed Sep 4 17:13:40 2019 -0700 @@ -918,7 +732,7 @@ Date: Wed Sep 4 17:13:40 2019 -0700 build them from. diff --git a/backends/Makefile.am b/backends/Makefile.am -index f4052125b..1beb661eb 100644 +index f4052125bd..1beb661eb1 100644 --- a/backends/Makefile.am +++ b/backends/Makefile.am @@ -34,7 +34,10 @@ endif @@ -934,7 +748,7 @@ index f4052125b..1beb661eb 100644 modules = i386 sh x86_64 ia64 alpha arm aarch64 sparc ppc ppc64 s390 \ tilegx m68k bpf riscv csky diff --git a/configure.ac b/configure.ac -index 12ee2f97c..d68d1a1eb 100644 +index 12ee2f97c1..d68d1a1eb1 100644 --- a/configure.ac +++ b/configure.ac @@ -70,6 +70,11 @@ AC_ARG_ENABLE([programs], @@ -950,7 +764,7 @@ index 12ee2f97c..d68d1a1eb 100644 [AS_HELP_STRING([--enable-deterministic-archives], [ar and ranlib default to -D behavior])], [ diff --git a/debuginfod/Makefile.am b/debuginfod/Makefile.am -index e62e8d14b..a811e2dd1 100644 +index e62e8d14b0..a811e2dd1d 100644 --- a/debuginfod/Makefile.am +++ b/debuginfod/Makefile.am @@ -86,16 +86,20 @@ libdebuginfod.so$(EXEEXT): $(srcdir)/libdebuginfod.map $(libdebuginfod_so_LIBS) @@ -975,7 +789,7 @@ index e62e8d14b..a811e2dd1 100644 EXTRA_DIST = libdebuginfod.map diff --git a/libasm/Makefile.am b/libasm/Makefile.am -index b2bff9292..8a5a9d0f0 100644 +index b2bff92923..8a5a9d0f04 100644 --- a/libasm/Makefile.am +++ b/libasm/Makefile.am @@ -34,8 +34,10 @@ GCC_INCLUDE = -I$(shell $(CC) -print-file-name=include) @@ -1011,7 +825,7 @@ index b2bff9292..8a5a9d0f0 100644 noinst_HEADERS = libasmP.h symbolhash.h diff --git a/libcpu/Makefile.am b/libcpu/Makefile.am -index 59def7d1b..57dc698ed 100644 +index 59def7d1bc..57dc698ed3 100644 --- a/libcpu/Makefile.am +++ b/libcpu/Makefile.am @@ -38,7 +38,10 @@ LEXCOMPILE = $(LEX) $(LFLAGS) $(AM_LFLAGS) -P$( Date: Wed Sep 4 17:13:23 2019 -0700 @@ -1150,7 +964,7 @@ Date: Wed Sep 4 17:13:23 2019 -0700 still to build everything. diff --git a/Makefile.am b/Makefile.am -index bd8926b52..0b13c717f 100644 +index bd8926b523..0b13c717fa 100644 --- a/Makefile.am +++ b/Makefile.am @@ -27,7 +27,11 @@ AM_MAKEFLAGS = --no-print-directory @@ -1167,7 +981,7 @@ index bd8926b52..0b13c717f 100644 if DEBUGINFOD SUBDIRS += debuginfod diff --git a/configure.ac b/configure.ac -index a39e800f7..12ee2f97c 100644 +index a39e800f70..12ee2f97c1 100644 --- a/configure.ac +++ b/configure.ac @@ -65,6 +65,11 @@ AC_CONFIG_FILES([debuginfod/Makefile]) @@ -1183,7 +997,7 @@ index a39e800f7..12ee2f97c 100644 [AS_HELP_STRING([--enable-deterministic-archives], [ar and ranlib default to -D behavior])], [ diff --git a/debuginfod/Makefile.am b/debuginfod/Makefile.am -index 51965f65d..e62e8d14b 100644 +index 51965f65db..e62e8d14b0 100644 --- a/debuginfod/Makefile.am +++ b/debuginfod/Makefile.am @@ -57,7 +57,9 @@ libeu = ../lib/libeu.a diff --git a/libdrgn/elfutils/libcpu/ChangeLog b/libdrgn/elfutils/libcpu/ChangeLog index a8b2b951e..a342b7f64 100644 --- a/libdrgn/elfutils/libcpu/ChangeLog +++ b/libdrgn/elfutils/libcpu/ChangeLog @@ -1,3 +1,7 @@ +2020-05-09 Mark Wielaard + + * i386_parse.y (new_bitfield): Call free newp on error. + 2020-04-16 Mark Wielaard * i386_disasm.c (i386_disasm): Replace assert with goto invalid_op diff --git a/libdrgn/elfutils/libcpu/i386_parse.y b/libdrgn/elfutils/libcpu/i386_parse.y index 910d54581..90c7bd934 100644 --- a/libdrgn/elfutils/libcpu/i386_parse.y +++ b/libdrgn/elfutils/libcpu/i386_parse.y @@ -579,6 +579,7 @@ new_bitfield (char *name, unsigned long int num) error (0, 0, "%d: duplicated definition of bitfield '%s'", i386_lineno, name); free (name); + free (newp); return; } diff --git a/libdrgn/elfutils/libdw/libdw.map b/libdrgn/elfutils/libdw/libdw.map index b4fa63631..25ae8b6e6 100644 --- a/libdrgn/elfutils/libdw/libdw.map +++ b/libdrgn/elfutils/libdw/libdw.map @@ -374,8 +374,8 @@ ELFUTILS_0.180 { global: dwfl_attach_thread; dwfl_detach_thread; + dwfl_frame_register; dwfl_frame_module; dwfl_frame_dwarf_frame; - dwfl_frame_register; dwfl_frame_eval_expr; } ELFUTILS_0.177; diff --git a/libdrgn/elfutils/libdwfl/ChangeLog b/libdrgn/elfutils/libdwfl/ChangeLog index 3f9cd6659..4f1ec9da4 100644 --- a/libdrgn/elfutils/libdwfl/ChangeLog +++ b/libdrgn/elfutils/libdwfl/ChangeLog @@ -1,3 +1,14 @@ +2020-05-09 Mark Wielaard + + * find-debuginfo.c (dwfl_standard_find_debuginfo): Return failure + when mod is NULL. + +2020-05-08 Mark Wielaard + + * libdwfl/core-file.c (dwfl_core_file_report): Keep track of + new bool cleanup_user_core and cleanup dwfl->user_core in error + case. + 2020-04-30 Mark Wielaard * find-debuginfo.c (dwfl_standard_find_debuginfo): When mod->dw diff --git a/libdrgn/elfutils/libdwfl/core-file.c b/libdrgn/elfutils/libdwfl/core-file.c index 01109f4bd..a0ccc9b3d 100644 --- a/libdrgn/elfutils/libdwfl/core-file.c +++ b/libdrgn/elfutils/libdwfl/core-file.c @@ -450,6 +450,7 @@ dwfl_core_file_report (Dwfl *dwfl, Elf *elf, const char *executable) return -1; } + bool cleanup_user_core = false; if (dwfl->user_core != NULL) free (dwfl->user_core->executable_for_core); if (executable == NULL) @@ -461,6 +462,7 @@ dwfl_core_file_report (Dwfl *dwfl, Elf *elf, const char *executable) { if (dwfl->user_core == NULL) { + cleanup_user_core = true; dwfl->user_core = calloc (1, sizeof (struct Dwfl_User_Core)); if (dwfl->user_core == NULL) { @@ -472,6 +474,11 @@ dwfl_core_file_report (Dwfl *dwfl, Elf *elf, const char *executable) dwfl->user_core->executable_for_core = strdup (executable); if (dwfl->user_core->executable_for_core == NULL) { + if (cleanup_user_core) + { + free (dwfl->user_core); + dwfl->user_core = NULL; + } __libdwfl_seterrno (DWFL_E_NOMEM); return -1; } @@ -481,7 +488,15 @@ dwfl_core_file_report (Dwfl *dwfl, Elf *elf, const char *executable) GElf_Phdr notes_phdr; int ndx = dwfl_report_core_segments (dwfl, elf, phnum, ¬es_phdr); if (unlikely (ndx <= 0)) - return ndx; + { + if (cleanup_user_core) + { + free (dwfl->user_core->executable_for_core); + free (dwfl->user_core); + dwfl->user_core = NULL; + } + return ndx; + } /* Next, we should follow the chain from DT_DEBUG. */ diff --git a/libdrgn/elfutils/libdwfl/dwfl_frame.c b/libdrgn/elfutils/libdwfl/dwfl_frame.c index 046f6c2ba..80f2bc146 100644 --- a/libdrgn/elfutils/libdwfl/dwfl_frame.c +++ b/libdrgn/elfutils/libdwfl/dwfl_frame.c @@ -105,7 +105,8 @@ state_alloc (Dwfl_Thread *thread) state->frame = NULL; state->moderr = DWFL_E_NOERROR; state->frameerr = DWFL_E_NOERROR; - state->isactivation = true; + state->signal_frame = false; + state->initial_frame = true; state->pc_state = DWFL_FRAME_STATE_ERROR; memset (state->regs_set, 0, sizeof (state->regs_set)); thread->unwound = state; diff --git a/libdrgn/elfutils/libdwfl/dwfl_frame_pc.c b/libdrgn/elfutils/libdwfl/dwfl_frame_pc.c index a955d995a..296c815b9 100644 --- a/libdrgn/elfutils/libdwfl/dwfl_frame_pc.c +++ b/libdrgn/elfutils/libdwfl/dwfl_frame_pc.c @@ -39,7 +39,26 @@ dwfl_frame_pc (Dwfl_Frame *state, Dwarf_Addr *pc, bool *isactivation) *pc = state->pc; ebl_normalize_pc (state->thread->process->ebl, pc); if (isactivation) - *isactivation = state->isactivation; + { + /* Bottom frame? */ + if (state->initial_frame) + *isactivation = true; + /* *ISACTIVATION is logical union of whether current or previous frame + state is SIGNAL_FRAME. */ + else if (state->signal_frame) + *isactivation = true; + else + { + /* If the previous frame has unwound unsuccessfully just silently do + not consider it could be a SIGNAL_FRAME. */ + __libdwfl_frame_unwind (state); + if (state->unwound == NULL + || state->unwound->pc_state != DWFL_FRAME_STATE_PC_SET) + *isactivation = false; + else + *isactivation = state->unwound->signal_frame; + } + } return true; } INTDEF (dwfl_frame_pc) diff --git a/libdrgn/elfutils/libdwfl/dwfl_frame_regs.c b/libdrgn/elfutils/libdwfl/dwfl_frame_regs.c index d013dc966..83b1abef1 100644 --- a/libdrgn/elfutils/libdwfl/dwfl_frame_regs.c +++ b/libdrgn/elfutils/libdwfl/dwfl_frame_regs.c @@ -38,6 +38,7 @@ dwfl_thread_state_registers (Dwfl_Thread *thread, int firstreg, { Dwfl_Frame *state = thread->unwound; assert (state && state->unwound == NULL); + assert (state->initial_frame); for (unsigned regno = firstreg; regno < firstreg + nregs; regno++) if (! __libdwfl_frame_reg_set (state, regno, regs[regno - firstreg])) { @@ -53,6 +54,7 @@ dwfl_thread_state_register_pc (Dwfl_Thread *thread, Dwarf_Word pc) { Dwfl_Frame *state = thread->unwound; assert (state && state->unwound == NULL); + assert (state->initial_frame); state->pc = pc; state->pc_state = DWFL_FRAME_STATE_PC_SET; } diff --git a/libdrgn/elfutils/libdwfl/find-debuginfo.c b/libdrgn/elfutils/libdwfl/find-debuginfo.c index 4cfd0b8b2..eb68d549d 100644 --- a/libdrgn/elfutils/libdwfl/find-debuginfo.c +++ b/libdrgn/elfutils/libdwfl/find-debuginfo.c @@ -355,6 +355,9 @@ dwfl_standard_find_debuginfo (Dwfl_Module *mod, GElf_Word debuglink_crc, char **debuginfo_file_name) { + if (mod == NULL) + return -1; + /* First try by build ID if we have one. If that succeeds or fails other than just by finding nothing, that's all we do. */ const unsigned char *bits = NULL; diff --git a/libdrgn/elfutils/libdwfl/frame_unwind.c b/libdrgn/elfutils/libdwfl/frame_unwind.c index 4885caa13..a6df26976 100644 --- a/libdrgn/elfutils/libdwfl/frame_unwind.c +++ b/libdrgn/elfutils/libdwfl/frame_unwind.c @@ -527,7 +527,8 @@ new_unwound (Dwfl_Frame *state) unwound->frame = NULL; unwound->moderr = DWFL_E_NOERROR; unwound->frameerr = DWFL_E_NOERROR; - unwound->isactivation = false; + unwound->signal_frame = false; + unwound->initial_frame = false; unwound->pc_state = DWFL_FRAME_STATE_ERROR; memset (unwound->regs_set, 0, sizeof (unwound->regs_set)); return unwound; @@ -542,11 +543,7 @@ static void handle_cfi (Dwfl_Frame *state, Dwarf_Frame *frame, Dwarf_Addr bias) { Dwfl_Frame *unwound = state->unwound; - if (frame->fde->cie->signal_frame) - { - state->isactivation = true; - unwound->isactivation = true; - } + unwound->signal_frame = frame->fde->cie->signal_frame; Dwfl_Thread *thread = state->thread; Dwfl_Process *process = thread->process; Ebl *ebl = process->ebl; @@ -702,68 +699,14 @@ readfunc (Dwarf_Addr addr, Dwarf_Word *datap, void *arg) process->callbacks_arg); } -void -internal_function -__libdwfl_frame_unwind (Dwfl_Frame *state) -{ - if (state->unwound) - return; - Dwarf_Addr pc; - bool isactivation; - bool ok = INTUSE(dwfl_frame_pc) (state, &pc, &isactivation); - assert (ok); - if (! isactivation) - pc--; - Dwarf_Addr bias; - Dwarf_Frame *frame = INTUSE(dwfl_frame_dwarf_frame) (state, &bias); - if (frame != NULL) - { - if (new_unwound (state) == NULL) - __libdwfl_seterrno (DWFL_E_NOMEM); - else - handle_cfi (state, frame, bias); - return; - } - Dwfl_Thread *thread = state->thread; - Dwfl_Process *process = thread->process; - Ebl *ebl = process->ebl; - if (new_unwound (state) == NULL) - { - __libdwfl_seterrno (DWFL_E_NOMEM); - return; - } - state->unwound->pc_state = DWFL_FRAME_STATE_PC_UNDEFINED; - bool signal_frame = false; - if (! ebl_unwind (ebl, pc, setfunc, getfunc, readfunc, state, &signal_frame)) - { - // Discard the unwind attempt. During next __libdwfl_frame_unwind call - // we may have for example the appropriate Dwfl_Module already mapped. - assert (state->unwound->unwound == NULL); - free (state->unwound); - state->unwound = NULL; - // __libdwfl_seterrno has been called above. - return; - } - assert (state->unwound->pc_state == DWFL_FRAME_STATE_PC_SET); - if (signal_frame) - { - state->isactivation = true; - state->unwound->isactivation = true; - } -} - -Dwfl_Module * -dwfl_frame_module (Dwfl_Frame *state) +/* Internal version of dwfl_frame_module when we already know the PC. */ +static Dwfl_Module * +dwfl_frame_module_pc (Dwfl_Frame *state, Dwarf_Addr pc) { if (state->mod != NULL) return state->mod; if (state->moderr == DWFL_E_NOERROR) { - Dwarf_Addr pc; - bool isactivation; - INTUSE(dwfl_frame_pc) (state, &pc, &isactivation); - if (! isactivation) - pc--; state->mod = INTUSE(dwfl_addrmodule) (state->thread->process->dwfl, pc); if (state->mod != NULL) return state->mod; @@ -772,33 +715,28 @@ dwfl_frame_module (Dwfl_Frame *state) __libdwfl_seterrno (state->moderr); return NULL; } -INTDEF (dwfl_frame_module) -Dwarf_Frame * -dwfl_frame_dwarf_frame (Dwfl_Frame *state, Dwarf_Addr *bias) +/* Internal version of dwfl_frame_dwarf_frame when we already know the PC. */ +static Dwarf_Frame * +dwfl_frame_dwarf_frame_pc (Dwfl_Frame *state, Dwarf_Addr pc, Dwarf_Addr *bias) { if (state->frame == NULL) { if (state->frameerr == DWFL_E_NOERROR) { - Dwfl_Module *mod = INTUSE(dwfl_frame_module) (state); + Dwfl_Module *mod = dwfl_frame_module_pc (state, pc); if (mod == NULL) { state->frameerr = state->moderr; + /* errno is already set. */ return NULL; } - Dwarf_Addr pc; - bool isactivation; - INTUSE(dwfl_frame_pc) (state, &pc, &isactivation); - if (! isactivation) - pc--; - Dwarf_CFI *cfi = INTUSE(dwfl_module_eh_cfi) (state->mod, - &state->bias); + Dwarf_CFI *cfi = INTUSE(dwfl_module_eh_cfi) (mod, &state->bias); if (cfi && INTUSE(dwarf_cfi_addrframe) (cfi, pc - state->bias, &state->frame) == 0) goto out; - cfi = INTUSE(dwfl_module_dwarf_cfi) (state->mod, &state->bias); + cfi = INTUSE(dwfl_module_dwarf_cfi) (mod, &state->bias); if (cfi && INTUSE(dwarf_cfi_addrframe) (cfi, pc - state->bias, &state->frame) == 0) @@ -813,7 +751,92 @@ dwfl_frame_dwarf_frame (Dwfl_Frame *state, Dwarf_Addr *bias) *bias = state->bias; return state->frame; } -INTDEF (dwfl_frame_dwarf_frame) + +Dwfl_Module * +dwfl_frame_module (Dwfl_Frame *state) +{ + if (state->mod != NULL) + return state->mod; + if (state->moderr == DWFL_E_NOERROR) + { + Dwarf_Addr pc; + bool isactivation; + INTUSE(dwfl_frame_pc) (state, &pc, &isactivation); + if (! isactivation) + pc--; + return dwfl_frame_module_pc (state, pc); + } + __libdwfl_seterrno (state->moderr); + return NULL; +} + +Dwarf_Frame * +dwfl_frame_dwarf_frame (Dwfl_Frame *state, Dwarf_Addr *bias) +{ + if (state->frame != NULL) + return state->frame; + if (state->frameerr == DWFL_E_NOERROR) + { + Dwarf_Addr pc; + bool isactivation; + INTUSE(dwfl_frame_pc) (state, &pc, &isactivation); + if (! isactivation) + pc--; + return dwfl_frame_dwarf_frame_pc (state, pc, bias); + } + __libdwfl_seterrno (state->frameerr); + return NULL; +} + +void +internal_function +__libdwfl_frame_unwind (Dwfl_Frame *state) +{ + if (state->unwound) + return; + /* Do not ask dwfl_frame_pc for ISACTIVATION, it would try to unwind STATE + which would deadlock us. */ + Dwarf_Addr pc; + bool ok = INTUSE(dwfl_frame_pc) (state, &pc, NULL); + assert (ok); + /* Check whether this is the initial frame or a signal frame. + Then we need to unwind from the original, unadjusted PC. */ + if (! state->initial_frame && ! state->signal_frame) + pc--; + Dwarf_Addr bias; + Dwarf_Frame *frame = dwfl_frame_dwarf_frame_pc (state, pc, &bias); + if (frame != NULL) + { + if (new_unwound (state) == NULL) + __libdwfl_seterrno (DWFL_E_NOMEM); + else + handle_cfi (state, frame, bias); + return; + } + Dwfl_Thread *thread = state->thread; + Dwfl_Process *process = thread->process; + Ebl *ebl = process->ebl; + if (new_unwound (state) == NULL) + { + __libdwfl_seterrno (DWFL_E_NOMEM); + return; + } + state->unwound->pc_state = DWFL_FRAME_STATE_PC_UNDEFINED; + // &Dwfl_Frame.signal_frame cannot be passed as it is a bitfield. + bool signal_frame = false; + if (! ebl_unwind (ebl, pc, setfunc, getfunc, readfunc, state, &signal_frame)) + { + // Discard the unwind attempt. During next __libdwfl_frame_unwind call + // we may have for example the appropriate Dwfl_Module already mapped. + assert (state->unwound->unwound == NULL); + free (state->unwound); + state->unwound = NULL; + // __libdwfl_seterrno has been called above. + return; + } + assert (state->unwound->pc_state == DWFL_FRAME_STATE_PC_SET); + state->unwound->signal_frame = signal_frame; +} bool dwfl_frame_eval_expr (Dwfl_Frame *state, const Dwarf_Op *ops, size_t nops, diff --git a/libdrgn/elfutils/libdwfl/libdwflP.h b/libdrgn/elfutils/libdwfl/libdwflP.h index 613ccf016..7baa3223f 100644 --- a/libdrgn/elfutils/libdwfl/libdwflP.h +++ b/libdrgn/elfutils/libdwfl/libdwflP.h @@ -261,7 +261,8 @@ struct Dwfl_Frame Dwfl_Error moderr; /* Error trying to get frame. */ Dwfl_Error frameerr; - bool isactivation; + bool signal_frame : 1; + bool initial_frame : 1; enum { /* This structure is still being initialized or there was an error @@ -774,8 +775,6 @@ INTDECL (dwfl_pid) INTDECL (dwfl_thread_dwfl) INTDECL (dwfl_thread_tid) INTDECL (dwfl_frame_thread) -INTDECL (dwfl_frame_module) -INTDECL (dwfl_frame_dwarf_frame) INTDECL (dwfl_thread_state_registers) INTDECL (dwfl_thread_state_register_pc) INTDECL (dwfl_getthread_frames) diff --git a/libdrgn/elfutils/libelf/ChangeLog b/libdrgn/elfutils/libelf/ChangeLog index 56f5354c5..fd5518dc4 100644 --- a/libdrgn/elfutils/libelf/ChangeLog +++ b/libdrgn/elfutils/libelf/ChangeLog @@ -1,3 +1,12 @@ +2020-05-08 Mark Wielaard + + * elf_strptr.c (elf_strptr): Check shdr is not NULL. + +2020-05-08 Mark Wielaard + + * elf_getdata.c (__libelf_set_rawdata_wrlock): Check + __gelf_getehdr_rdlock return value. + 2020-04-25 Mark Wielaard * elf_compress.c (__libelf_compress): Remove free (out_buf). diff --git a/libdrgn/elfutils/libelf/elf_getdata.c b/libdrgn/elfutils/libelf/elf_getdata.c index 40fe16945..0d8f8d2ee 100644 --- a/libdrgn/elfutils/libelf/elf_getdata.c +++ b/libdrgn/elfutils/libelf/elf_getdata.c @@ -271,6 +271,8 @@ __libelf_set_rawdata_wrlock (Elf_Scn *scn) { GElf_Ehdr ehdr_mem; GElf_Ehdr *ehdr = __gelf_getehdr_rdlock (elf, &ehdr_mem); + if (unlikely (ehdr == NULL)) + return 1; entsize = SH_ENTSIZE_HASH (ehdr); } else diff --git a/libdrgn/elfutils/libelf/elf_strptr.c b/libdrgn/elfutils/libelf/elf_strptr.c index e72a3a369..c72717074 100644 --- a/libdrgn/elfutils/libelf/elf_strptr.c +++ b/libdrgn/elfutils/libelf/elf_strptr.c @@ -145,7 +145,7 @@ elf_strptr (Elf *elf, size_t idx, size_t offset) else { Elf64_Shdr *shdr = strscn->shdr.e64 ?: __elf64_getshdr_rdlock (strscn); - if (unlikely (shdr->sh_type != SHT_STRTAB)) + if (unlikely (shdr == NULL || shdr->sh_type != SHT_STRTAB)) { /* This is no string section. */ __libelf_seterrno (ELF_E_INVALID_SECTION); diff --git a/libdrgn/elfutils/src/ChangeLog b/libdrgn/elfutils/src/ChangeLog index 83d586071..83fe19eb0 100644 --- a/libdrgn/elfutils/src/ChangeLog +++ b/libdrgn/elfutils/src/ChangeLog @@ -1,3 +1,14 @@ +2020-05-14 Mark Wielaard + + * size.c (show_bsd): Set printf format based on radix. + +2020-05-09 Mark Wielaard + + * elflint.c (process_elf_file): Error out if ebl_openbackend fails. + * objdump.c (handle_elf): Likewise. + * nm.c (handle_elf): Likewise. Move full name string construction + forward, so it can be used in the error message. + 2020-04-17 Mark Wielaard * readelf.c (print_debug): Check .gnu.debuglto_ prefix. diff --git a/libdrgn/elfutils/src/elflint.c b/libdrgn/elfutils/src/elflint.c index 0ef432366..6ad9bc421 100644 --- a/libdrgn/elfutils/src/elflint.c +++ b/libdrgn/elfutils/src/elflint.c @@ -4775,7 +4775,14 @@ process_elf_file (Elf *elf, const char *prefix, const char *suffix, ebl = ebl_openbackend (elf); /* If there is no appropriate backend library we cannot test architecture and OS specific features. Any encountered extension - is an error. */ + is an error. Often we'll get a "dummy" ebl, except if something + really bad happen, like a totally corrupted ELF file or out of + memory situation. */ + if (ebl == NULL) + { + ERROR (gettext ("cannot create backend for ELF file\n")); + return; + } /* Go straight by the gABI, check all the parts in turn. */ check_elf_header (ebl, ehdr, size); diff --git a/libdrgn/elfutils/src/nm.c b/libdrgn/elfutils/src/nm.c index b7c2aed6c..f6ca3b0af 100644 --- a/libdrgn/elfutils/src/nm.c +++ b/libdrgn/elfutils/src/nm.c @@ -1510,8 +1510,17 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, GElf_Ehdr *ehdr; Ebl *ebl; + /* Create the full name of the file. */ + if (prefix != NULL) + cp = mempcpy (cp, prefix, prefix_len); + cp = mempcpy (cp, fname, fname_len); + if (suffix != NULL) + memcpy (cp - 1, suffix, suffix_len + 1); + /* Get the backend for this object file type. */ ebl = ebl_openbackend (elf); + if (ebl == NULL) + INTERNAL_ERROR (fullname); /* We need the ELF header in a few places. */ ehdr = gelf_getehdr (elf, &ehdr_mem); @@ -1530,13 +1539,6 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, goto out; } - /* Create the full name of the file. */ - if (prefix != NULL) - cp = mempcpy (cp, prefix, prefix_len); - cp = mempcpy (cp, fname, fname_len); - if (suffix != NULL) - memcpy (cp - 1, suffix, suffix_len + 1); - /* Find the symbol table. XXX Can there be more than one? Do we print all? Currently we do. */ diff --git a/libdrgn/elfutils/src/objdump.c b/libdrgn/elfutils/src/objdump.c index a619674f4..82d7bcf6a 100644 --- a/libdrgn/elfutils/src/objdump.c +++ b/libdrgn/elfutils/src/objdump.c @@ -755,6 +755,9 @@ handle_elf (Elf *elf, const char *prefix, const char *fname, /* Get the backend for this object file type. */ Ebl *ebl = ebl_openbackend (elf); + if (ebl == NULL) + error (EXIT_FAILURE, 0, + gettext ("cannot create backend for elf file")); printf ("%s: elf%d-%s\n\n", fname, gelf_getclass (elf) == ELFCLASS32 ? 32 : 64, diff --git a/libdrgn/elfutils/src/size.c b/libdrgn/elfutils/src/size.c index a25d4471f..e49b64b86 100644 --- a/libdrgn/elfutils/src/size.c +++ b/libdrgn/elfutils/src/size.c @@ -545,8 +545,11 @@ show_bsd (Elf *elf, const char *prefix, const char *fname, datasize += shdr->sh_size; } - printf ("%*" PRId64 " %*" PRId64 " %*" PRId64 " %*" PRId64 " %*" - PRIx64 " %s", + printf (radix == radix_decimal + ? "%*" PRId64 " %*" PRId64 " %*" PRId64 " %*" PRId64 " %*" PRIx64 " %s" + : radix == radix_hex + ? "%#*" PRIx64 " %#*" PRIx64 " %#*" PRIx64 " %*" PRId64 " %*" PRIx64 " %s" + : "%#*" PRIo64 " %#*" PRIo64 " %#*" PRIo64 " %*" PRId64 " %*" PRIx64 " %s", ddigits - 2, textsize, ddigits - 2, datasize, ddigits - 2, bsssize, diff --git a/libdrgn/elfutils/tests/ChangeLog b/libdrgn/elfutils/tests/ChangeLog index 4e9ae020b..05aab3ef4 100644 --- a/libdrgn/elfutils/tests/ChangeLog +++ b/libdrgn/elfutils/tests/ChangeLog @@ -1,3 +1,8 @@ +2020-05-08 Mark Wielaard + + * elfputzdata.c (main): Explicitly check orig_buf is not NULL + before calling memcmp. + 2020-05-05 Mark Wielaard * testfile-lto-gcc8.bz2: New test file. diff --git a/libdrgn/elfutils/tests/elfputzdata.c b/libdrgn/elfutils/tests/elfputzdata.c index 66ab77ba7..0d9c020ec 100644 --- a/libdrgn/elfutils/tests/elfputzdata.c +++ b/libdrgn/elfutils/tests/elfputzdata.c @@ -105,14 +105,17 @@ main (int argc, char *argv[]) printf ("Unexpected data size for orig section %zd\n", idx); return -1; } - char *orig_buf = malloc (d->d_size); - if (orig_size > 0 && orig_buf == NULL) + char *orig_buf = NULL; + if (orig_size > 0) { - printf ("No memory to copy section %zd data\n", idx); - return -1; + orig_buf = malloc (d->d_size); + if (orig_buf == NULL) + { + printf ("No memory to copy section %zd data\n", idx); + return -1; + } + memcpy (orig_buf, d->d_buf, orig_size); } - if (orig_size > 0) - memcpy (orig_buf, d->d_buf, orig_size); bool forced = false; if (gnu) @@ -175,7 +178,8 @@ main (int argc, char *argv[]) } if (new_size == orig_size - && memcmp (orig_buf, d->d_buf, orig_size) == 0) + && (orig_buf == NULL + || memcmp (orig_buf, d->d_buf, orig_size) == 0)) { printf ("section %zd didn't compress\n", idx); return -1; @@ -211,7 +215,8 @@ main (int argc, char *argv[]) return -1; } if (newer_size != orig_size - && memcmp (orig_buf, d->d_buf, orig_size) != 0) + && (orig_buf == NULL + || memcmp (orig_buf, d->d_buf, orig_size) != 0)) { printf ("section %zd didn't correctly uncompress\n", idx); return -1; diff --git a/libdrgn/error.c b/libdrgn/error.c index 08ff1b708..bba0e5432 100644 --- a/libdrgn/error.c +++ b/libdrgn/error.c @@ -1,4 +1,4 @@ -// Copyright 2018-2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #include diff --git a/libdrgn/error.h b/libdrgn/error.h index de998eb92..fe44b6665 100644 --- a/libdrgn/error.h +++ b/libdrgn/error.h @@ -1,4 +1,4 @@ -// Copyright 2018-2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ /** diff --git a/libdrgn/hash_table.c b/libdrgn/hash_table.c index cc062d46e..1a73c21c3 100644 --- a/libdrgn/hash_table.c +++ b/libdrgn/hash_table.c @@ -1,3 +1,6 @@ +// Copyright (c) Facebook, Inc. and its affiliates. +// SPDX-License-Identifier: GPL-3.0+ + #include "hash_table.h" const uint8_t hash_table_empty_chunk_header[16] __attribute__((aligned(16))); diff --git a/libdrgn/hash_table.h b/libdrgn/hash_table.h index 61eb96f79..32652af7f 100644 --- a/libdrgn/hash_table.h +++ b/libdrgn/hash_table.h @@ -1,4 +1,4 @@ -// Copyright 2018-2020 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ /** diff --git a/libdrgn/helpers.h b/libdrgn/helpers.h index e32882d80..e287d19e4 100644 --- a/libdrgn/helpers.h +++ b/libdrgn/helpers.h @@ -1,4 +1,4 @@ -// Copyright 2019-2020 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ /** diff --git a/libdrgn/include/Makefile.am b/libdrgn/include/Makefile.am index 56d1e0e60..2afd29229 100644 --- a/libdrgn/include/Makefile.am +++ b/libdrgn/include/Makefile.am @@ -1,3 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ + # "Install" the elfutils headers to the build directory. BUILT_SOURCES = dwarf.h \ diff --git a/libdrgn/internal.c b/libdrgn/internal.c index 859b28b00..4c2e42aac 100644 --- a/libdrgn/internal.c +++ b/libdrgn/internal.c @@ -1,4 +1,4 @@ -// Copyright 2018-2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #include diff --git a/libdrgn/internal.h b/libdrgn/internal.h index b16ed2ef4..84fc814d2 100644 --- a/libdrgn/internal.h +++ b/libdrgn/internal.h @@ -1,4 +1,4 @@ -// Copyright 2018-2020 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ /** diff --git a/libdrgn/language.c b/libdrgn/language.c index ee71aa26f..e6219cd2d 100644 --- a/libdrgn/language.c +++ b/libdrgn/language.c @@ -1,4 +1,4 @@ -// Copyright 2020 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #include "internal.h" diff --git a/libdrgn/language.h b/libdrgn/language.h index c63fdb771..9d129dcc1 100644 --- a/libdrgn/language.h +++ b/libdrgn/language.h @@ -1,4 +1,4 @@ -// Copyright 2018-2020 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ /** diff --git a/libdrgn/language_c.c b/libdrgn/language_c.c index 8d2c49ac9..b74910c8d 100644 --- a/libdrgn/language_c.c +++ b/libdrgn/language_c.c @@ -1,4 +1,4 @@ -// Copyright 2018-2020 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #include diff --git a/libdrgn/lexer.c b/libdrgn/lexer.c index 1b43b4f87..426f72098 100644 --- a/libdrgn/lexer.c +++ b/libdrgn/lexer.c @@ -1,4 +1,4 @@ -// Copyright 2018-2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #include "internal.h" diff --git a/libdrgn/lexer.h b/libdrgn/lexer.h index cb098e469..62511e8a8 100644 --- a/libdrgn/lexer.h +++ b/libdrgn/lexer.h @@ -1,4 +1,4 @@ -// Copyright 2018-2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ /** diff --git a/libdrgn/linux_kernel.c b/libdrgn/linux_kernel.c index 4f7801894..0c2d0bc22 100644 --- a/libdrgn/linux_kernel.c +++ b/libdrgn/linux_kernel.c @@ -1,4 +1,4 @@ -// Copyright 2018-2020 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #include @@ -234,6 +234,33 @@ struct drgn_error *read_vmcoreinfo_fallback(struct drgn_memory_reader *reader, return err; } +struct drgn_error *linux_kernel_get_thread_size(struct drgn_program *prog, + uint64_t *ret) +{ + struct drgn_error *err; + struct drgn_qualified_type thread_union_type; + struct drgn_member_info stack_member; + + if (!prog->thread_size) { + err = drgn_program_find_type(prog, "union thread_union", NULL, + &thread_union_type); + if (err) + return err; + err = drgn_program_member_info(prog, thread_union_type.type, + "stack", &stack_member); + if (err) + return err; + err = drgn_type_sizeof(stack_member.qualified_type.type, + &prog->thread_size); + if (err) { + prog->thread_size = 0; + return err; + } + } + *ret = prog->thread_size; + return NULL; +} + struct drgn_error *linux_kernel_object_find(const char *name, size_t name_len, const char *filename, enum drgn_find_object_flags flags, @@ -296,6 +323,20 @@ struct drgn_error *linux_kernel_object_find(const char *name, size_t name_len, return drgn_object_set_unsigned(ret, qualified_type, ~(prog->vmcoreinfo.page_size - 1), 0); + } else if (name_len == strlen("THREAD_SIZE") && + memcmp(name, "THREAD_SIZE", name_len) == 0) { + uint64_t thread_size; + + err = linux_kernel_get_thread_size(prog, &thread_size); + if (err) + return err; + err = drgn_type_index_find_primitive(&prog->tindex, + DRGN_C_TYPE_UNSIGNED_LONG, + &qualified_type.type); + if (err) + return err; + return drgn_object_set_unsigned(ret, qualified_type, + thread_size, 0); } else if (name_len == strlen("UTS_RELEASE") && memcmp(name, "UTS_RELEASE", name_len) == 0) { size_t len; diff --git a/libdrgn/linux_kernel.h b/libdrgn/linux_kernel.h index 6bb3b5751..c467bf27c 100644 --- a/libdrgn/linux_kernel.h +++ b/libdrgn/linux_kernel.h @@ -1,4 +1,4 @@ -// Copyright 2018-2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #ifndef DRGN_LINUX_KERNEL_H @@ -24,6 +24,8 @@ struct drgn_error *proc_kallsyms_symbol_addr(const char *name, struct drgn_error *read_vmcoreinfo_fallback(struct drgn_memory_reader *reader, struct vmcoreinfo *ret); +struct drgn_error *linux_kernel_get_thread_size(struct drgn_program *prog, + uint64_t *ret); struct drgn_error *linux_kernel_object_find(const char *name, size_t name_len, const char *filename, diff --git a/libdrgn/linux_kernel_helpers.c b/libdrgn/linux_kernel_helpers.c index 2365d88cf..dedaed776 100644 --- a/libdrgn/linux_kernel_helpers.c +++ b/libdrgn/linux_kernel_helpers.c @@ -1,4 +1,4 @@ -// Copyright 2019-2020 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #include diff --git a/libdrgn/memory_reader.c b/libdrgn/memory_reader.c index b368fb8e7..48682c3ce 100644 --- a/libdrgn/memory_reader.c +++ b/libdrgn/memory_reader.c @@ -1,4 +1,4 @@ -// Copyright 2018-2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #include diff --git a/libdrgn/memory_reader.h b/libdrgn/memory_reader.h index f8cca1fb1..f6d94a332 100644 --- a/libdrgn/memory_reader.h +++ b/libdrgn/memory_reader.h @@ -1,4 +1,4 @@ -// Copyright 2018-2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ /** diff --git a/libdrgn/object.c b/libdrgn/object.c index 330f96ae9..5361dedee 100644 --- a/libdrgn/object.c +++ b/libdrgn/object.c @@ -1,4 +1,4 @@ -// Copyright 2018-2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #include diff --git a/libdrgn/object.h b/libdrgn/object.h index 5b80b5fcf..ca9b3c580 100644 --- a/libdrgn/object.h +++ b/libdrgn/object.h @@ -1,4 +1,4 @@ -// Copyright 2018-2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ /** diff --git a/libdrgn/object_index.c b/libdrgn/object_index.c index 46cebf123..68f069b0c 100644 --- a/libdrgn/object_index.c +++ b/libdrgn/object_index.c @@ -1,4 +1,4 @@ -// Copyright 2018-2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #include diff --git a/libdrgn/object_index.h b/libdrgn/object_index.h index 5e54bf5d3..fcd384795 100644 --- a/libdrgn/object_index.h +++ b/libdrgn/object_index.h @@ -1,4 +1,4 @@ -// Copyright 2018-2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ /** diff --git a/libdrgn/path.c b/libdrgn/path.c index aa78cd3fa..6aa5ed690 100644 --- a/libdrgn/path.c +++ b/libdrgn/path.c @@ -1,4 +1,4 @@ -// Copyright 2018-2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #include diff --git a/libdrgn/platform.c b/libdrgn/platform.c index edaed554f..a2ba6df37 100644 --- a/libdrgn/platform.c +++ b/libdrgn/platform.c @@ -1,4 +1,4 @@ -// Copyright 2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #include diff --git a/libdrgn/platform.h b/libdrgn/platform.h index bc7f7d206..c97608ec8 100644 --- a/libdrgn/platform.h +++ b/libdrgn/platform.h @@ -1,4 +1,4 @@ -// Copyright 2019-2020 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #ifndef DRGN_PLATFORM_H @@ -13,17 +13,6 @@ struct drgn_register { enum drgn_register_number number; }; -/* Register in NT_PRSTATUS note or struct pt_regs used for stack unwinding. */ -struct drgn_frame_register { - enum drgn_register_number number; - size_t size; - size_t prstatus_offset; - /* Name used in the kernel. */ - const char *pt_regs_name; - /* Name used for the UAPI, if different from above. */ - const char *pt_regs_name2; -}; - /* Page table iterator. */ struct pgtable_iterator { struct drgn_program *prog; @@ -69,10 +58,42 @@ struct drgn_architecture_info { const struct drgn_register *registers; size_t num_registers; const struct drgn_register *(*register_by_name)(const char *name); - const struct drgn_frame_register *frame_registers; - size_t num_frame_registers; + /* Given pt_regs as a value buffer object. */ + struct drgn_error *(*pt_regs_set_initial_registers)(Dwfl_Thread *, + const struct drgn_object *); + struct drgn_error *(*prstatus_set_initial_registers)(struct drgn_program *, + Dwfl_Thread *, + const void *, + size_t); + /* + * Get a task's registers from the task_struct or PRSTATUS note as + * appropriate. + * + * The given PRSTATUS note is for the CPU that the task is assigned to, + * which may or may not be for the given task. This callback must + * determine that (typically by checking whether the stack pointer in + * PRSTATUS lies within the task's stack). + * + * We find the PRSTATUS note by CPU rather than by PID for two reasons: + * + * 1. The PID is populated by the kernel from "current" (the current + * task) via a non-maskable interrupt (NMI). During a context switch, + * the stack pointer and current are not updated atomically, so if + * the NMI arrives in the middle of a context switch, the stack + * pointer may not actually be that of current. Therefore, the stack + * pointer in PRSTATUS may not actually be for the PID in PRSTATUS. + * + * We go through all of this trouble because blindly trusting the PID + * could result in a stack trace for the wrong task, which we want to + * avoid at all costs. + * + * 2. There is an idle task with PID 0 for each CPU, so for an idle task + * we have no choice but to find the note by CPU. + */ struct drgn_error *(*linux_kernel_set_initial_registers)(Dwfl_Thread *, - const struct drgn_object *); + const struct drgn_object *, + const void *prstatus, + size_t prstatus_size); struct drgn_error *(*linux_kernel_get_page_offset)(struct drgn_program *, uint64_t *); struct drgn_error *(*linux_kernel_get_vmemmap)(struct drgn_program *, diff --git a/libdrgn/program.c b/libdrgn/program.c index b8a23b902..72fbfe832 100644 --- a/libdrgn/program.c +++ b/libdrgn/program.c @@ -1,4 +1,4 @@ -// Copyright 2018-2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #include @@ -28,6 +28,7 @@ #include "type_index.h" #include "vector.h" +DEFINE_VECTOR_FUNCTIONS(drgn_prstatus_vector) DEFINE_HASH_TABLE_FUNCTIONS(drgn_prstatus_map, hash_pair_int_type, hash_table_scalar_eq) @@ -75,7 +76,6 @@ void drgn_program_init(struct drgn_program *prog, drgn_type_index_init(&prog->tindex); drgn_object_index_init(&prog->oindex); prog->core_fd = -1; - drgn_prstatus_map_init(&prog->prstatus_cache); if (platform) drgn_program_set_platform(prog, platform); } @@ -83,7 +83,12 @@ void drgn_program_init(struct drgn_program *prog, void drgn_program_deinit(struct drgn_program *prog) { free(prog->task_state_chars); - drgn_prstatus_map_deinit(&prog->prstatus_cache); + if (prog->prstatus_cached) { + if (prog->flags & DRGN_PROGRAM_IS_LINUX_KERNEL) + drgn_prstatus_vector_deinit(&prog->prstatus_vector); + else + drgn_prstatus_map_deinit(&prog->prstatus_map); + } free(prog->pgtable_it); drgn_object_index_deinit(&prog->oindex); @@ -736,41 +741,64 @@ drgn_program_load_debug_info(struct drgn_program *prog, const char **paths, struct drgn_error *drgn_program_cache_prstatus_entry(struct drgn_program *prog, char *data, size_t size) { - struct drgn_prstatus_map_entry entry; - size_t pr_pid_offset; - uint32_t pr_pid; + if (prog->flags & DRGN_PROGRAM_IS_LINUX_KERNEL) { + struct string *entry; - pr_pid_offset = drgn_program_is_64_bit(prog) ? 32 : 24; + entry = drgn_prstatus_vector_append_entry(&prog->prstatus_vector); + if (!entry) + return &drgn_enomem; + entry->str = data; + entry->len = size; + } else { + struct drgn_prstatus_map_entry entry; + size_t pr_pid_offset; + uint32_t pr_pid; - if (size < pr_pid_offset + sizeof(pr_pid)) - return NULL; + pr_pid_offset = drgn_program_is_64_bit(prog) ? 32 : 24; + if (size < pr_pid_offset + sizeof(pr_pid)) + return NULL; - memcpy(&pr_pid, data + pr_pid_offset, sizeof(pr_pid)); - if (drgn_program_bswap(prog)) - pr_pid = bswap_32(pr_pid); - if (!pr_pid) - return NULL; + memcpy(&pr_pid, data + pr_pid_offset, sizeof(pr_pid)); + if (drgn_program_bswap(prog)) + pr_pid = bswap_32(pr_pid); - entry.key = pr_pid; - entry.value.str = data; - entry.value.len = size; - if (drgn_prstatus_map_insert(&prog->prstatus_cache, &entry, - NULL) == -1) { - return &drgn_enomem; + entry.key = pr_pid; + entry.value.str = data; + entry.value.len = size; + if (drgn_prstatus_map_insert(&prog->prstatus_map, &entry, + NULL) == -1) + return &drgn_enomem; } return NULL; } static struct drgn_error *drgn_program_cache_prstatus(struct drgn_program *prog) { + struct drgn_error *err; size_t phnum, i; + if (prog->prstatus_cached) + return NULL; + + if (prog->flags & DRGN_PROGRAM_IS_LINUX_KERNEL) + drgn_prstatus_vector_init(&prog->prstatus_vector); + else + drgn_prstatus_map_init(&prog->prstatus_map); + #ifdef WITH_LIBKDUMPFILE - if (prog->kdump_ctx) - return drgn_program_cache_prstatus_kdump(prog); + if (prog->kdump_ctx) { + err = drgn_program_cache_prstatus_kdump(prog); + goto out; + } #endif - if (elf_getphdrnum(prog->core, &phnum) != 0) - return drgn_error_libelf(); + if (!prog->core) { + err = NULL; + goto out; + } + if (elf_getphdrnum(prog->core, &phnum) != 0) { + err = drgn_error_libelf(); + goto out; + } for (i = 0; i < phnum; i++) { GElf_Phdr phdr_mem, *phdr; Elf_Data *data; @@ -779,23 +807,26 @@ static struct drgn_error *drgn_program_cache_prstatus(struct drgn_program *prog) size_t name_offset, desc_offset; phdr = gelf_getphdr(prog->core, i, &phdr_mem); - if (!phdr) - return drgn_error_libelf(); + if (!phdr) { + err = drgn_error_libelf(); + goto out; + } if (phdr->p_type != PT_NOTE) continue; data = elf_getdata_rawchunk(prog->core, phdr->p_offset, phdr->p_filesz, note_header_type(phdr)); - if (!data) - return drgn_error_libelf(); + if (!data) { + err = drgn_error_libelf(); + goto out; + } offset = 0; while (offset < data->d_size && (offset = gelf_getnote(data, offset, &nhdr, &name_offset, &desc_offset))) { const char *name; - struct drgn_error *err; name = (char *)data->d_buf + name_offset; if (strncmp(name, "CORE", nhdr.n_namesz) != 0 || @@ -806,26 +837,56 @@ static struct drgn_error *drgn_program_cache_prstatus(struct drgn_program *prog) (char *)data->d_buf + desc_offset, nhdr.n_descsz); if (err) - return err; + goto out; } } + + err = NULL; +out: + if (err) { + if (prog->flags & DRGN_PROGRAM_IS_LINUX_KERNEL) + drgn_prstatus_vector_deinit(&prog->prstatus_vector); + else + drgn_prstatus_map_deinit(&prog->prstatus_map); + } else { + prog->prstatus_cached = true; + } + return err; +} + +struct drgn_error *drgn_program_find_prstatus_by_cpu(struct drgn_program *prog, + uint32_t cpu, + struct string *ret) +{ + struct drgn_error *err; + + assert(prog->flags & DRGN_PROGRAM_IS_LINUX_KERNEL); + err = drgn_program_cache_prstatus(prog); + if (err) + return err; + + if (cpu < prog->prstatus_vector.size) { + *ret = prog->prstatus_vector.data[cpu]; + } else { + ret->str = NULL; + ret->len = 0; + } return NULL; } -struct drgn_error *drgn_program_find_prstatus(struct drgn_program *prog, - uint32_t tid, struct string *ret) +struct drgn_error *drgn_program_find_prstatus_by_tid(struct drgn_program *prog, + uint32_t tid, + struct string *ret) { struct drgn_error *err; struct drgn_prstatus_map_iterator it; - if (!prog->prstatus_cached) { - err = drgn_program_cache_prstatus(prog); - if (err) - return err; - prog->prstatus_cached = true; - } + assert(!(prog->flags & DRGN_PROGRAM_IS_LINUX_KERNEL)); + err = drgn_program_cache_prstatus(prog); + if (err) + return err; - it = drgn_prstatus_map_search(&prog->prstatus_cache, &tid); + it = drgn_prstatus_map_search(&prog->prstatus_map, &tid); if (!it.entry) { ret->str = NULL; ret->len = 0; diff --git a/libdrgn/program.h b/libdrgn/program.h index ac1602dbb..f4db36c6c 100644 --- a/libdrgn/program.h +++ b/libdrgn/program.h @@ -1,4 +1,4 @@ -// Copyright 2018-2020 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ /** @@ -22,6 +22,7 @@ #include "object_index.h" #include "platform.h" #include "type_index.h" +#include "vector.h" /** * @ingroup Internals @@ -53,6 +54,7 @@ struct vmcoreinfo { bool pgtable_l5_enabled; }; +DEFINE_VECTOR_TYPE(drgn_prstatus_vector, struct string) DEFINE_HASH_MAP_TYPE(drgn_prstatus_map, uint32_t, struct string) struct drgn_dwarf_info_cache; @@ -74,6 +76,8 @@ struct drgn_program { uint64_t page_offset; /* Cached vmemmap. */ uint64_t vmemmap; + /* Cached THREAD_SIZE. */ + uint64_t thread_size; #ifdef WITH_LIBKDUMPFILE kdump_ctx_t *kdump_ctx; #endif @@ -90,7 +94,16 @@ struct drgn_program { */ pid_t pid; struct drgn_dwarf_info_cache *_dicache; - struct drgn_prstatus_map prstatus_cache; + union { + /* + * For the Linux kernel, PRSTATUS notes indexed by CPU. See @ref + * drgn_architecture_info::linux_kernel_set_initial_registers + * for why we don't use the PID map. + */ + struct drgn_prstatus_vector prstatus_vector; + /* For userspace programs, PRSTATUS notes indexed by PID. */ + struct drgn_prstatus_map prstatus_map; + }; /* See @ref drgn_object_stack_trace(). */ struct drgn_error *stack_trace_err; /* See @ref drgn_object_stack_trace_next_thread(). */ @@ -170,16 +183,29 @@ static inline bool drgn_program_is_64_bit(struct drgn_program *prog) struct drgn_error *drgn_program_get_dwfl(struct drgn_program *prog, Dwfl **ret); +/** + * Find the @c NT_PRSTATUS note for the given CPU. + * + * This is only valid for the Linux kernel. + * + * @param[out] ret Returned note data. If not found, ret->str is set to + * @c NULL and ret->len is set to zero. + */ +struct drgn_error *drgn_program_find_prstatus_by_cpu(struct drgn_program *prog, + uint32_t cpu, + struct string *ret); + /** * Find the @c NT_PRSTATUS note for the given thread ID. * - * This assumes that prog->core is not @c NULL. + * This is only valid for userspace programs. * * @param[out] ret Returned note data. If not found, ret->str is set to * @c NULL and ret->len is set to zero. */ -struct drgn_error *drgn_program_find_prstatus(struct drgn_program *prog, - uint32_t tid, struct string *ret); +struct drgn_error *drgn_program_find_prstatus_by_tid(struct drgn_program *prog, + uint32_t tid, + struct string *ret); /** * Cache the @c NT_PRSTATUS note provided by @p data in @p prog. diff --git a/libdrgn/python/drgnpy.h b/libdrgn/python/drgnpy.h index e916f61cf..96c7d303a 100644 --- a/libdrgn/python/drgnpy.h +++ b/libdrgn/python/drgnpy.h @@ -1,4 +1,4 @@ -// Copyright 2018-2020 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #ifndef DRGNPY_H diff --git a/libdrgn/python/error.c b/libdrgn/python/error.c index 8116fd27a..dedb40898 100644 --- a/libdrgn/python/error.c +++ b/libdrgn/python/error.c @@ -1,4 +1,4 @@ -// Copyright 2018-2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #include "drgnpy.h" diff --git a/libdrgn/python/helpers.c b/libdrgn/python/helpers.c index 189831bf7..805255066 100644 --- a/libdrgn/python/helpers.c +++ b/libdrgn/python/helpers.c @@ -1,4 +1,4 @@ -// Copyright 2019-2020 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #include "drgnpy.h" diff --git a/libdrgn/python/language.c b/libdrgn/python/language.c index d5b9b6e76..b677215a2 100644 --- a/libdrgn/python/language.c +++ b/libdrgn/python/language.c @@ -1,4 +1,4 @@ -// Copyright 2020 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #include "drgnpy.h" diff --git a/libdrgn/python/module.c b/libdrgn/python/module.c index 981c1aed1..92d5185f4 100644 --- a/libdrgn/python/module.c +++ b/libdrgn/python/module.c @@ -1,4 +1,4 @@ -// Copyright 2018-2020 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #include "drgnpy.h" diff --git a/libdrgn/python/object.c b/libdrgn/python/object.c index 99b4b7833..117c99c61 100644 --- a/libdrgn/python/object.c +++ b/libdrgn/python/object.c @@ -1,4 +1,4 @@ -// Copyright 2018-2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #include @@ -9,32 +9,6 @@ #include "../serialize.h" #include "../type.h" -static DrgnObject *DrgnObject_new(PyTypeObject *subtype, PyObject *args, - PyObject *kwds) -{ - PyObject *arg; - - if (PyTuple_GET_SIZE(args) < 1) { - PyErr_SetString(PyExc_TypeError, - "Object() missing required argument 'prog' (pos 1)"); - return NULL; - } - arg = PyTuple_GET_ITEM(args, 0); - if (!PyObject_TypeCheck(arg, &Program_type)) { - PyErr_SetString(PyExc_TypeError, - "Object() argument 1 must be Program"); - return NULL; - } - return DrgnObject_alloc((Program *)arg); -} - -static void DrgnObject_dealloc(DrgnObject *self) -{ - Py_DECREF(DrgnObject_prog(self)); - drgn_object_deinit(&self->obj); - Py_TYPE(self)->tp_free((PyObject *)self); -} - static int DrgnObject_literal(struct drgn_object *res, PyObject *literal) { struct drgn_error *err; @@ -393,7 +367,8 @@ static int buffer_object_from_value(struct drgn_object *res, return 0; } -static int DrgnObject_init(DrgnObject *self, PyObject *args, PyObject *kwds) +static DrgnObject *DrgnObject_new(PyTypeObject *subtype, PyObject *args, + PyObject *kwds) { static char *keywords[] = { "prog", "type", "value", "address", "byteorder", @@ -411,44 +386,41 @@ static int DrgnObject_init(DrgnObject *self, PyObject *args, PyObject *kwds) struct index_arg bit_offset = { .allow_none = true, .is_none = true }; struct index_arg bit_field_size = { .allow_none = true, .is_none = true }; struct drgn_qualified_type qualified_type; + DrgnObject *obj; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|O$OO&O&O&O&:Object", + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|OO$O&O&O&O&:Object", keywords, &Program_type, &prog, &type_obj, &value_obj, index_converter, &address, byteorder_converter, &byteorder, index_converter, &bit_offset, index_converter, &bit_field_size)) - return -1; - - if (&prog->prog != self->obj.prog) { - PyErr_SetString(PyExc_ValueError, - "cannot change object program"); - return -1; - } + return NULL; - if (Program_type_arg(DrgnObject_prog(self), type_obj, true, - &qualified_type) == -1) - return -1; + if (Program_type_arg(prog, type_obj, true, &qualified_type) == -1) + return NULL; if (!bit_field_size.is_none && bit_field_size.uvalue == 0) { PyErr_SetString(PyExc_ValueError, "bit field size cannot be zero"); - return -1; + return NULL; } + obj = DrgnObject_alloc(prog); + if (!obj) + return NULL; if (!address.is_none && value_obj != Py_None) { PyErr_SetString(PyExc_ValueError, "object cannot have address and value"); - return -1; + goto err; } else if (!address.is_none) { if (!qualified_type.type) { PyErr_SetString(PyExc_ValueError, "reference must have type"); - return -1; + goto err; } - err = drgn_object_set_reference(&self->obj, qualified_type, + err = drgn_object_set_reference(&obj->obj, qualified_type, address.uvalue, bit_offset.uvalue, bit_field_size.uvalue, @@ -459,27 +431,27 @@ static int DrgnObject_init(DrgnObject *self, PyObject *args, PyObject *kwds) if (!byteorder.is_none) { PyErr_SetString(PyExc_ValueError, "literal cannot have byteorder"); - return -1; + goto err; } if (!bit_offset.is_none) { PyErr_SetString(PyExc_ValueError, "literal cannot have bit offset"); - return -1; + goto err; } if (!bit_field_size.is_none) { PyErr_SetString(PyExc_ValueError, "literal cannot be bit field"); - return -1; + goto err; } - ret = DrgnObject_literal(&self->obj, value_obj); + ret = DrgnObject_literal(&obj->obj, value_obj); if (ret == -1) { - return -1; + goto err; } else if (ret) { PyErr_Format(PyExc_TypeError, "cannot create %s literal", Py_TYPE(value_obj)->tp_name); - return -1; + goto err; } err = NULL; } else if (value_obj != Py_None) { @@ -490,35 +462,35 @@ static int DrgnObject_init(DrgnObject *self, PyObject *args, PyObject *kwds) err = drgn_error_incomplete_type("cannot create object with %s type", qualified_type.type); set_drgn_error(err); - return -1; + goto err; } if (!bit_field_size.is_none && kind != DRGN_OBJECT_SIGNED && kind != DRGN_OBJECT_UNSIGNED) { PyErr_SetString(PyExc_ValueError, "bit field must be integer"); - return -1; + goto err; } if (kind != DRGN_OBJECT_BUFFER) { if (!byteorder.is_none) { PyErr_SetString(PyExc_ValueError, "primitive value cannot have byteorder"); - return -1; + goto err; } if (!bit_offset.is_none) { PyErr_SetString(PyExc_ValueError, "primitive value cannot have bit offset"); - return -1; + goto err; } } switch (kind) { case DRGN_OBJECT_BUFFER: - if (buffer_object_from_value(&self->obj, qualified_type, + if (buffer_object_from_value(&obj->obj, qualified_type, value_obj, bit_offset.uvalue, byteorder.value) == -1) - return -1; + goto err; err = NULL; break; case DRGN_OBJECT_SIGNED: @@ -532,23 +504,23 @@ static int DrgnObject_init(DrgnObject *self, PyObject *args, PyObject *kwds) if (!PyNumber_Check(value_obj)) { set_error_type_name("'%s' value must be number", qualified_type); - return -1; + goto err; } long_obj = PyNumber_Long(value_obj); if (!long_obj) - return -1; + goto err; tmp.uvalue = PyLong_AsUnsignedLongLongMask(long_obj); Py_DECREF(long_obj); if (tmp.uvalue == (unsigned long long)-1 && PyErr_Occurred()) - return -1; + goto err; if (kind == DRGN_OBJECT_SIGNED) { - err = drgn_object_set_signed(&self->obj, + err = drgn_object_set_signed(&obj->obj, qualified_type, tmp.svalue, bit_field_size.uvalue); } else { - err = drgn_object_set_unsigned(&self->obj, + err = drgn_object_set_unsigned(&obj->obj, qualified_type, tmp.uvalue, bit_field_size.uvalue); @@ -561,12 +533,12 @@ static int DrgnObject_init(DrgnObject *self, PyObject *args, PyObject *kwds) if (!PyNumber_Check(value_obj)) { set_error_type_name("'%s' value must be number", qualified_type); - return -1; + goto err; } fvalue = PyFloat_AsDouble(value_obj); if (fvalue == -1.0 && PyErr_Occurred()) - return -1; - err = drgn_object_set_float(&self->obj, qualified_type, + goto err; + err = drgn_object_set_float(&obj->obj, qualified_type, fvalue); break; } @@ -576,13 +548,24 @@ static int DrgnObject_init(DrgnObject *self, PyObject *args, PyObject *kwds) } else { PyErr_SetString(PyExc_ValueError, "object must have either address or value"); - return -1; + goto err; } if (err) { set_drgn_error(err); - return -1; + goto err; } - return 0; + return obj; + +err: + Py_DECREF(obj); + return NULL; +} + +static void DrgnObject_dealloc(DrgnObject *self) +{ + Py_DECREF(DrgnObject_prog(self)); + drgn_object_deinit(&self->obj); + Py_TYPE(self)->tp_free((PyObject *)self); } static PyObject *DrgnObject_value_impl(struct drgn_object *obj); @@ -1743,7 +1726,6 @@ PyTypeObject DrgnObject_type = { .tp_iter = (getiterfunc)DrgnObject_iter, .tp_methods = DrgnObject_methods, .tp_getset = DrgnObject_getset, - .tp_init = (initproc)DrgnObject_init, .tp_new = (newfunc)DrgnObject_new, }; diff --git a/libdrgn/python/platform.c b/libdrgn/python/platform.c index 281ac1b09..43a7c39da 100644 --- a/libdrgn/python/platform.c +++ b/libdrgn/python/platform.c @@ -1,4 +1,4 @@ -// Copyright 2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #include "drgnpy.h" diff --git a/libdrgn/python/program.c b/libdrgn/python/program.c index 5d4ad9b92..bcd0d0959 100644 --- a/libdrgn/python/program.c +++ b/libdrgn/python/program.c @@ -1,4 +1,4 @@ -// Copyright 2018-2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #include "drgnpy.h" diff --git a/libdrgn/python/stack_trace.c b/libdrgn/python/stack_trace.c index 21bf3a411..6653311e9 100644 --- a/libdrgn/python/stack_trace.c +++ b/libdrgn/python/stack_trace.c @@ -1,4 +1,4 @@ -// Copyright 2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #include "drgnpy.h" diff --git a/libdrgn/python/symbol.c b/libdrgn/python/symbol.c index 77ea47d66..8fc2bfa26 100644 --- a/libdrgn/python/symbol.c +++ b/libdrgn/python/symbol.c @@ -1,4 +1,4 @@ -// Copyright 2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #include "drgnpy.h" diff --git a/libdrgn/python/test.c b/libdrgn/python/test.c index 24af51df8..2077a31ed 100644 --- a/libdrgn/python/test.c +++ b/libdrgn/python/test.c @@ -1,4 +1,4 @@ -// Copyright 2018-2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ /* diff --git a/libdrgn/python/type.c b/libdrgn/python/type.c index 893b64943..649dcfff2 100644 --- a/libdrgn/python/type.c +++ b/libdrgn/python/type.c @@ -1,4 +1,4 @@ -// Copyright 2018-2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #include "drgnpy.h" diff --git a/libdrgn/python/util.c b/libdrgn/python/util.c index d0dfb2c5c..aa419c4bb 100644 --- a/libdrgn/python/util.c +++ b/libdrgn/python/util.c @@ -1,4 +1,4 @@ -// Copyright 2018-2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #include "drgnpy.h" diff --git a/libdrgn/read.h b/libdrgn/read.h index 9f0231e93..7b9b16ff5 100644 --- a/libdrgn/read.h +++ b/libdrgn/read.h @@ -1,4 +1,4 @@ -// Copyright 2018-2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ /** diff --git a/libdrgn/serialize.c b/libdrgn/serialize.c index 9b739599a..91cfa0f35 100644 --- a/libdrgn/serialize.c +++ b/libdrgn/serialize.c @@ -1,4 +1,4 @@ -// Copyright 2018-2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #include diff --git a/libdrgn/serialize.h b/libdrgn/serialize.h index b22434c93..43ed0453f 100644 --- a/libdrgn/serialize.h +++ b/libdrgn/serialize.h @@ -1,4 +1,4 @@ -// Copyright 2018-2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ /** diff --git a/libdrgn/siphash.h b/libdrgn/siphash.h index 997718d3d..fd522d521 100644 --- a/libdrgn/siphash.h +++ b/libdrgn/siphash.h @@ -1,4 +1,4 @@ -// Copyright 2018 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #ifndef DRGN_SIPHASH_H diff --git a/libdrgn/splay_tree.c b/libdrgn/splay_tree.c index f10e0dd7c..7b216fc73 100644 --- a/libdrgn/splay_tree.c +++ b/libdrgn/splay_tree.c @@ -1,4 +1,4 @@ -// Copyright 2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #include "binary_search_tree.h" diff --git a/libdrgn/stack_trace.c b/libdrgn/stack_trace.c index 771009e53..d3c344df8 100644 --- a/libdrgn/stack_trace.c +++ b/libdrgn/stack_trace.c @@ -1,4 +1,4 @@ -// Copyright 2019-2020 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #include @@ -241,135 +241,17 @@ drgn_get_stack_trace_obj(struct drgn_object *res, struct drgn_program *prog, ", struct task_struct *" : ""); } -static struct drgn_error * -drgn_pt_regs_set_initial_registers(Dwfl_Thread *thread, - struct drgn_platform *platform, - const struct drgn_object *pt_regs) -{ - struct drgn_error *err; - struct drgn_object obj; - size_t i; - - drgn_object_init(&obj, pt_regs->prog); - - if (!platform->arch->num_frame_registers) { - return drgn_error_format(DRGN_ERROR_INVALID_ARGUMENT, - "pt_regs stack unwinding is not supported for %s architecture", - platform->arch->name); - } - - for (i = 0; i < platform->arch->num_frame_registers; i++) { - const struct drgn_frame_register *reg; - union drgn_value value; - Dwarf_Word word; - - reg = &platform->arch->frame_registers[i]; - err = drgn_object_member(&obj, pt_regs, reg->pt_regs_name); - if (err && err->code == DRGN_ERROR_LOOKUP && - reg->pt_regs_name2) { - drgn_error_destroy(err); - err = drgn_object_member(&obj, pt_regs, - reg->pt_regs_name2); - } - if (err) - goto out; - err = drgn_object_read_integer(&obj, &value); - if (err) - goto out; - word = value.uvalue; - if (!dwfl_thread_state_registers(thread, reg->number, 1, &word)) - return drgn_error_libdwfl(); - } - err = NULL; -out: - drgn_object_deinit(&obj); - return err; -} - -static struct drgn_error * -drgn_get_task_pid(const struct drgn_object *task, uint32_t *ret) -{ - struct drgn_error *err; - struct drgn_object pid; - union drgn_value value; - - drgn_object_init(&pid, task->prog); - err = drgn_object_member_dereference(&pid, task, "pid"); - if (err) - goto out; - err = drgn_object_read_integer(&pid, &value); - if (err) - goto out; - *ret = value.uvalue; -out: - drgn_object_deinit(&pid); - return err; -} - -static struct drgn_error * -drgn_prstatus_set_initial_registers(Dwfl_Thread *thread, - struct drgn_platform *platform, - struct string *prstatus) -{ - bool bswap = (!!(platform->flags & DRGN_PLATFORM_IS_LITTLE_ENDIAN) != - (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)); - size_t i; - - if (!platform->arch->num_frame_registers) { - return drgn_error_format(DRGN_ERROR_INVALID_ARGUMENT, - "core dump stack unwinding is not supported for %s architecture", - platform->arch->name); - } - - for (i = 0; i < platform->arch->num_frame_registers; i++) { - const struct drgn_frame_register *reg; - const char *p; - Dwarf_Word word; - - reg = &platform->arch->frame_registers[i]; - if (prstatus->len < reg->prstatus_offset + reg->size) { - return drgn_error_create(DRGN_ERROR_OTHER, - "NT_PRSTATUS is truncated"); - } - p = prstatus->str + reg->prstatus_offset; - switch (reg->size) { - case 4: { - uint32_t tmp; - - memcpy(&tmp, p, sizeof(tmp)); - if (bswap) - tmp = bswap_32(tmp); - word = tmp; - break; - } - case 8: { - uint64_t tmp; - - memcpy(&tmp, p, sizeof(tmp)); - if (bswap) - tmp = bswap_64(tmp); - word = tmp; - break; - } - default: - UNREACHABLE(); - } - if (!dwfl_thread_state_registers(thread, reg->number, 1, &word)) - return drgn_error_libdwfl(); - } - return NULL; -} - static bool drgn_thread_set_initial_registers(Dwfl_Thread *thread, void *thread_arg) { struct drgn_error *err; struct drgn_program *prog = thread_arg; struct drgn_object obj; - bool truthy; - char state; + struct drgn_object tmp; + struct string prstatus; drgn_object_init(&obj, prog); + drgn_object_init(&tmp, prog); /* First, try pt_regs. */ if (prog->stack_trace_obj) { @@ -380,90 +262,121 @@ static bool drgn_thread_set_initial_registers(Dwfl_Thread *thread, goto out; if (is_pt_regs) { - assert(obj.kind == DRGN_OBJECT_BUFFER); - err = drgn_pt_regs_set_initial_registers(thread, - &prog->platform, - &obj); + assert(obj.kind == DRGN_OBJECT_BUFFER && + !obj.is_reference); + if (!prog->platform.arch->pt_regs_set_initial_registers) { + err = drgn_error_format(DRGN_ERROR_INVALID_ARGUMENT, + "pt_regs stack unwinding is not supported for %s architecture", + prog->platform.arch->name); + goto out; + } + err = prog->platform.arch->pt_regs_set_initial_registers(thread, + &obj); goto out; } - } + } else if (prog->flags & DRGN_PROGRAM_IS_LINUX_KERNEL) { + bool found; - /* Then, try the core dump (and/or kdump if supported). */ -#ifdef WITH_LIBKDUMPFILE - if (prog->core || prog->kdump_ctx) { -#else - if (prog->core) { -#endif - uint32_t tid; - struct string prstatus; - - if (prog->stack_trace_obj) { - err = drgn_get_task_pid(&obj, &tid); - if (err) - goto out; - } else { - tid = prog->stack_trace_tid; - } - err = drgn_program_find_prstatus(prog, tid, &prstatus); + err = drgn_program_find_object(prog, "init_pid_ns", NULL, + DRGN_FIND_OBJECT_ANY, &tmp); + if (err) + goto out; + err = drgn_object_address_of(&tmp, &tmp); if (err) goto out; - if (prstatus.str) { - err = drgn_prstatus_set_initial_registers(thread, - &prog->platform, - &prstatus); + err = linux_helper_find_task(&obj, &tmp, prog->stack_trace_tid); + if (err) + goto out; + err = drgn_object_bool(&obj, &found); + if (err) + goto out; + if (!found) { + err = drgn_error_create(DRGN_ERROR_LOOKUP, "task not found"); goto out; } } - /* Finally, try the task_struct. */ - if (!(prog->flags & DRGN_PROGRAM_IS_LINUX_KERNEL)) { - err = drgn_error_create(DRGN_ERROR_LOOKUP, "thread not found"); - goto out; - } - - if (!prog->platform.arch->linux_kernel_set_initial_registers) { - err = drgn_error_format(DRGN_ERROR_INVALID_ARGUMENT, - "Linux kernel stack unwinding is not supported for %s architecture", - prog->platform.arch->name); - goto out; - } - - if (!prog->stack_trace_obj) { - struct drgn_object ns; - - drgn_object_init(&ns, prog); - err = drgn_program_find_object(prog, "init_pid_ns", NULL, - DRGN_FIND_OBJECT_ANY, &ns); - if (!err) - err = drgn_object_address_of(&ns, &ns); - if (!err) { - err = linux_helper_find_task(&obj, &ns, - prog->stack_trace_tid); + if (prog->flags & DRGN_PROGRAM_IS_LINUX_KERNEL) { + if (prog->flags & DRGN_PROGRAM_IS_LIVE) { + err = drgn_object_member_dereference(&tmp, &obj, "on_cpu"); + if (!err) { + bool on_cpu; + err = drgn_object_bool(&tmp, &on_cpu); + if (err) + goto out; + if (on_cpu) { + err = drgn_error_create(DRGN_ERROR_INVALID_ARGUMENT, + "cannot unwind stack of running task"); + goto out; + } + } else if (err->code == DRGN_ERROR_LOOKUP) { + /* + * The running kernel is !SMP. Assume that the + * task isn't running (which can only be wrong + * for this thread itself). + */ + drgn_error_destroy(err); + } else { + goto out; + } + prstatus.str = NULL; + prstatus.len = 0; + } else { + union drgn_value value; + uint32_t cpu; + + err = drgn_object_member_dereference(&tmp, &obj, "cpu"); + if (!err) { + err = drgn_object_read_integer(&tmp, &value); + if (err) + goto out; + cpu = value.uvalue; + } else if (err->code == DRGN_ERROR_LOOKUP) { + /* !SMP. Must be CPU 0. */ + drgn_error_destroy(err); + cpu = 0; + } else { + goto out; + } + err = drgn_program_find_prstatus_by_cpu(prog, cpu, + &prstatus); + if (err) + goto out; + } + if (!prog->platform.arch->linux_kernel_set_initial_registers) { + err = drgn_error_format(DRGN_ERROR_INVALID_ARGUMENT, + "Linux kernel stack unwinding is not supported for %s architecture", + prog->platform.arch->name); + goto out; } - drgn_object_deinit(&ns); + err = prog->platform.arch->linux_kernel_set_initial_registers(thread, + &obj, + prstatus.str, + prstatus.len); + } else { + err = drgn_program_find_prstatus_by_tid(prog, + prog->stack_trace_tid, + &prstatus); if (err) goto out; - } - err = drgn_object_bool(&obj, &truthy); - if (err) - goto out; - if (!truthy) { - err = drgn_error_create(DRGN_ERROR_LOOKUP, "task not found"); - goto out; - } - - err = linux_helper_task_state_to_char(&obj, &state); - if (err) - goto out; - if (state == 'R') { - err = drgn_error_create(DRGN_ERROR_INVALID_ARGUMENT, - "cannot unwind stack of running task"); - goto out; + if (!prstatus.str) { + err = drgn_error_create(DRGN_ERROR_LOOKUP, "thread not found"); + goto out; + } + if (!prog->platform.arch->prstatus_set_initial_registers) { + err = drgn_error_format(DRGN_ERROR_INVALID_ARGUMENT, + "core dump stack unwinding is not supported for %s architecture", + prog->platform.arch->name); + goto out; + } + err = prog->platform.arch->prstatus_set_initial_registers(prog, + thread, + prstatus.str, + prstatus.len); } - err = prog->platform.arch->linux_kernel_set_initial_registers(thread, - &obj); out: + drgn_object_deinit(&tmp); drgn_object_deinit(&obj); if (err) { drgn_error_destroy(prog->stack_trace_err); diff --git a/libdrgn/string_builder.c b/libdrgn/string_builder.c index a738e8878..1fbf86b3c 100644 --- a/libdrgn/string_builder.c +++ b/libdrgn/string_builder.c @@ -1,4 +1,4 @@ -// Copyright 2018-2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #include diff --git a/libdrgn/string_builder.h b/libdrgn/string_builder.h index cfdb194db..a517c0686 100644 --- a/libdrgn/string_builder.h +++ b/libdrgn/string_builder.h @@ -1,4 +1,4 @@ -// Copyright 2018-2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ /** diff --git a/libdrgn/symbol.c b/libdrgn/symbol.c index 37d092d4a..369452c21 100644 --- a/libdrgn/symbol.c +++ b/libdrgn/symbol.c @@ -1,4 +1,4 @@ -// Copyright 2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #include diff --git a/libdrgn/symbol.h b/libdrgn/symbol.h index c57997839..f6cf4ddb5 100644 --- a/libdrgn/symbol.h +++ b/libdrgn/symbol.h @@ -1,4 +1,4 @@ -// Copyright 2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #ifndef DRGN_SYMBOL_H diff --git a/libdrgn/type.c b/libdrgn/type.c index aa07da60b..f09f0b104 100644 --- a/libdrgn/type.c +++ b/libdrgn/type.c @@ -1,3 +1,6 @@ +// Copyright (c) Facebook, Inc. and its affiliates. +// SPDX-License-Identifier: GPL-3.0+ + #include #include "internal.h" diff --git a/libdrgn/type.h b/libdrgn/type.h index 46c451e61..4acae99e2 100644 --- a/libdrgn/type.h +++ b/libdrgn/type.h @@ -1,4 +1,4 @@ -// Copyright 2018-2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ /** diff --git a/libdrgn/type_index.c b/libdrgn/type_index.c index c9f5ce49a..5b5113fef 100644 --- a/libdrgn/type_index.c +++ b/libdrgn/type_index.c @@ -1,4 +1,4 @@ -// Copyright 2018-2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #include diff --git a/libdrgn/type_index.h b/libdrgn/type_index.h index 8bfc5b813..46425ac2f 100644 --- a/libdrgn/type_index.h +++ b/libdrgn/type_index.h @@ -1,4 +1,4 @@ -// Copyright 2018-2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ /** diff --git a/libdrgn/util.h b/libdrgn/util.h index 7a756d7b9..085999bdd 100644 --- a/libdrgn/util.h +++ b/libdrgn/util.h @@ -1,4 +1,4 @@ -// Copyright 2018-2020 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ /** diff --git a/libdrgn/vector.c b/libdrgn/vector.c index 2eefa6696..573a10c0e 100644 --- a/libdrgn/vector.c +++ b/libdrgn/vector.c @@ -1,4 +1,4 @@ -// Copyright 2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ #include "vector.h" diff --git a/libdrgn/vector.h b/libdrgn/vector.h index 3261885f9..3e3a96b0a 100644 --- a/libdrgn/vector.h +++ b/libdrgn/vector.h @@ -1,4 +1,4 @@ -// Copyright 2019 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ /** diff --git a/scripts/generate_dwarf_constants.py b/scripts/generate_dwarf_constants.py index 09dd9c88c..ae62a6300 100755 --- a/scripts/generate_dwarf_constants.py +++ b/scripts/generate_dwarf_constants.py @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ import keyword import re diff --git a/scripts/generate_primitive_type_spellings.py b/scripts/generate_primitive_type_spellings.py index e755b94f3..03b943dad 100755 --- a/scripts/generate_primitive_type_spellings.py +++ b/scripts/generate_primitive_type_spellings.py @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ import itertools import sys diff --git a/scripts/test_cityhash.c b/scripts/test_cityhash.c index bd2a79869..3f9d2ebed 100644 --- a/scripts/test_cityhash.c +++ b/scripts/test_cityhash.c @@ -1,3 +1,6 @@ +// Copyright (c) Facebook, Inc. and its affiliates. +// SPDX-License-Identifier: GPL-3.0+ + #include #include diff --git a/scripts/test_siphash.c b/scripts/test_siphash.c index f070f0264..f84ac8bdf 100644 --- a/scripts/test_siphash.c +++ b/scripts/test_siphash.c @@ -1,3 +1,6 @@ +// Copyright (c) Facebook, Inc. and its affiliates. +// SPDX-License-Identifier: GPL-3.0+ + #include #include #include diff --git a/scripts/update-elfutils.sh b/scripts/update-elfutils.sh index 013f788d6..bc9029055 100755 --- a/scripts/update-elfutils.sh +++ b/scripts/update-elfutils.sh @@ -1,4 +1,6 @@ #!/bin/sh +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ # drgn depends heavily on elfutils. In particular, we need a recent version, # potentially with some patches that may not be released or even merged yet. We diff --git a/setup.py b/setup.py index 143a2466e..2b21b9183 100755 --- a/setup.py +++ b/setup.py @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ import contextlib from distutils import log diff --git a/tests/__init__.py b/tests/__init__.py index 2b2b523c3..96d7366ca 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,3 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ + import functools from typing import Any, NamedTuple, Optional import unittest diff --git a/tests/dwarfwriter.py b/tests/dwarfwriter.py index f87255dac..8073d0ed9 100644 --- a/tests/dwarfwriter.py +++ b/tests/dwarfwriter.py @@ -1,3 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ + from collections import namedtuple import os.path diff --git a/tests/elf.py b/tests/elf.py index 26ac9614a..8a99f5ca9 100644 --- a/tests/elf.py +++ b/tests/elf.py @@ -1,3 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ + import enum diff --git a/tests/elfwriter.py b/tests/elfwriter.py index 56f90b5f9..b96246eb7 100644 --- a/tests/elfwriter.py +++ b/tests/elfwriter.py @@ -1,3 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ + import struct from typing import Optional, Sequence diff --git a/tests/helpers/linux/__init__.py b/tests/helpers/linux/__init__.py index b0f96f3a4..42abe34d3 100644 --- a/tests/helpers/linux/__init__.py +++ b/tests/helpers/linux/__init__.py @@ -1,3 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ + import ctypes import errno import os diff --git a/tests/helpers/linux/test_block.py b/tests/helpers/linux/test_block.py index 9666c1163..b77b77b5e 100644 --- a/tests/helpers/linux/test_block.py +++ b/tests/helpers/linux/test_block.py @@ -1,3 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ + import errno from fcntl import ioctl import os diff --git a/tests/helpers/linux/test_cgroup.py b/tests/helpers/linux/test_cgroup.py index ed4ee5712..686657af1 100644 --- a/tests/helpers/linux/test_cgroup.py +++ b/tests/helpers/linux/test_cgroup.py @@ -1,3 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ + import os diff --git a/tests/helpers/linux/test_fs.py b/tests/helpers/linux/test_fs.py index 4fbad7076..dbcccb394 100644 --- a/tests/helpers/linux/test_fs.py +++ b/tests/helpers/linux/test_fs.py @@ -1,3 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ + import os import os.path import tempfile diff --git a/tests/helpers/linux/test_kconfig.py b/tests/helpers/linux/test_kconfig.py index 2992140bf..83d0d80ac 100644 --- a/tests/helpers/linux/test_kconfig.py +++ b/tests/helpers/linux/test_kconfig.py @@ -1,3 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ + import os.path from drgn.helpers.linux.kconfig import get_kconfig diff --git a/tests/helpers/linux/test_kernfs.py b/tests/helpers/linux/test_kernfs.py index 5c3d63721..4ceaf0178 100644 --- a/tests/helpers/linux/test_kernfs.py +++ b/tests/helpers/linux/test_kernfs.py @@ -1,3 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ + import os from drgn import cast diff --git a/tests/helpers/linux/test_mm.py b/tests/helpers/linux/test_mm.py index 7227915a1..edd8dca89 100644 --- a/tests/helpers/linux/test_mm.py +++ b/tests/helpers/linux/test_mm.py @@ -1,3 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ + import contextlib import ctypes import mmap diff --git a/tests/helpers/linux/test_net.py b/tests/helpers/linux/test_net.py index b20dc8025..ff909a139 100644 --- a/tests/helpers/linux/test_net.py +++ b/tests/helpers/linux/test_net.py @@ -1,3 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ + import os from drgn import cast diff --git a/tests/helpers/linux/test_pid.py b/tests/helpers/linux/test_pid.py index cbd3e9a8f..7fe870ed5 100644 --- a/tests/helpers/linux/test_pid.py +++ b/tests/helpers/linux/test_pid.py @@ -1,3 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ + import os from drgn.helpers.linux.pid import ( diff --git a/tests/helpers/linux/test_sched.py b/tests/helpers/linux/test_sched.py index edff69439..548b4c498 100644 --- a/tests/helpers/linux/test_sched.py +++ b/tests/helpers/linux/test_sched.py @@ -1,3 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ + import os import re import signal @@ -12,6 +15,10 @@ ) +def is_power_of_two(n): + return n != 0 and (n & (n - 1)) == 0 + + class TestSched(LinuxHelperTestCase): def test_task_state_to_char(self): task = find_task(self.prog, os.getpid()) @@ -32,3 +39,15 @@ def test_task_state_to_char(self): self.assertEqual(task_state_to_char(task), "Z") os.waitpid(pid, 0) + + def test_thread_size(self): + # As far as I can tell, there's no way to query this value from + # userspace, so at least sanity check that it's a power-of-two multiple + # of the page size and that we can read the entire stack. + thread_size = self.prog["THREAD_SIZE"].value_() + page_size = self.prog["PAGE_SIZE"].value_() + self.assertEqual(thread_size % page_size, 0) + self.assertTrue(is_power_of_two(thread_size // page_size)) + + task = find_task(self.prog, os.getpid()) + self.prog.read(task.stack, thread_size) diff --git a/tests/helpers/linux/test_stack_trace.py b/tests/helpers/linux/test_stack_trace.py index 88e3e5026..44481e42e 100644 --- a/tests/helpers/linux/test_stack_trace.py +++ b/tests/helpers/linux/test_stack_trace.py @@ -1,3 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ + import os import signal diff --git a/tests/helpers/linux/test_tcp.py b/tests/helpers/linux/test_tcp.py index 5e2877c1c..e8fa2056e 100644 --- a/tests/helpers/linux/test_tcp.py +++ b/tests/helpers/linux/test_tcp.py @@ -1,3 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ + import os import socket diff --git a/tests/helpers/linux/test_user.py b/tests/helpers/linux/test_user.py index 021056b7a..47a9c0555 100644 --- a/tests/helpers/linux/test_user.py +++ b/tests/helpers/linux/test_user.py @@ -1,3 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ + import functools import os import signal diff --git a/tests/helpers/linux/test_uts.py b/tests/helpers/linux/test_uts.py index adb3804df..033262ef0 100644 --- a/tests/helpers/linux/test_uts.py +++ b/tests/helpers/linux/test_uts.py @@ -1,3 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ + import os import drgn diff --git a/tests/libdrgn.py b/tests/libdrgn.py index 1b6b49df2..8138a945f 100644 --- a/tests/libdrgn.py +++ b/tests/libdrgn.py @@ -1,3 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ + import ctypes import enum from enum import auto diff --git a/tests/test_docs.py b/tests/test_docs.py index 0cbeeb694..1288cf112 100644 --- a/tests/test_docs.py +++ b/tests/test_docs.py @@ -1,3 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ + import pydoc import unittest diff --git a/tests/test_dwarf.py b/tests/test_dwarf.py index acf43610a..27527bdb5 100644 --- a/tests/test_dwarf.py +++ b/tests/test_dwarf.py @@ -1,3 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ + import os.path import re import tempfile diff --git a/tests/test_language_c.py b/tests/test_language_c.py index 07077bda2..3aee580a3 100644 --- a/tests/test_language_c.py +++ b/tests/test_language_c.py @@ -1,3 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ + from functools import reduce import operator import unittest diff --git a/tests/test_lexer.py b/tests/test_lexer.py index ea62914d9..c2ff473b7 100644 --- a/tests/test_lexer.py +++ b/tests/test_lexer.py @@ -1,3 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ + import unittest from tests.libdrgn import drgn_test_lexer_func, Lexer diff --git a/tests/test_object.py b/tests/test_object.py index 6121cfbb9..c07dce858 100644 --- a/tests/test_object.py +++ b/tests/test_object.py @@ -1,3 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ + import math import operator import struct @@ -39,16 +42,6 @@ class TestInit(ObjectTestCase): - def test_reinit(self): - obj = Object(self.prog, "int", value=1) - self.assertEqual(obj.value_(), 1) - obj.__init__(self.prog, value=2) - self.assertEqual(obj.value_(), 2) - prog = mock_program() - self.assertRaisesRegex( - ValueError, "cannot change object program", obj.__init__, prog, value=3 - ) - def test_type_stays_alive(self): obj = Object(self.prog, int_type("int", 4, True), value=0) self.assertEqual(obj.type_, int_type("int", 4, True)) @@ -77,6 +70,15 @@ def test_address_xor_value(self): self.prog, "int", ) + self.assertRaisesRegex( + ValueError, + "object cannot have address and value", + Object, + self.prog, + "int", + 0, + address=0, + ) self.assertRaisesRegex( ValueError, "object cannot have address and value", @@ -370,6 +372,9 @@ def test_incomplete(self): class TestValue(ObjectTestCase): + def test_positional(self): + self.assertEqual(Object(self.prog, "int", 1), Object(self.prog, "int", value=1)) + def test_signed(self): obj = Object(self.prog, "int", value=-4) self.assertIs(obj.prog_, self.prog) diff --git a/tests/test_path.py b/tests/test_path.py index 50edb6d55..e3c0a7b9d 100644 --- a/tests/test_path.py +++ b/tests/test_path.py @@ -1,3 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ + import itertools import os.path import unittest diff --git a/tests/test_platform.py b/tests/test_platform.py index 58b7a87cf..2ddaea11f 100644 --- a/tests/test_platform.py +++ b/tests/test_platform.py @@ -1,3 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ + import unittest from drgn import Architecture, Platform, PlatformFlags diff --git a/tests/test_program.py b/tests/test_program.py index 090fad079..52c32f4ef 100644 --- a/tests/test_program.py +++ b/tests/test_program.py @@ -1,3 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ + import ctypes import itertools import os @@ -161,8 +164,7 @@ def test_read_unsigned(self): self.assertEqual(prog.read_word(0xA0, True), value) prog = mock_program( - MOCK_32BIT_PLATFORM, - segments=[MockMemorySegment(data, 0xFFFF0000, 0xA0)], + MOCK_32BIT_PLATFORM, segments=[MockMemorySegment(data, 0xFFFF0000, 0xA0)], ) def test_bad_address(self): diff --git a/tests/test_python.py b/tests/test_python.py index d881eda8f..44efd6af1 100644 --- a/tests/test_python.py +++ b/tests/test_python.py @@ -1,3 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ + import _drgn import drgn import unittest diff --git a/tests/test_serialize.py b/tests/test_serialize.py index 7840237d0..04ae95023 100644 --- a/tests/test_serialize.py +++ b/tests/test_serialize.py @@ -1,3 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ + import unittest from tests.libdrgn import deserialize_bits, serialize_bits diff --git a/tests/test_type.py b/tests/test_type.py index c7986eaa3..31a389b4a 100644 --- a/tests/test_type.py +++ b/tests/test_type.py @@ -1,3 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ + import unittest from drgn import ( diff --git a/tests/test_util.py b/tests/test_util.py index bf5cef82f..a88e4761b 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -1,3 +1,6 @@ +# Copyright (c) Facebook, Inc. and its affiliates. +# SPDX-License-Identifier: GPL-3.0+ + from functools import cmp_to_key import unittest diff --git a/tools/bpf_inspect.py b/tools/bpf_inspect.py index c4ac6c1d0..8fd5f986e 100755 --- a/tools/bpf_inspect.py +++ b/tools/bpf_inspect.py @@ -1,7 +1,6 @@ #!/usr/bin/env drgn +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ -# -# Copyright (c) 2020 Facebook DESCRIPTION = """ drgn script to list BPF programs or maps and their properties diff --git a/util.py b/util.py index 982bd9553..4ac7ab051 100644 --- a/util.py +++ b/util.py @@ -1,4 +1,4 @@ -# Copyright 2020 - Omar Sandoval +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ from functools import total_ordering diff --git a/vmtest/manage.py b/vmtest/manage.py index 7b121f14e..10058bba9 100644 --- a/vmtest/manage.py +++ b/vmtest/manage.py @@ -1,4 +1,4 @@ -# Copyright 2020 - Omar Sandoval +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ import aiohttp diff --git a/vmtest/onoatimehack.c b/vmtest/onoatimehack.c index 3d65f51cf..dd5c4fa82 100644 --- a/vmtest/onoatimehack.c +++ b/vmtest/onoatimehack.c @@ -1,4 +1,4 @@ -// Copyright 2020 - Omar Sandoval +// Copyright (c) Facebook, Inc. and its affiliates. // SPDX-License-Identifier: GPL-3.0+ /* diff --git a/vmtest/resolver.py b/vmtest/resolver.py index bf2f8fa84..ffa862ea7 100644 --- a/vmtest/resolver.py +++ b/vmtest/resolver.py @@ -1,4 +1,4 @@ -# Copyright 2020 - Omar Sandoval +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ import fnmatch diff --git a/vmtest/vm.py b/vmtest/vm.py index 569457f25..de1d7e690 100644 --- a/vmtest/vm.py +++ b/vmtest/vm.py @@ -1,4 +1,4 @@ -# Copyright 2020 - Omar Sandoval +# Copyright (c) Facebook, Inc. and its affiliates. # SPDX-License-Identifier: GPL-3.0+ import errno