// Copyright (c) Meta Platforms, Inc. and affiliates. // SPDX-License-Identifier: LGPL-2.1-or-later /** * @file * * libdrgn public interface. */ #ifndef DRGN_H #define DRGN_H // IWYU pragma: begin_exports #include #include #include // IWYU pragma: end_exports #include #include #include #include #include #include /** * @mainpage * * libdrgn provides the functionality of the * [drgn](https://github.com/osandov/drgn) programmable debugger as a library. * It implements the main drgn abstractions: @ref Programs, @ref Types, @ref * Objects, and @ref StackTraces. See [Modules](modules.html) for detailed * documentation. * * @subsection ThreadSafety Thread Safety * * Only one thread at a time should access the same @ref drgn_program (including * @ref drgn_object, @ref drgn_type, @ref drgn_stack_trace, etc. from that * program). It is safe to use different @ref drgn_program%s from concurrent * threads. */ /** Major version of drgn. */ #define DRGN_VERSION_MAJOR 0 /** Minor version of drgn. */ #define DRGN_VERSION_MINOR 0 /** Patch level of drgn. */ #define DRGN_VERSION_PATCH 27 /** * @defgroup ErrorHandling Error handling * * Error handling in libdrgn. * * Operations in libdrgn can fail for various reasons. libdrgn returns errors as * @ref drgn_error. * * @{ */ /** Error code for a @ref drgn_error. */ enum drgn_error_code { /** Cannot allocate memory. */ DRGN_ERROR_NO_MEMORY, /** Stop iteration. */ DRGN_ERROR_STOP, /** Miscellaneous error. */ DRGN_ERROR_OTHER, /** Invalid argument. */ DRGN_ERROR_INVALID_ARGUMENT, /** Integer overflow. */ DRGN_ERROR_OVERFLOW, /** Maximum recursion depth exceeded. */ DRGN_ERROR_RECURSION, /** System call error. */ DRGN_ERROR_OS, /** One or more files do not have debug information. */ DRGN_ERROR_MISSING_DEBUG_INFO, /** Syntax error while parsing. */ DRGN_ERROR_SYNTAX, /** Entry not found. */ DRGN_ERROR_LOOKUP, /** Bad memory access. */ DRGN_ERROR_FAULT, /** Type error in expression. */ DRGN_ERROR_TYPE, /** Division by zero. */ DRGN_ERROR_ZERO_DIVISION, /** Array out of bounds */ DRGN_ERROR_OUT_OF_BOUNDS, /** Operation was attempted with absent object. */ DRGN_ERROR_OBJECT_ABSENT, /** Functionality is not implemented. */ DRGN_ERROR_NOT_IMPLEMENTED, /** Number of defined error codes. */ DRGN_NUM_ERROR_CODES, } __attribute__((__packed__)); /** * libdrgn error. * * All functions in libdrgn that can return an error return this type. */ struct drgn_error { /** Error code. */ enum drgn_error_code code; /** * @private * * Whether this error needs to be passed to @ref drgn_error_destroy(). * * This is @c true for the error codes returned from @ref * drgn_error_create() and its related functions. Certain errors are * statically allocated and do not need to be passed to @ref * drgn_error_destroy() (but they can be). */ bool needs_destroy; /** * If @c code is @c DRGN_ERROR_OS, then the error number returned from * the system call. */ int errnum; /** * If @c code is @c DRGN_ERROR_OS, then the path of the file which * encountered the error if applicable. Otherwise, @c NULL. */ char *path; /** * If @c code is @c DRGN_ERROR_FAULT, then the address of the read * which encountered the error. */ uint64_t address; /** Human-readable error message. */ char *message; }; /** * Out of memory @ref drgn_error. * * This has a code of @ref DRGN_ERROR_NO_MEMORY. It can be returned if a memory * allocation fails in order to avoid doing another memory allocation. It does * not need to be passed to @ref drgn_error_destroy() (but it can be). */ extern struct drgn_error drgn_enomem; /** * Non-fatal lookup @ref drgn_error. * * This has a code of @ref DRGN_ERROR_LOOKUP. It does not need to be passed to * @ref drgn_error_destroy() (but it can be). */ extern struct drgn_error drgn_not_found; /** * Create a @ref drgn_error. * * @param[in] code Error code. * @param[in] message Human-readable error message. This string is copied. * @return A new error with the given code and message. If there is a failure to * allocate memory for the error or the message, @ref drgn_enomem is returned * instead. */ struct drgn_error *drgn_error_create(enum drgn_error_code code, const char *message) __attribute__((__returns_nonnull__)); /** * Create a @ref drgn_error from a printf-style format. * * @param[in] code Error code. * @param[in] format printf-style format string. * @param[in] ... Arguments for the format string. * @return A new error with the given code and formatted message. If there is a * failure to allocate memory for the error or the message, @ref drgn_enomem is * returned instead. */ struct drgn_error *drgn_error_format(enum drgn_error_code code, const char *format, ...) __attribute__((__returns_nonnull__, __format__(__printf__, 2, 3))); /** * Create a @ref DRGN_ERROR_OS @ref drgn_error. * * @sa drgn_error_create(). * * @param[in] errnum Error number (i.e., @c errno). * @param[in] path If not @c NULL, the path of the file which encountered the * error. This string is copied. */ struct drgn_error *drgn_error_create_os(const char *message, int errnum, const char *path) __attribute__((__returns_nonnull__)); /** * Create a @ref DRGN_ERROR_OS @ref drgn_error with a printf-style formatted * path. * * @param[in] errnum Error number (i.e., @c errno). * @param[in] path_format printf-style format string for path. * @param[in] ... Arguments for the format string. */ struct drgn_error *drgn_error_format_os(const char *message, int errnum, const char *path_format, ...) __attribute__((__returns_nonnull__, __format__(__printf__, 3, 4))); /** * Create a @ref DRGN_ERROR_FAULT @ref drgn_error. * * @param[in] message Human-readable error message. This string is copied. * @param[in] address Address where the fault happened. */ struct drgn_error *drgn_error_create_fault(const char *message, uint64_t address) __attribute__((__returns_nonnull__)); /** * * Create a @ref DRGN_ERROR_FAULT @ref drgn_error with a printf-style formatted * message. * * @param[in] address Address where the fault happened. * @param[in] format printf-style format string for message. * @param[in] ... Arguments for the format string. */ struct drgn_error *drgn_error_format_fault(uint64_t address, const char *format, ...) __attribute__((__returns_nonnull__, __format__(__printf__, 2, 3))); /* * Create a copy of a @ref drgn_error. * * The source's error message and path are copied if necessary, so the source * error can be destroyed without affecting the new error and vice versa. * * @param[in] src Error to copy. * @return A new error with the same fields. If there is a failure to allocate * memory, @ref drgn_enomem is returned instead. */ struct drgn_error *drgn_error_copy(struct drgn_error *src) __attribute__((__returns_nonnull__)); /** * Return a string representation of a @ref drgn_error. * * @param[in] err Error to write. * @return Returned string, or @c NULL if memory could not be allocated. On * success, must be freed with @c free(). */ char *drgn_error_string(struct drgn_error *err); /** * Write a @ref drgn_error followed by a newline to a @c stdio stream. * * @param[in] file File to write to (usually @c stderr). * @param[in] err Error to write. * @return Non-negative on success, negative on failure. */ int drgn_error_fwrite(FILE *file, struct drgn_error *err); /** * Write a @ref drgn_error followed by a newline to a file descriptor. * * @param[in] fd File descriptor to write to. * @param[in] err Error to write. * @return Non-negative on success, negative on failure. */ int drgn_error_dwrite(int fd, struct drgn_error *err); /** * Free a @ref drgn_error. * * This must be called on any error returned from libdrgn unless otherwise * noted. * * @param[in] err Error to destroy. If @c NULL, this is a no-op. */ void drgn_error_destroy(struct drgn_error *err); /** @} */ /** * @defgroup Languages Languages * * Programming languages. * * @{ */ struct drgn_language; // IWYU pragma: export /** C */ extern const struct drgn_language drgn_language_c; /** C++ */ extern const struct drgn_language drgn_language_cpp; /** Get the name of a @ref drgn_language. */ const char *drgn_language_name(const struct drgn_language *lang); /** @} */ /** * @ingroup Types * * Kinds of types. * * Every type in a program supported by libdrgn falls into one of these * categories. */ enum drgn_type_kind { /** Void type. */ DRGN_TYPE_VOID = 1, /** Integer type. */ DRGN_TYPE_INT, /** Boolean type. */ DRGN_TYPE_BOOL, /** Floating-point type. */ DRGN_TYPE_FLOAT, /** Structure type. */ DRGN_TYPE_STRUCT, /** Union type. */ DRGN_TYPE_UNION, /** Class type. */ DRGN_TYPE_CLASS, /** Enumerated type. */ DRGN_TYPE_ENUM, /** Type definition (a.k.a.\ alias) type. */ DRGN_TYPE_TYPEDEF, /** Pointer type. */ DRGN_TYPE_POINTER, /** Array type. */ DRGN_TYPE_ARRAY, /** Function type. */ DRGN_TYPE_FUNCTION, } __attribute__((__packed__)); /** * @ingroup Types * * Type qualifiers. * * Some languages, like C, have the notion of qualifiers which add properties to * a type. Qualifiers are represented as a bitmask; each qualifier is a bit. */ enum drgn_qualifiers { /** Constant type. */ DRGN_QUALIFIER_CONST = (1 << 0), /** Volatile type. */ DRGN_QUALIFIER_VOLATILE = (1 << 1), /** Restrict type. */ DRGN_QUALIFIER_RESTRICT = (1 << 2), /** Atomic type. */ DRGN_QUALIFIER_ATOMIC = (1 << 3), /** Bitmask of all valid qualifiers. */ DRGN_ALL_QUALIFIERS = (1 << 4) - 1, } __attribute__((__packed__)); /** * @ingroup Types * * Qualified type. * * A type with qualifiers. * * @sa drgn_qualifiers */ struct drgn_qualified_type { /** Unqualified type. */ struct drgn_type *type; /** Bitmask of qualifiers on this type. */ enum drgn_qualifiers qualifiers; }; static inline struct drgn_program * drgn_type_program(struct drgn_type *type); static inline const struct drgn_language * drgn_type_language(struct drgn_type *type); /** * @defgroup Platforms Platforms * * Program platforms (i.e., architecture and ABI). * * @{ */ /** An instruction set architecture. */ enum drgn_architecture { DRGN_ARCH_UNKNOWN, DRGN_ARCH_X86_64, DRGN_ARCH_I386, DRGN_ARCH_AARCH64, DRGN_ARCH_ARM, DRGN_ARCH_PPC64, DRGN_ARCH_RISCV64, DRGN_ARCH_RISCV32, DRGN_ARCH_S390X, DRGN_ARCH_S390, }; /** Flags describing a @ref drgn_platform. */ enum drgn_platform_flags { /** Platform is 64-bit. */ DRGN_PLATFORM_IS_64_BIT = (1 << 0), /** Platform is little-endian. */ DRGN_PLATFORM_IS_LITTLE_ENDIAN = (1 << 1), /** All valid platform flags. */ DRGN_ALL_PLATFORM_FLAGS = (1 << 2) - 1, /** Use the default flags for the architecture. */ DRGN_PLATFORM_DEFAULT_FLAGS = UINT_MAX, }; /** * @struct drgn_platform * * The environment that a program runs on. */ struct drgn_platform; // IWYU pragma: export /** * @struct drgn_register * * A processor register. */ struct drgn_register; // IWYU pragma: export /** * Create a @ref drgn_platform. * * The returned platform should be destroyed with @ref drgn_platform_destroy(). */ struct drgn_error *drgn_platform_create(enum drgn_architecture arch, enum drgn_platform_flags flags, struct drgn_platform **ret); /** Destroy a @ref drgn_platform. */ void drgn_platform_destroy(struct drgn_platform *platform); /** Get the instruction set architecture of a @ref drgn_platform. */ enum drgn_architecture drgn_platform_arch(const struct drgn_platform *platform); /** Get the flags of a @ref drgn_platform. */ enum drgn_platform_flags drgn_platform_flags(const struct drgn_platform *platform); /** Get the number of @ref drgn_register's on a @ref drgn_platform. */ size_t drgn_platform_num_registers(const struct drgn_platform *platform); /** Get the @p n-th @ref drgn_register of a @ref drgn_platform. */ const struct drgn_register * drgn_platform_register(const struct drgn_platform *platform, size_t n); /** Get a @ref drgn_register in a @ref drgn_platform by its name. */ const struct drgn_register * drgn_platform_register_by_name(const struct drgn_platform *platform, const char *name); /** Return whether two platforms are identical. */ bool drgn_platform_eq(struct drgn_platform *a, struct drgn_platform *b); /** Platform that drgn was compiled for. */ extern const struct drgn_platform drgn_host_platform; /** * Get the names of a @ref drgn_register. * * @param[out] num_names_ret Returned number of names. * @return Array of names. */ const char * const *drgn_register_names(const struct drgn_register *reg, size_t *num_names_ret); /** @} */ struct drgn_object; struct drgn_thread; /** * @defgroup Programs Programs * * Debugging programs. * * A program being debugged is represented by a @ref drgn_program. * * @{ */ /** * @struct drgn_program * * Program being debugged. * * A @ref drgn_program represents a crashed or running program. It supports * looking up objects (@ref drgn_program_find_object()) and types (@ref * drgn_program_find_type()) by name and reading arbitrary memory from the * program (@ref drgn_program_read_memory()). * * A @ref drgn_program is created with @ref drgn_program_from_core_dump(), @ref * drgn_program_from_kernel(), or @ref drgn_program_from_pid(). It must be freed * with @ref drgn_program_destroy(). */ struct drgn_program; // IWYU pragma: export /** Flags which apply to a @ref drgn_program. */ enum drgn_program_flags { /** The program is the Linux kernel. */ DRGN_PROGRAM_IS_LINUX_KERNEL = (1 << 0), /** The program is currently running. */ DRGN_PROGRAM_IS_LIVE = (1 << 1), /** The program is running on the local machine. */ DRGN_PROGRAM_IS_LOCAL = (1 << 2), }; /** * Create a @ref drgn_program. * * Usually, @ref drgn_program_from_core_dump(), @ref drgn_program_from_kernel(), * and @ref drgn_program_from_pid() are more convenient to use. However, this * can be used if more flexibility is required. * * @param[in] platform Platform that this program runs on, or @c NULL if it * should be determined automatically. This is copied. * @param[out] ret Returned program. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_program_create(const struct drgn_platform *platform, struct drgn_program **ret); /** * Free a @ref drgn_program. * * @param[in] prog Program to free. */ void drgn_program_destroy(struct drgn_program *prog); /** * Callback implementing a memory read. * * @param[out] buf Buffer to read into. * @param[in] address Address which we are reading from. * @param[in] count Number of bytes to read. * @param[in] offset Offset in bytes of @p address from the beginning of the * segment. * @param[in] arg Argument passed to @ref drgn_program_add_memory_segment(). * @param[in] physical Whether @c address is physical. * @return @c NULL on success, non-@c NULL on error. */ typedef struct drgn_error *(*drgn_memory_read_fn)(void *buf, uint64_t address, size_t count, uint64_t offset, void *arg, bool physical); /** * Register a segment of memory in a @ref drgn_program. * * If the segment overlaps a previously registered segment, the new segment * takes precedence. If any part of the segment is beyond the maximum address, * that part is ignored. * * @param[in] address Address of the segment. * @param[in] size Size of the segment in bytes. * @param[in] read_fn Callback to read from segment. * @param[in] arg Argument to pass to @p read_fn. * @param[in] physical Whether to add a physical memory segment. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error * drgn_program_add_memory_segment(struct drgn_program *prog, uint64_t address, uint64_t size, drgn_memory_read_fn read_fn, void *arg, bool physical); /** * Return whether a filename containing a definition (@p haystack) matches a * filename being searched for (@p needle). * * The path is matched from right to left, so a definition in * /usr/include/stdio.h will match stdio.h, * include/stdio.h, usr/include/stdio.h, and * /usr/include/stdio.h. An empty or @c NULL @p needle matches any @p * haystack. */ bool drgn_filename_matches(const char *haystack, const char *needle); enum { /** Enable a handler after all enabled handlers. */ DRGN_HANDLER_REGISTER_ENABLE_LAST = SIZE_MAX, /** Don't enable a handler. */ DRGN_HANDLER_REGISTER_DONT_ENABLE = SIZE_MAX - 1, }; /** Type finder callback table. */ struct drgn_type_finder_ops { /** * Callback to destroy the type finder. * * This may be @c NULL. * * @param[in] arg Argument passed to @ref * drgn_program_register_type_finder(). */ void (*destroy)(void *arg); /** * Callback for finding a type. * * @param[in] kinds Kinds of types to find, as a bitmask of bits shifted * by @ref drgn_type_kind. E.g., `(1 << DRGN_TYPE_STRUCT) | (1 << * DRGN_TYPE_CLASS)` means to find a structure or class type. * @param[in] name Name of type (or tag, for structs, unions, and * enums). This is @em not null-terminated. * @param[in] name_len Length of @p name. * @param[in] filename Filename containing the type definition or @c * NULL. This should be matched with @ref drgn_filename_matches(). * @param[in] arg Argument passed to @ref * drgn_program_register_type_finder(). * @param[out] ret Returned type. * @return @c NULL on success, non-@c NULL on error. In particular, if * the type is not found, this should return &@ref drgn_not_found; any * other errors are considered fatal. */ struct drgn_error *(*find)(uint64_t kinds, const char *name, size_t name_len, const char *filename, void *arg, struct drgn_qualified_type *ret); }; /** * Register a type finding callback. * * @param[in] name Finder name. This is copied. * @param[in] ops Callback table. This is copied. * @param[in] arg Argument to pass to callbacks. * @param[in] enable_index Insert the finder into the list of enabled finders at * the given index. If @ref DRGN_HANDLER_REGISTER_ENABLE_LAST or greater than * the number of enabled finders, insert it at the end. If @ref * DRGN_HANDLER_REGISTER_DONT_ENABLE, don’t enable the finder. */ struct drgn_error * drgn_program_register_type_finder(struct drgn_program *prog, const char *name, const struct drgn_type_finder_ops *ops, void *arg, size_t enable_index); /** * Get the names of all registered type finders. * * The order of the names is arbitrary. * * @param[out] names_ret Returned array of names. * @param[out] count_ret Returned number of names in @p names_ret. */ struct drgn_error * drgn_program_registered_type_finders(struct drgn_program *prog, const char ***names_ret, size_t *count_ret); /** * Set the list of enabled type finders. * * Finders are called in the same order as the list until a type is found. * * @param[in] names Names of finders to enable, in order. * @param[in] count Number of names in @p names. */ struct drgn_error * drgn_program_set_enabled_type_finders(struct drgn_program *prog, const char * const *names, size_t count); /** * Get the names of enabled type finders, in order. * * @param[out] names_ret Returned array of names. * @param[out] count_ret Returned number of names in @p names_ret. */ struct drgn_error *drgn_program_enabled_type_finders(struct drgn_program *prog, const char ***names_ret, size_t *count_ret); /** Flags for @ref drgn_program_find_object(). */ enum drgn_find_object_flags { /** Find a constant (e.g., enumeration constant or macro). */ DRGN_FIND_OBJECT_CONSTANT = 1 << 0, /** Find a function. */ DRGN_FIND_OBJECT_FUNCTION = 1 << 1, /** Find a variable. */ DRGN_FIND_OBJECT_VARIABLE = 1 << 2, /** Find any kind of object. */ DRGN_FIND_OBJECT_ANY = (1 << 3) - 1, }; /** Object finder callback table. */ struct drgn_object_finder_ops { /** * Callback to destroy the object finder. * * This may be @c NULL. * * @param[in] arg Argument passed to @ref * drgn_program_register_object_finder(). */ void (*destroy)(void *arg); /** * Callback for finding an object. * * @param[in] name Name of object. This is @em not null-terminated. * @param[in] name_len Length of @p name. * @param[in] filename Filename containing the object definition or @c * NULL. This should be matched with @ref drgn_filename_matches(). * @param[in] flags Flags indicating what kind of object to look for. * @param[in] arg Argument passed to @ref * drgn_program_register_object_finder(). * @param[out] ret Returned object. This must only be modified on * success. * @return @c NULL on success, non-@c NULL on error. In particular, if * the object is not found, this should return &@ref drgn_not_found; any * other errors are considered fatal. */ struct drgn_error *(*find)(const char *name, size_t name_len, const char *filename, enum drgn_find_object_flags flags, void *arg, struct drgn_object *ret); }; /** * Register an object finding callback. * * @param[in] name Finder name. This is copied. * @param[in] ops Callback table. This is copied. * @param[in] arg Argument to pass to callbacks. * @param[in] enable_index Insert the finder into the list of enabled finders at * the given index. If @ref DRGN_HANDLER_REGISTER_ENABLE_LAST or greater than * the number of enabled finders, insert it at the end. If @ref * DRGN_HANDLER_REGISTER_DONT_ENABLE, don’t enable the finder. */ struct drgn_error * drgn_program_register_object_finder(struct drgn_program *prog, const char *name, const struct drgn_object_finder_ops *ops, void *arg, size_t enable_index); /** * Get the names of all registered object finders. * * The order of the names is arbitrary. * * @param[out] names_ret Returned array of names. * @param[out] count_ret Returned number of names in @p names_ret. */ struct drgn_error * drgn_program_registered_object_finders(struct drgn_program *prog, const char ***names_ret, size_t *count_ret); /** * Set the list of enabled object finders. * * Finders are called in the same order as the list until a object is found. * * @param[in] names Names of finders to enable, in order. * @param[in] count Number of names in @p names. */ struct drgn_error * drgn_program_set_enabled_object_finders(struct drgn_program *prog, const char * const *names, size_t count); /** * Get the names of enabled object finders, in order. * * @param[out] names_ret Returned array of names. * @param[out] count_ret Returned number of names in @p names_ret. */ struct drgn_error * drgn_program_enabled_object_finders(struct drgn_program *prog, const char ***names_ret, size_t *count_ret); /** * Set a @ref drgn_program to a core dump. * * @sa drgn_program_from_core_dump() * * @param[in] path Core dump file path. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_program_set_core_dump(struct drgn_program *prog, const char *path); /** * Set a @ref drgn_program to a core dump from a file descriptor. * * @param[in] path Core dump file descriptor. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_program_set_core_dump_fd(struct drgn_program *prog, int fd); /** * Set a @ref drgn_program to the running operating system kernel. * * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_program_set_kernel(struct drgn_program *prog); /** * Set a @ref drgn_program to a running process. * * @sa drgn_program_from_pid() * * @param[in] pid Process ID. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_program_set_pid(struct drgn_program *prog, pid_t pid); /** * Load debugging information for a list of executable or library files. * * @param[in] load_default Whether to also load debugging information which can * automatically be determined from the program. This implies @p load_main. * @param[in] load_main Whether to also load information for the main * executable. */ struct drgn_error *drgn_program_load_debug_info(struct drgn_program *prog, const char **paths, size_t n, bool load_default, bool load_main); /** * Create a @ref drgn_program from a core dump file. * * The type of program (e.g., userspace or kernel) is determined automatically. * * @param[in] path Core dump file path. * @param[out] ret Returned program. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_program_from_core_dump(const char *path, struct drgn_program **ret); /** * Create a @ref drgn_program from a core dump file descriptor. * * Same as @ref drgn_program_from_core_dump but with an already-opened file * descriptor. * * @param[in] fd Core dump file path descriptor. * @param[out] ret Returned program. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_program_from_core_dump_fd(int fd, struct drgn_program **ret); /** * Create a @ref drgn_program from the running operating system kernel. * * This requires root privileges. * * @param[out] ret Returned program. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_program_from_kernel(struct drgn_program **ret); /** * Create a @ref drgn_program from the a running program. * * On Linux, this requires @c PTRACE_MODE_ATTACH_FSCREDS permissions (see * ptrace(2)). * * @param[in] pid Process ID of the program to debug. * @param[out] ret Returned program. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_program_from_pid(pid_t pid, struct drgn_program **ret); /** Get the set of @ref drgn_program_flags applying to a @ref drgn_program. */ enum drgn_program_flags drgn_program_flags(struct drgn_program *prog); /** * Get the platform of a @ref drgn_program. * * This remains valid until the program is destroyed. It should @em not be * destroyed with @ref drgn_platform_destroy(). * @return non-@c NULL on success, @c NULL if the platform is not known yet. */ const struct drgn_platform *drgn_program_platform(struct drgn_program *prog); /** Get the default language of a @ref drgn_program. */ const struct drgn_language *drgn_program_language(struct drgn_program *prog); /** Set the default language of a @ref drgn_program. */ void drgn_program_set_language(struct drgn_program *prog, const struct drgn_language *lang); /** * Read from a program's memory. * * @param[in] prog Program to read from. * @param[out] buf Buffer to read into. * @param[in] address Starting address in memory to read. * @param[in] count Number of bytes to read. * @param[in] physical Whether @c address is physical. A program may support * only virtual or physical addresses or both. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_program_read_memory(struct drgn_program *prog, void *buf, uint64_t address, size_t count, bool physical); /** * Read a C string from a program's memory. * * This reads up to and including the terminating null byte. * * @param[in] prog Program to read from. * @param[in] address Starting address in memory to read. * @param[in] physical Whether @c address is physical. See @ref * drgn_program_read_memory(). * @param[in] max_size Stop after this many bytes are read, not including the * null byte. A null byte is appended to @p ret in this case. * @param[out] ret Returned string. On success, it must be freed with @c free(). * On error, it is not modified. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_program_read_c_string(struct drgn_program *prog, uint64_t address, bool physical, size_t max_size, char **ret); struct drgn_error *drgn_program_read_u8(struct drgn_program *prog, uint64_t address, bool physical, uint8_t *ret); struct drgn_error *drgn_program_read_u16(struct drgn_program *prog, uint64_t address, bool physical, uint16_t *ret); struct drgn_error *drgn_program_read_u32(struct drgn_program *prog, uint64_t address, bool physical, uint32_t *ret); struct drgn_error *drgn_program_read_u64(struct drgn_program *prog, uint64_t address, bool physical, uint64_t *ret); struct drgn_error *drgn_program_read_word(struct drgn_program *prog, uint64_t address, bool physical, uint64_t *ret); /** * Find a type in a program by name. * * The returned type is valid for the lifetime of the @ref drgn_program. * * @param[in] prog Program. * @param[in] name Name of the type. * @param[in] filename Filename containing the type definition. This is matched * with @ref drgn_filename_matches(). If multiple definitions match, one is * returned arbitrarily. * @param[out] ret Returned type. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_program_find_type(struct drgn_program *prog, const char *name, const char *filename, struct drgn_qualified_type *ret); /** * Find an object in a program by name. * * The object can be a variable, constant, or function depending on @p flags. * * @param[in] prog Program. * @param[in] name Name of the object. * @param[in] filename Filename containing the object definition. This is * matched with @ref drgn_filename_matches(). If multiple definitions match, one * is returned arbitrarily. * @param[in] flags Flags indicating what kind of object to look for. * @param[out] ret Returned object. This must have already been initialized with * @ref drgn_object_init(). * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_program_find_object(struct drgn_program *prog, const char *name, const char *filename, enum drgn_find_object_flags flags, struct drgn_object *ret); /** * @ingroup Symbols * * @struct drgn_symbol * * A @ref drgn_symbol represents an entry in a program's symbol table. */ struct drgn_symbol; // IWYU pragma: export /** * Get the symbol containing the given address. * * @param[out] ret The returned symbol. It should be freed with @ref * drgn_symbol_destroy(). * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error * drgn_program_find_symbol_by_address(struct drgn_program *prog, uint64_t address, struct drgn_symbol **ret); /** * Get the symbol corresponding to the given name. * * @param[out] ret The returned symbol. It should be freed with @ref * drgn_symbol_destroy(). * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_program_find_symbol_by_name(struct drgn_program *prog, const char *name, struct drgn_symbol **ret); /** * Get all global and local symbols, optionally with the given name. * * @param[in] prog Program. * @param[in] name Name to match. If @c NULL, returns all symbols. * @param[out] syms_ret Returned array of symbols. On success, this must be * freed with @ref drgn_symbols_destroy(). * @param[out] count_ret Returned number of symbols in @p syms_ret. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_program_find_symbols_by_name(struct drgn_program *prog, const char *name, struct drgn_symbol ***syms_ret, size_t *count_ret); /** * Get all symbols containing the given address. * * @param[in] prog Program. * @param[in] address Address to search for. * @param[out] syms_ret Returned array of symbols. On success, this must be * freed with @ref drgn_symbols_destroy(). * @param[out] count_ret Returned number of symbols in @p syms_ret. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_program_find_symbols_by_address(struct drgn_program *prog, uint64_t address, struct drgn_symbol ***syms_ret, size_t *count_ret); /** Flags for @ref drgn_symbol_finder_ops::find() */ enum drgn_find_symbol_flags { /** Find symbols whose name matches the name argument */ DRGN_FIND_SYMBOL_NAME = 1 << 0, /** Find symbols whose address matches the addr argument */ DRGN_FIND_SYMBOL_ADDR = 1 << 1, /** Find only one symbol */ DRGN_FIND_SYMBOL_ONE = 1 << 2, }; /** Result builder for @ref drgn_symbol_finder_ops::find() */ struct drgn_symbol_result_builder; /** * Add or set the return value for a symbol search * * Symbol finders should call this with each symbol search result. If the symbol * search was @ref DRGN_FIND_SYMBOL_ONE, then only the most recent symbol added * to the builder will be returned. Otherwise, all symbols added to the builder * are returned. Returns true on success, or false on an allocation failure. */ bool drgn_symbol_result_builder_add(struct drgn_symbol_result_builder *builder, struct drgn_symbol *symbol); /** Get the current number of results in a symbol search result. */ size_t drgn_symbol_result_builder_count(const struct drgn_symbol_result_builder *builder); /** Symbol finder callback table. */ struct drgn_symbol_finder_ops { /** * Callback to destroy the symbol finder. * * This may be @c NULL. * * @param[in] arg Argument passed to @ref * drgn_program_register_symbol_finder(). */ void (*destroy)(void *arg); /** * Callback for finding one or more symbols. * * The callback should perform a symbol lookup based on the flags given * in @p flags. When multiple flags are provided, the effect should be * treated as a logical AND. Symbol results should be added to the * result builder @p builder, via @ref drgn_symbol_result_builder_add(). * When @ref DRGN_FIND_SYMBOL_ONE is set, then the finding function * should only return the single best symbol result, and short-circuit * return. * * When no symbol is found, simply do not add any result to the builder. * No error should be returned in this case. * * @param[in] name Name of the symbol to match * @param[in] addr Address of the symbol to match * @param[in] flags Flags indicating the desired behavior of the search * @param[in] arg Argument passed to @ref * drgn_program_register_symbol_finder(). * @param[in] builder Used to build the resulting symbol output */ struct drgn_error *(*find)(const char *name, uint64_t addr, enum drgn_find_symbol_flags flags, void *arg, struct drgn_symbol_result_builder *builder); }; /** * Register a symbol finding callback. * * @param[in] name Finder name. This is copied. * @param[in] ops Callback table. This is copied. * @param[in] arg Argument to pass to callbacks. * @param[in] enable_index Insert the finder into the list of enabled finders at * the given index. If @ref DRGN_HANDLER_REGISTER_ENABLE_LAST or greater than * the number of enabled finders, insert it at the end. If @ref * DRGN_HANDLER_REGISTER_DONT_ENABLE, don’t enable the finder. */ struct drgn_error * drgn_program_register_symbol_finder(struct drgn_program *prog, const char *name, const struct drgn_symbol_finder_ops *ops, void *arg, size_t enable_index); /** * Get the names of all registered symbol finders. * * The order of the names is arbitrary. * * @param[out] names_ret Returned array of names. * @param[out] count_ret Returned number of names in @p names_ret. */ struct drgn_error * drgn_program_registered_symbol_finders(struct drgn_program *prog, const char ***names_ret, size_t *count_ret); /** * Set the list of enabled symbol finders. * * Finders are called in the same order as the list. In case of a search for * multiple symbols, then the results of all callbacks are concatenated. If the * search is for a single symbol, then the first callback which finds a symbol * will short-circuit the search. * * @param[in] names Names of finders to enable, in order. * @param[in] count Number of names in @p names. */ struct drgn_error * drgn_program_set_enabled_symbol_finders(struct drgn_program *prog, const char * const *names, size_t count); /** * Get the names of enabled symbol finders, in order. * * @param[out] names_ret Returned array of names. * @param[out] count_ret Returned number of names in @p names_ret. */ struct drgn_error * drgn_program_enabled_symbol_finders(struct drgn_program *prog, const char ***names_ret, size_t *count_ret); /** Element type and size. */ struct drgn_element_info { /** Type of the element. */ struct drgn_qualified_type qualified_type; /** * Size in bits of one element. * * Element @c i is at bit offset i * bit_size. */ uint64_t bit_size; }; /** * Get the element type and size of an array or pointer @ref drgn_type. * * @param[in] prog Program. * @param[in] type Array or pointer. After this function is called, this type * must remain valid until the program is destroyed. * @param[out] ret Returned element information. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_program_element_info(struct drgn_program *prog, struct drgn_type *type, struct drgn_element_info *ret); /** @} */ /** * @defgroup Logging Logging * * Logging configuration. * * drgn can log to a file (@ref drgn_program_set_log_file()) or an arbitrary * callback (@ref drgn_program_set_log_callback()). Messages can be filtered * based on the log level (@ref drgn_program_set_log_level()). * * By default, the log file is set to `stderr` and the log level is @ref * DRGN_LOG_NONE, so logging is disabled. * * @{ */ /** Log levels. */ enum drgn_log_level { DRGN_LOG_DEBUG = 0, DRGN_LOG_INFO = 1, DRGN_LOG_WARNING = 2, DRGN_LOG_ERROR = 3, DRGN_LOG_CRITICAL = 4, }; /** Don't log anything. */ #define DRGN_LOG_NONE (DRGN_LOG_CRITICAL + 1) /** * Set the minimum log level. * * Messages below this level will not be logged. * * @param[in] level Minimum @ref drgn_log_level to log, or @ref DRGN_LOG_NONE to * disable logging. */ void drgn_program_set_log_level(struct drgn_program *prog, int level); /** * Get the minimum log level. * * @return Minimum @ref drgn_log_level being logged, or @ref DRGN_LOG_NONE if * logging is disabled. */ int drgn_program_get_log_level(struct drgn_program *prog); /** Write logs to the given file. */ void drgn_program_set_log_file(struct drgn_program *prog, FILE *file); /** * Log callback. * * @param[in] prog Program message was logged to. * @param[in] arg `callback_arg` passed to @ref drgn_program_set_log_callback(). * @param[in] level Message level. * @param[in] format printf-style format of message. * @param[in] ap Arguments for @p format. * @param[in] err Error to append after formatted message if non-@c NULL. This * can be formatted with @ref drgn_error_string(), @ref drgn_error_fwrite(), or * @ref drgn_error_dwrite(). */ typedef void drgn_log_fn(struct drgn_program *prog, void *arg, enum drgn_log_level level, const char *format, va_list ap, struct drgn_error *err); /** * Set a callback to log to. * * @param[in] callback Callback to call for each log message. This is only * called if the message's level is at least the current log level. * @param[in] callback_arg Argument to pass to callback. */ void drgn_program_set_log_callback(struct drgn_program *prog, drgn_log_fn *callback, void *callback_arg); /** * Get the current log callback. * * @param[out] callback_ret Returned callback. * @param[out] callback_arg_ret Returned callback argument. */ void drgn_program_get_log_callback(struct drgn_program *prog, drgn_log_fn **callback_ret, void **callback_arg_ret); /** @} */ /** * @defgroup Embedding Embedding * * Embedding drgn in another runtime. * * @{ */ /** * Callback before a blocking operation. * * @param[in] arg @c callback_arg passed to @ref * drgn_program_set_blocking_callback(). * @return Opaque pointer to pass to @ref drgn_program_end_blocking_fn(). */ typedef void *drgn_program_begin_blocking_fn(struct drgn_program *prog, void *arg); /** * Callback after a blocking operation. * * @param[in] arg @c callback_arg passed to @ref * drgn_program_set_blocking_callback(). * @param[in] state Return value of @ref drgn_program_begin_blocking_fn(). */ typedef void drgn_program_end_blocking_fn(struct drgn_program *prog, void *arg, void *state); /** * Set callbacks around blocking operations. * * These callbacks will be called around blocking I/O operations and * long-running computations. They are intended for things like releasing the * [global interpreter * lock](https://docs.python.org/3/glossary.html#term-global-interpreter-lock). * * @param[in] begin_callback Callback called before a blocking operation. Can be * @c NULL to unset. * @param[in] end_callback Callback called after a blocking operation. Can be @c * NULL to unset. * @param[in] callback_arg Argument passed to @p begin_callback and @p * end_callback. */ void drgn_program_set_blocking_callback(struct drgn_program *prog, drgn_program_begin_blocking_fn *begin_callback, drgn_program_end_blocking_fn *end_callback, void *callback_arg); /** * Get callbacks set by @ref drgn_program_set_blocking_callback(). * * @param[out] begin_callback_ret Returned @c begin_callback. * @param[out] end_callback_ret Returned @c end_callback. * @param[out] callback_arg_ret Returned @c callback_arg. */ void drgn_program_get_blocking_callback(struct drgn_program *prog, drgn_program_begin_blocking_fn **begin_callback_ret, drgn_program_end_blocking_fn **end_callback_ret, void **callback_arg_ret); /** @} */ /** * @defgroup Objects Objects * * Objects in a program. * * A @ref drgn_object represents an object (e.g., variable, constant, or * function) in a program. * * Various operators and helpers are defined on objects; see @ref * ObjectOperators and @ref ObjectHelpers. * * Many operations are language-specific. C is currently the only supported * language. * * In drgn's emulation of C: * * - Signed and unsigned integer arithmetic is reduced modulo 2^width. * - Integer division truncates towards zero. * - Modulo has the sign of the dividend. * - Division or modulo by 0 returns an error. * - Shifts are reduced modulo 2^width. In particular, a shift by a value * greater than the width returns 0. * - Shifts by a negative number return an error. * - Bitwise operators on signed integers act on the two's complement * representation. * - Pointer arithmetic is supported. * - Integer literal have the first type of @c int, @c long, long long, * and unsigned long long which can represent the value. * - Boolean literals have type @c int (@b not @c _Bool). * - Floating-point literals have type @c double. * @{ */ /** Kinds of objects. */ enum drgn_object_kind { /** Constant or temporary computed value. */ DRGN_OBJECT_VALUE, /** In program memory. */ DRGN_OBJECT_REFERENCE, /** Absent (e.g. optimized out). */ DRGN_OBJECT_ABSENT, } __attribute__((__packed__)); /** * Object encodings. * * The value of a @ref drgn_object may be encoded in various ways depending on * its type. This determines which field of a @ref drgn_value is used. * * The incomplete encodings are only possible for reference objects; values have * a complete type. */ enum drgn_object_encoding { /** * Memory buffer. * * This is used for objects with a structure, union, class, or array * type. */ DRGN_OBJECT_ENCODING_BUFFER, /** * Signed integer. * * This is used for objects with a signed integer or signed enumerated * type no larger than 64 bits. */ DRGN_OBJECT_ENCODING_SIGNED, /** * Unsigned integer. * * This is used for objects with a unsigned integer, boolean, or pointer * type no larger than 64 bits. */ DRGN_OBJECT_ENCODING_UNSIGNED, /** * Big signed integer. * * This is used for objects with a signed integer or signed enumerated * type larger than 64 bits. */ DRGN_OBJECT_ENCODING_SIGNED_BIG, /** * Big unsigned integer. * * This is used for objects with a unsigned integer, boolean, or pointer * type larger than 64 bits. */ DRGN_OBJECT_ENCODING_UNSIGNED_BIG, /** * Floating-point value. * * This used for objects with a floating-point type. */ DRGN_OBJECT_ENCODING_FLOAT, /** * No value. * * This is used for reference objects with a void or function type. */ DRGN_OBJECT_ENCODING_NONE = -1, /** * Incomplete buffer value. * * This is used for reference objects with an incomplete structure, * union, class, or array type. */ DRGN_OBJECT_ENCODING_INCOMPLETE_BUFFER = -2, /** * Incomplete integer value. * * This is used for reference objects with an incomplete enumerated * types. */ DRGN_OBJECT_ENCODING_INCOMPLETE_INTEGER = -3, } __attribute__((__packed__)); /** * Return whether a type corresponding to an object encoding is complete. * * @sa drgn_type_is_complete() */ static inline bool drgn_object_encoding_is_complete(enum drgn_object_encoding encoding) { return encoding >= 0; } /** Value of a @ref drgn_object. */ union drgn_value { /** * Pointer to an external buffer for a @ref DRGN_OBJECT_ENCODING_BUFFER, * @ref DRGN_OBJECT_ENCODING_SIGNED_BIG, or @ref * DRGN_OBJECT_ENCODING_UNSIGNED_BIG value. * * For @ref DRGN_OBJECT_ENCODING_BUFFER, this contains the object's * representation in the memory of the program. * * For @ref DRGN_OBJECT_ENCODING_SIGNED_BIG and @ref * DRGN_OBJECT_ENCODING_UNSIGNED_BIG, the representation of the value is * an implementation detail which may change. */ char *bufp; /** * Inline buffer for a @ref DRGN_OBJECT_ENCODING_BUFFER value. * * Tiny buffers (see @ref drgn_value_is_inline()) are stored inline here * instead of in a separate allocation. */ char ibuf[8]; /** @ref DRGN_OBJECT_ENCODING_SIGNED value. */ int64_t svalue; /** @ref DRGN_OBJECT_ENCODING_UNSIGNED value. */ uint64_t uvalue; /** @ref DRGN_OBJECT_ENCODING_FLOAT value. */ double fvalue; }; /** * Return the number of bytes needed to store the given number of bits. * * @param[in] bits Number of bits. */ static inline uint64_t drgn_value_size(uint64_t bits) { return bits / CHAR_BIT + (bits % CHAR_BIT ? 1 : 0); } /** * Return whether the given number of bits can be stored in the inline buffer of * a @ref drgn_value (@ref drgn_value::ibuf). * * @param[in] bits Number of bits. */ static inline bool drgn_value_is_inline(uint64_t bits) { return bits <= CHAR_BIT * sizeof(((union drgn_value *)0)->ibuf); } /** * Object in a program. * * A @ref drgn_object represents a symbol or value in a program. It can be in * the memory of the program (a "reference"), a temporary computed value (a * "value"), or "absent". * * A @ref drgn_object must be initialized with @ref drgn_object_init() before it * is used. It can then be set and otherwise changed repeatedly. When the object * is no longer needed, it must be deinitialized @ref drgn_object_deinit(). * * It is more effecient to initialize an object once and reuse it rather than * creating a new one repeatedly (e.g., in a loop). * * Members of a @ref drgn_object should not be modified except through the * provided functions. */ struct drgn_object { /** Type of this object. */ struct drgn_type *type; /** * Size of this object in bits. * * This is usually the size of @ref drgn_object::type, but it may be * smaller if this is a bit field (@ref drgn_object::is_bit_field). */ uint64_t bit_size; /** Qualifiers on @ref drgn_object::type. */ enum drgn_qualifiers qualifiers; /** How this object is encoded. */ enum drgn_object_encoding encoding; /** Kind of this object. */ enum drgn_object_kind kind; /** Whether this object is a bit field. */ bool is_bit_field; /** * Whether this object is little-endian. * * Valid only for scalars (i.e., @ref DRGN_OBJECT_ENCODING_SIGNED, @ref * DRGN_OBJECT_ENCODING_UNSIGNED, @ref DRGN_OBJECT_ENCODING_SIGNED_BIG, * @ref DRGN_OBJECT_ENCODING_UNSIGNED_BIG, @ref * DRGN_OBJECT_ENCODING_FLOAT, or @ref * DRGN_OBJECT_ENCODING_INCOMPLETE_INTEGER). */ bool little_endian; /** * Offset in bits from @c address. * * Valid only for reference objects. */ uint8_t bit_offset; union { /** Value of value object. */ union drgn_value value; /** Address of reference object. */ uint64_t address; }; }; /** Return the number of bytes needed to store an object's value. */ static inline uint64_t drgn_object_size(const struct drgn_object *obj) { return drgn_value_size(obj->bit_size); } /** * Return whether an object's value can be stored in the inline buffer of a @ref * drgn_value (@ref drgn_value::ibuf). */ static inline bool drgn_object_is_inline(const struct drgn_object *obj) { return drgn_value_is_inline(obj->bit_size); } /** Return an object's buffer. */ #define drgn_object_buffer(obj) ({ \ __auto_type _obj = (obj); \ drgn_object_is_inline(_obj) ? _obj->value.ibuf : _obj->value.bufp; \ }) /** Get the type of a @ref drgn_object. */ static inline struct drgn_qualified_type drgn_object_qualified_type(const struct drgn_object *obj) { return (struct drgn_qualified_type){ .type = obj->type, .qualifiers = obj->qualifiers, }; } /** * Initialize a @ref drgn_object. * * The object is initialized to an absent object with a void type. This must be * paired with a call to @ref drgn_object_deinit(). * * @param[in] obj Object to initialize. * @param[in] prog Program containing the object. */ void drgn_object_init(struct drgn_object *obj, struct drgn_program *prog); /** * Deinitialize a @ref drgn_object. * * The object cannot be used after this unless it is reinitialized with @ref * drgn_object_init(). * * @param[in] obj Object to deinitialize. */ void drgn_object_deinit(struct drgn_object *obj); /** * Define and initialize a @ref drgn_object named @p obj that is automatically * deinitialized when it goes out of scope. * * This is equivalent to * * ``` * struct drgn_object obj; * drgn_object_init(&obj, prog); * ... * drgn_object_deinit(&obj); * ``` * * @param[in] obj Name of object. * @param[in] prog Program containing the object. */ #define DRGN_OBJECT(obj, prog) \ struct drgn_object obj \ __attribute__((__cleanup__(drgn_object_deinit))) = \ drgn_object_initializer(prog) struct drgn_object drgn_object_initializer(struct drgn_program *prog); /** Get the program that a @ref drgn_object is from. */ static inline struct drgn_program * drgn_object_program(const struct drgn_object *obj) { return drgn_type_program(obj->type); } /** Get the language of a @ref drgn_object from its type. */ static inline const struct drgn_language * drgn_object_language(const struct drgn_object *obj) { return drgn_type_language(obj->type); } /** * @defgroup ObjectSetters Setters * * Object setters. * * Once a @ref drgn_object is initialized with @ref drgn_object_init(), it may * be set any number of times. * * @{ */ /** * Set a @ref drgn_object to a signed value. * * @param[out] res Object to set. * @param[in] qualified_type Type to set to. * @param[in] svalue Value to set to. * @param[in] bit_field_size If the object should be a bit field, its size in * bits. Otherwise, 0. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error * drgn_object_set_signed(struct drgn_object *res, struct drgn_qualified_type qualified_type, int64_t svalue, uint64_t bit_field_size); /** * Set a @ref drgn_object to an unsigned value. * * @param[out] res Object to set. * @param[in] qualified_type Type to set to. * @param[in] uvalue Value to set to. * @param[in] bit_field_size If the object should be a bit field, its size in * bits. Otherwise, 0. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error * drgn_object_set_unsigned(struct drgn_object *res, struct drgn_qualified_type qualified_type, uint64_t uvalue, uint64_t bit_field_size); /** * Set a @ref drgn_object to a floating-point value. * * @param[out] res Object to set. * @param[in] qualified_type Type to set to. * @param[in] fvalue Value to set to. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error * drgn_object_set_float(struct drgn_object *res, struct drgn_qualified_type qualified_type, double fvalue); /** * Set a @ref drgn_object from a buffer. * * @param[out] res Object to set. * @param[in] qualified_type Type to set to. * @param[in] buf Buffer to set to. It is copied, so it need not remain valid * after this function returns. * @param[in] buf_size Size of @p buf, in bytes. `buf_size * 8` must be at least * `bit_size + bit_offset`, where @c bit_size is @p bit_field_size if non-zero * and the size of @p qualified_type in bits otherwise. * @param[in] bit_offset Offset of the value from the beginning of the buffer, * in bits. This is usually 0. It must be aligned to a byte unless the type is * scalar. * @param[in] bit_field_size If the object should be a bit field, its size in * bits. Otherwise, 0. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error * drgn_object_set_from_buffer(struct drgn_object *res, struct drgn_qualified_type qualified_type, const void *buf, size_t buf_size, uint64_t bit_offset, uint64_t bit_field_size); /** * Set a @ref drgn_object to a reference. * * @param[out] res Object to set. * @param[in] qualified_type Type to set to. * @param[in] address Address of the object. * @param[in] bit_offset Offset of the value from @p address, in bits. This is * usually 0. * @param[in] bit_field_size If the object should be a bit field, its size in * bits. Otherwise, 0. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error * drgn_object_set_reference(struct drgn_object *res, struct drgn_qualified_type qualified_type, uint64_t address, uint64_t bit_offset, uint64_t bit_field_size); /** * Set a @ref drgn_object as absent. * * @param[out] res Object to set. * @param[in] qualified_type Type to set to. * @param[in] bit_field_size If the object should be a bit field, its size in * bits. Otherwise, 0. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error * drgn_object_set_absent(struct drgn_object *res, struct drgn_qualified_type qualified_type, uint64_t bit_field_size); /** * Set a @ref drgn_object to a integer literal. * * This determines the type based on the programming language of the program * that the object belongs to. * * @param[out] res Object to set. * @param[in] uvalue Integer value. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_object_integer_literal(struct drgn_object *res, uint64_t uvalue); /** * Set a @ref drgn_object to a boolean literal. * * This determines the type based on the programming language of the program * that the object belongs to. * * @param[out] res Object to set. * @param[in] bvalue Boolean value. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_object_bool_literal(struct drgn_object *res, bool bvalue); /** * Set a @ref drgn_object to a floating-point literal. * * This determines the type based on the programming language of the program * that the object belongs to. * * @param[out] res Object to set. * @param[in] fvalue Floating-point value. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_object_float_literal(struct drgn_object *res, double fvalue); /** @} */ /** * @defgroup ObjectHelpers Helpers * * Object helpers. * * Several helpers are provided for working with @ref drgn_object%s. * * Helpers which return a @ref drgn_object have the same calling convention: the * result object is the first argument, which must be initialized and may be the * same as the input object argument; the result is only modified if the helper * succeeds. * * @{ */ /** * Set a @ref drgn_object to another object. * * This copies @c obj to @c res. If @c obj is a value, then @c res is set to a * value with the same type and value, and similarly if @c obj was a reference, * @c res is set to the same reference. * * @param[out] res Destination object. * @param[in] obj Source object. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_object_copy(struct drgn_object *res, const struct drgn_object *obj); /** * Get a @ref drgn_object from a "slice" of an object. * * This is a low-level interface used to implement @ref drgn_object_subscript(), * @ref drgn_object_member(), and @ref drgn_object_reinterpret(). Those * functions are usually more convenient. * * If multiple elements of an array are accessed (e.g., when iterating through * it), it can be more efficient to call @ref drgn_program_element_info() once * to get the required information and this function with the computed bit * offset for each element. * * If the same member of a type is accessed repeatedly (e.g., in a loop), it can * be more efficient to call @ref drgn_type_find_member() once to get the * required information and this function to access the member each time. * * @sa drgn_object_dereference_offset * * @param[out] res Destination object. * @param[in] obj Source object. * @param[in] qualified_type Result type. * @param[in] bit_offset Offset in bits from the beginning of @p obj. * @param[in] bit_field_size If the object should be a bit field, its size in * bits. Otherwise, 0. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_object_slice(struct drgn_object *res, const struct drgn_object *obj, struct drgn_qualified_type qualified_type, uint64_t bit_offset, uint64_t bit_field_size); /** * Get a @ref drgn_object from dereferencing a pointer object with an offset. * * This is a low-level interface used to implement @ref drgn_object_subscript() * and @ref drgn_object_member_dereference(). Those functions are usually more * convenient, but this function can be more efficient if accessing multiple * elements or the same member multiple times. * * @sa drgn_object_slice * * @param[out] res Dereferenced object. * @param[in] obj Pointer object. * @param[in] qualified_type Result type. * @param[in] bit_offset Offset in bits from the address given by the value of * @p obj. * @param[in] bit_field_size If the object should be a bit field, its size in * bits. Otherwise, 0. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error * drgn_object_dereference_offset(struct drgn_object *res, const struct drgn_object *obj, struct drgn_qualified_type qualified_type, int64_t bit_offset, uint64_t bit_field_size); /** * Read a @ref drgn_object. * * If @c obj is already a value, then this is equivalent to @ref * drgn_object_copy(). If @c is a reference, then this reads the reference and * sets @p res to the value. * * @param[out] res Object to set. * @param[in] obj Object to read. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_object_read(struct drgn_object *res, const struct drgn_object *obj); /** * Read the value of a @ref drgn_object. * * If @p obj is a value, that value is returned directly. If @p is a reference, * the value is read into the provided temporary buffer. * * This must be paired with @ref drgn_object_deinit_value(). * * @param[in] obj Object to read. * @param[in] value Temporary value to use if necessary. * @param[out] ret Pointer to the returned value, which is &obj->value * if @p obj is a value, or @p value if @p obj is a reference. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_object_read_value(const struct drgn_object *obj, union drgn_value *value, const union drgn_value **ret); /** * Deinitialize a value which was read with @ref drgn_object_read_value(). * * @param[in] obj Object which was read. * @param[in] value Value returned from @ref drgn_object_read_value() in @p ret. */ void drgn_object_deinit_value(const struct drgn_object *obj, const union drgn_value *value); /** * Get the binary representation of the value of a @ref drgn_object. * * @param[out] Buffer to read into. Size must be at least * `drgn_object_size(obj)`. */ struct drgn_error *drgn_object_read_bytes(const struct drgn_object *obj, void *buf); /** * Get the value of an object encoded with @ref * drgn_object_encoding::DRGN_OBJECT_ENCODING_SIGNED. * * If the object is not a signed integer, an error is returned. * * @param[in] obj Object to read. * @param[out] ret Returned value. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_object_read_signed(const struct drgn_object *obj, int64_t *ret); /** * Get the value of an object encoded with @ref * drgn_object_encoding::DRGN_OBJECT_ENCODING_UNSIGNED. * * If the object is not an unsigned integer, an error is returned. * * @param[in] obj Object to read. * @param[out] ret Returned value. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_object_read_unsigned(const struct drgn_object *obj, uint64_t *ret); /** * Get the value of an object encoded with @ref * drgn_object_encoding::DRGN_OBJECT_ENCODING_SIGNED or @ref * drgn_object_encoding::DRGN_OBJECT_ENCODING_UNSIGNED. * * If the object is not an integer, an error is returned. * * @param[in] obj Object to read. * @param[out] ret Returned value. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_object_read_integer(const struct drgn_object *obj, union drgn_value *ret); /** * Get the value of an object encoded with @ref * drgn_object_encoding::DRGN_OBJECT_ENCODING_FLOAT. * * If the object does not have a floating-point type, an error is returned. * * @param[in] obj Object to read. * @param[out] ret Returned value. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_object_read_float(const struct drgn_object *obj, double *ret); /** * Read the null-terminated string pointed to by a @ref drgn_object. * * This is only valid for pointers and arrays. The element type is ignored; this * operates byte-by-byte. * * For pointers and flexible arrays, this stops at the first null byte. * * For complete arrays, this stops at the first null byte or at the end of the * array. * * The returned string is always null-terminated. * * @param[in] obj Object to read. * @param[out] ret Returned string. On success, it must be freed with @c free(). * On error, it is not modified. */ struct drgn_error *drgn_object_read_c_string(const struct drgn_object *obj, char **ret); /** Flags to control @ref drgn_format_object() output. */ enum drgn_format_object_flags { DRGN_FORMAT_OBJECT_DEREFERENCE = 1 << 0, DRGN_FORMAT_OBJECT_SYMBOLIZE = 1 << 1, DRGN_FORMAT_OBJECT_STRING = 1 << 2, DRGN_FORMAT_OBJECT_CHAR = 1 << 3, DRGN_FORMAT_OBJECT_TYPE_NAME = 1 << 4, DRGN_FORMAT_OBJECT_MEMBER_TYPE_NAMES = 1 << 5, DRGN_FORMAT_OBJECT_ELEMENT_TYPE_NAMES = 1 << 6, DRGN_FORMAT_OBJECT_MEMBERS_SAME_LINE = 1 << 7, DRGN_FORMAT_OBJECT_ELEMENTS_SAME_LINE = 1 << 8, DRGN_FORMAT_OBJECT_MEMBER_NAMES = 1 << 9, DRGN_FORMAT_OBJECT_ELEMENT_INDICES = 1 << 10, DRGN_FORMAT_OBJECT_IMPLICIT_MEMBERS = 1 << 11, DRGN_FORMAT_OBJECT_IMPLICIT_ELEMENTS = 1 << 12, /** Default "pretty" flags. */ DRGN_FORMAT_OBJECT_PRETTY = (DRGN_FORMAT_OBJECT_DEREFERENCE | DRGN_FORMAT_OBJECT_SYMBOLIZE | DRGN_FORMAT_OBJECT_STRING | DRGN_FORMAT_OBJECT_TYPE_NAME | DRGN_FORMAT_OBJECT_MEMBER_TYPE_NAMES | DRGN_FORMAT_OBJECT_ELEMENTS_SAME_LINE | DRGN_FORMAT_OBJECT_MEMBER_NAMES | DRGN_FORMAT_OBJECT_IMPLICIT_MEMBERS), DRGN_FORMAT_OBJECT_VALID_FLAGS = (1 << 13) - 1, }; /** * Format a @ref drgn_object as a string. * * This will format the object similarly to an expression in its programming * language. * * @param[in] obj Object to format. * @param[in] columns Number of columns to limit output to when the expression * can be reasonably wrapped. * param[in] flags Flags to change output. * @param[out] ret Returned string. On success, it must be freed with @c free(). * On error, it is not modified. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_format_object(const struct drgn_object *obj, size_t columns, enum drgn_format_object_flags flags, char **ret); /** @} */ /** * @defgroup ObjectOperators Operators * * Object operators. * * Various operators are defined on @ref drgn_object%s. These operators obey the * rules of the programming language of the given objects. * * Operators which return a @ref drgn_object have the same calling convention: * the result object is the first argument, which must be initialized and may be * the same as one or more of the operands; the result is only modified if the * operator succeeds. * * @{ */ /** * Set a @ref drgn_object to the value of an object casted to a another type. * * Objects with a scalar type can be casted to a different scalar type. Other * objects can only be casted to the same type. @p res is always set to a value * object. * * @sa drgn_object_reinterpret() * * @param[out] res Object to set. * @param[in] qualified_type New type. * @param[in] obj Object to read. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_object_cast(struct drgn_object *res, struct drgn_qualified_type qualified_type, const struct drgn_object *obj); /** * Set a @ref drgn_object to the representation of an object reinterpreted as * another type. * * This reinterprets the raw memory of the object, so an object can be * reinterpreted as any other type. * * If @c obj is a value, then @c res is set to a value; if @c obj is a * reference, then @c res is set to a reference. * * @sa drgn_object_cast() * * @param[out] res Object to set. * @param[in] qualified_type New type. * @param[in] obj Object to reinterpret. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error * drgn_object_reinterpret(struct drgn_object *res, struct drgn_qualified_type qualified_type, const struct drgn_object *obj); /** * @ref drgn_object binary operator. * * Binary operators apply any language-specific conversions to @p lhs and @p * rhs, apply the operator, and store the result in @p res. * * @param[out] res Operator result. May be the same as @p lhs and/or @p rhs. * @param[in] lhs Operator left hand side. * @param[in] rhs Operator right hand side. * @return @c NULL on success, non-@c NULL on error. @p res is not modified on * error. */ typedef struct drgn_error *drgn_binary_op(struct drgn_object *res, const struct drgn_object *lhs, const struct drgn_object *rhs); /** * @ref drgn_object unary operator. * * Unary operators apply any language-specific conversions to @p obj, apply the * operator, and store the result in @p res. * * @param[out] res Operator result. May be the same as @p obj. * @param[in] obj Operand. * @return @c NULL on success, non-@c NULL on error. @p res is not modified on * error. */ typedef struct drgn_error *drgn_unary_op(struct drgn_object *res, const struct drgn_object *obj); /** * Convert a @ref drgn_object to a boolean value. * * This gets the "truthiness" of an object according to its programming * language. * * @param[in] obj Object. * @param[out] ret Returned boolean value. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_object_bool(const struct drgn_object *obj, bool *ret); /** * Compare the value of two @ref drgn_object%s. * * This applies any language-specific conversions to @p lhs and @p rhs and * compares the resulting values. * * @param[in] lhs Comparison left hand side. * @param[in] rhs Comparison right hand side. * @param[out] ret 0 if the operands are equal, < 0 if @p lhs < @p rhs, and > 0 * if @p lhs > @p rhs. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_object_cmp(const struct drgn_object *lhs, const struct drgn_object *rhs, int *ret); /** Add (@c +) two @ref drgn_object%s. */ drgn_binary_op drgn_object_add; /** Subtract (@c -) a @ref drgn_object from another. */ drgn_binary_op drgn_object_sub; /** Multiply (@c *) two @ref drgn_object%s. */ drgn_binary_op drgn_object_mul; /** Divide (@c /) a @ref drgn_object by another. */ drgn_binary_op drgn_object_div; /** Calculate the modulus (@c %) of two @ref drgn_object%s. */ drgn_binary_op drgn_object_mod; /** Left shift (@c <<) a @ref drgn_object by another. */ drgn_binary_op drgn_object_lshift; /** Right shift (@c >>) a @ref drgn_object by another. */ drgn_binary_op drgn_object_rshift; /** Calculate the bitwise and (@c &) of two @ref drgn_object%s. */ drgn_binary_op drgn_object_and; /** Calculate the bitwise or (@c |) of two @ref drgn_object%s. */ drgn_binary_op drgn_object_or; /** Calculate the bitwise exclusive or (@c ^) of two @ref drgn_object%s. */ drgn_binary_op drgn_object_xor; /** Apply unary plus (@c +) to a @ref drgn_object. */ drgn_unary_op drgn_object_pos; /** Calculate the arithmetic negation (@c -) of a @ref drgn_object. */ drgn_unary_op drgn_object_neg; /** Calculate the bitwise negation (@c ~) of a @ref drgn_object. */ drgn_unary_op drgn_object_not; /** * Get the address of (@c &) a @ref drgn_object as an object. * * This is only possible for reference objects, as value objects don't have an * address in the program. * * @param[out] res Resulting pointer value. May be the same as @p obj. * @param[in] obj Reference object. * @return @c NULL on success, non-@c NULL on error. @p res is not modified on * error. */ struct drgn_error *drgn_object_address_of(struct drgn_object *res, const struct drgn_object *obj); /** * Subscript (@c []) a @ref drgn_object. * * This is applicable to pointers and arrays. * * @param[out] res Resulting element. May be the same as @p obj. * @param[in] obj Object to subscript. * @param[in] index Element index. * @return @c NULL on success, non-@c NULL on error. @p res is not modified on * error. */ struct drgn_error *drgn_object_subscript(struct drgn_object *res, const struct drgn_object *obj, int64_t index); /** * Deference (@c *) a @ref drgn_object. * * This is equivalent to @ref drgn_object_subscript with an index of 0. * * @param[out] res Deferenced object. May be the same as @p obj. * @param[in] obj Object to dereference. * @return @c NULL on success, non-@c NULL on error. @p res is not modified on * error. */ static inline struct drgn_error * drgn_object_dereference(struct drgn_object *res, const struct drgn_object *obj) { return drgn_object_subscript(res, obj, 0); } /** * Get a member of a structure, union, or class @ref drgn_object (@c .). * * @param[out] res Returned member. May be the same as @p obj. * @param[in] obj Object. * @param[in] member_name Name of member. * @return @c NULL on success, non-@c NULL on error. @p res is not modified on * error. */ struct drgn_error *drgn_object_member(struct drgn_object *res, const struct drgn_object *obj, const char *member_name); /** * Get a member of a pointer @ref drgn_object (@c ->). * * This is applicable to pointers to structures and pointers to unions. * * @param[out] res Returned member. May be the same as @p obj. * @param[in] obj Object. * @param[in] member_name Name of member. * @return @c NULL on success, non-@c NULL on error. @p res is not modified on * error. */ struct drgn_error *drgn_object_member_dereference(struct drgn_object *res, const struct drgn_object *obj, const char *member_name); /** * Get the containing object of a member @ref drgn_object. * * This corresponds to the @c container_of() macro commonly used in C. * * @param[out] res Returned object. May be the same as @p obj. * @param[in] obj Pointer to a member. * @param[in] qualified_type Type which contains the member. * @param[in] member_designator Name of the member in @p qualified_type. This * can include one or more member references and zero or more array subscripts. * @return @c NULL on success, non-@c NULL on error. @p res is not modified on * error. */ struct drgn_error * drgn_object_container_of(struct drgn_object *res, const struct drgn_object *obj, struct drgn_qualified_type qualified_type, const char *member_designator); /** * Get the size of a @ref drgn_object in bytes. * * @param[in] obj Object. * @param[out] ret Returned size. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_object_sizeof(const struct drgn_object *obj, uint64_t *ret); /** @} */ /** @} */ /** * @ingroup LazyObjects * * Callback to evaluate and/or free a @ref drgn_lazy_object. * * If @p res is not @c NULL, then this should return the object in @p res and * free @p arg if necessary. If this returns an error, it may be called again * (so @p arg must remain valid). * * If @p res is @c NULL, then this should free @p arg if necessary; it must not * return an error. * * @param[out] res Result object (if evaluating) or @c NULL (if freeing). This * is already initialized and should not be deinitialized on error. * @param[in] arg Callback argument passed to @ref * drgn_lazy_object_init_thunk(). * @return @c NULL on success, non-@c NULL on error. */ typedef struct drgn_error *drgn_object_thunk_fn(struct drgn_object *res, void *arg); /** * @ingroup LazyObjects * * Lazily-evaluated object. * * A lazy object may be in two states: unevaluated, in which case a callback * must be called to evaluate the object, or evaluated, in which case the object * is cached. To evaluate an object, the callback is called, and the result is * cached. * * This is for internal use only. */ union drgn_lazy_object { /** Object if it has already been evaluated. */ struct drgn_object obj; /** Thunk if the object has not been evaluated yet. */ struct { /** * Always @c NULL to indicate an unevaluated lazy object. * * This must be at the same offset as @ref drgn_object::type. */ struct drgn_type *dummy_type; /** Program owning this thunk. */ struct drgn_program *prog; /** Callback. */ drgn_object_thunk_fn *fn; /** Argument passed to @ref drgn_lazy_object::thunk::fn. */ void *arg; } thunk; }; /** * @defgroup Types Types * * Type descriptors. * * Types in a program are represented by @ref drgn_type. * * Type descriptors have various fields depending on the kind of type. For each * field @c foo, there is a @c drgn_type_kind_has_foo() helper which returns * whether the given kind of type has the field @c foo; a @c drgn_type_has_foo() * helper which does the same but takes a type; and a @c drgn_type_foo() helper * which returns the field. For members, enumerators, and parameters, there is * also a @c drgn_type_num_foo() helper. * * @{ */ /** Primitive types known to drgn. */ enum drgn_primitive_type { /* Primitive C types. */ DRGN_C_TYPE_VOID, DRGN_C_TYPE_CHAR, DRGN_C_TYPE_SIGNED_CHAR, DRGN_C_TYPE_UNSIGNED_CHAR, DRGN_C_TYPE_SHORT, DRGN_C_TYPE_UNSIGNED_SHORT, DRGN_C_TYPE_INT, DRGN_C_TYPE_UNSIGNED_INT, DRGN_C_TYPE_LONG, DRGN_C_TYPE_UNSIGNED_LONG, DRGN_C_TYPE_LONG_LONG, DRGN_C_TYPE_UNSIGNED_LONG_LONG, DRGN_C_TYPE_BOOL, DRGN_C_TYPE_FLOAT, DRGN_C_TYPE_DOUBLE, DRGN_C_TYPE_LONG_DOUBLE, DRGN_C_TYPE_SIZE_T, DRGN_C_TYPE_PTRDIFF_T, DRGN_PRIMITIVE_TYPE_NUM, DRGN_NOT_PRIMITIVE_TYPE = DRGN_PRIMITIVE_TYPE_NUM, /* * Make sure to update api_reference.rst and type.c when adding anything * here. */ } __attribute__((__packed__)); /** Member of a structure, union, or class type. */ struct drgn_type_member { /** * Member as an object. * * Access this with @ref drgn_member_object() or @ref * drgn_member_type(). */ union drgn_lazy_object object; /** Member name or @c NULL if it is unnamed. */ const char *name; /** * Offset in bits from the beginning of the type to the beginning of * this member (i.e., for little-endian machines, the least significant * bit, and for big-endian machines, the most significant bit). Members * are usually aligned to at least a byte, so this is usually a multiple * of 8 (but that may not be the case for bit fields). */ uint64_t bit_offset; }; /** Value of an enumerated type. */ struct drgn_type_enumerator { /** Enumerator name. */ const char *name; union { /** Enumerator value if the type is signed. */ int64_t svalue; /** Enumerator value if the type is unsigned. */ uint64_t uvalue; }; }; /** Parameter of a function type. */ struct drgn_type_parameter { /** * Parameter type and default argument. * * Access this with @ref drgn_parameter_default_argument() or @ref * drgn_parameter_type(). */ union drgn_lazy_object default_argument; /** Parameter name or @c NULL if it is unnamed. */ const char *name; }; /** Template parameter of a structure, union, class, or function type. */ struct drgn_type_template_parameter { /** * Template parameter type or value. * * Access this with @ref drgn_template_parameter_type() and @ref * drgn_template_parameter_object(). */ union drgn_lazy_object argument; /** Template parameter name or @c NULL if it is unnamed. */ const char *name; /** Whether the argument is the default. */ bool is_default; }; /** * Language-agnostic type descriptor. * * This structure should not be accessed directly; see @ref Types. */ struct drgn_type { /** @privatesection */ struct { enum drgn_type_kind kind; bool is_complete; enum drgn_primitive_type primitive; /* These are the qualifiers for the wrapped type, not this type. */ enum drgn_qualifiers qualifiers; struct drgn_program *program; const struct drgn_language *language; /* * This mess of unions is used to make this as compact as possible. Use * the provided helpers and don't think about it. */ union { const char *name; const char *tag; size_t num_parameters; }; union { uint64_t size; uint64_t length; size_t num_enumerators; bool is_variadic; }; union { bool is_signed; size_t num_members; struct drgn_type *type; }; union { bool little_endian; struct drgn_type_member *members; struct drgn_type_enumerator *enumerators; struct drgn_type_parameter *parameters; }; struct drgn_type_template_parameter *template_parameters; size_t num_template_parameters; } _private; }; /** Get the kind of a type. */ static inline enum drgn_type_kind drgn_type_kind(struct drgn_type *type) { return type->_private.kind; } /** Get the primitive type corresponding to a @ref drgn_type. */ static inline enum drgn_primitive_type drgn_type_primitive(struct drgn_type *type) { return type->_private.primitive; } /** * Get whether a type is complete (i.e., the type definition is known). * * This is always @c false for the void type. It may be @c false for structure, * union, class, enumerated, and array types, as well as typedef types where the * underlying type is one of those. Otherwise, it is always @c true. */ static inline bool drgn_type_is_complete(struct drgn_type *type) { return type->_private.is_complete; } static inline struct drgn_program * drgn_type_program(struct drgn_type *type) { return type->_private.program; } /** Get the language of a type. */ static inline const struct drgn_language * drgn_type_language(struct drgn_type *type) { return type->_private.language; } /** * Get whether a kind of type has a name. This is true for integer, boolean, * floating-point, and typedef types. */ static inline bool drgn_type_kind_has_name(enum drgn_type_kind kind) { return (kind == DRGN_TYPE_INT || kind == DRGN_TYPE_BOOL || kind == DRGN_TYPE_FLOAT || kind == DRGN_TYPE_TYPEDEF); } /** Get whether a type has a name. @sa drgn_type_kind_has_name() */ static inline bool drgn_type_has_name(struct drgn_type *type) { return drgn_type_kind_has_name(drgn_type_kind(type)); } /** * Get the name of a type. @ref drgn_type_has_name() must be true for this type. */ static inline const char *drgn_type_name(struct drgn_type *type) { assert(drgn_type_has_name(type)); return type->_private.name; } /** * Get whether a kind of type has a size. This is true for integer, boolean, * floating-point, structure, union, class, and pointer types. */ static inline bool drgn_type_kind_has_size(enum drgn_type_kind kind) { return (kind == DRGN_TYPE_INT || kind == DRGN_TYPE_BOOL || kind == DRGN_TYPE_FLOAT || kind == DRGN_TYPE_STRUCT || kind == DRGN_TYPE_UNION || kind == DRGN_TYPE_CLASS || kind == DRGN_TYPE_POINTER); } /** Get whether a type has a size. @sa drgn_type_kind_has_size() */ static inline bool drgn_type_has_size(struct drgn_type *type) { return drgn_type_kind_has_size(drgn_type_kind(type)); } /** * Get the size of a type in bytes. @ref drgn_type_has_size() must be true for * this type. */ static inline uint64_t drgn_type_size(struct drgn_type *type) { assert(drgn_type_has_size(type)); return type->_private.size; } /** * Get whether a kind of type has a signedness. This is true for integer types. */ static inline bool drgn_type_kind_has_is_signed(enum drgn_type_kind kind) { return kind == DRGN_TYPE_INT; } /** Get whether a type has a signedness. @sa drgn_type_kind_has_is_signed() */ static inline bool drgn_type_has_is_signed(struct drgn_type *type) { return drgn_type_kind_has_is_signed(drgn_type_kind(type)); } /** * Get the signedness of a type. @ref drgn_type_has_is_signed() must be true for * this type. */ static inline bool drgn_type_is_signed(struct drgn_type *type) { assert(drgn_type_has_is_signed(type)); return type->_private.is_signed; } /** * Get whether a kind of type has a byte order. This is true for integer, * boolean, floating-point, and pointer types. */ static inline bool drgn_type_kind_has_little_endian(enum drgn_type_kind kind) { return (kind == DRGN_TYPE_INT || kind == DRGN_TYPE_BOOL || kind == DRGN_TYPE_FLOAT || kind == DRGN_TYPE_POINTER); } /** * Get whether a type has a byte order. @sa drgn_type_kind_has_little_endian() */ static inline bool drgn_type_has_little_endian(struct drgn_type *type) { return drgn_type_kind_has_little_endian(drgn_type_kind(type)); } /** * Get the byte order of a type. @ref drgn_type_has_little_endian() must be true * for this type. * * @return @c true if the type is little-endian, @c false if it is big-endian. */ static inline bool drgn_type_little_endian(struct drgn_type *type) { assert(drgn_type_has_little_endian(type)); return type->_private.little_endian; } /** * Get whether a kind of type has a tag. This is true for structure, union, * class, and enumerated types. */ static inline bool drgn_type_kind_has_tag(enum drgn_type_kind kind) { return (kind == DRGN_TYPE_STRUCT || kind == DRGN_TYPE_UNION || kind == DRGN_TYPE_CLASS || kind == DRGN_TYPE_ENUM); } /** Get whether a type has a tag. @sa drgn_type_kind_has_tag() */ static inline bool drgn_type_has_tag(struct drgn_type *type) { return drgn_type_kind_has_tag(drgn_type_kind(type)); } /** * Get the tag of a type. @ref drgn_type_has_tag() must be true for this type. */ static inline const char *drgn_type_tag(struct drgn_type *type) { assert(drgn_type_has_tag(type)); return type->_private.tag; } /** * Get whether a kind of type has members. This is true for structure, union, * and class types. */ static inline bool drgn_type_kind_has_members(enum drgn_type_kind kind) { return (kind == DRGN_TYPE_STRUCT || kind == DRGN_TYPE_UNION || kind == DRGN_TYPE_CLASS); } /** Get whether a type has members. @sa drgn_type_kind_has_members() */ static inline bool drgn_type_has_members(struct drgn_type *type) { return drgn_type_kind_has_members(drgn_type_kind(type)); } /** * Get the members of a type. @ref drgn_type_has_members() must be true for this * type. */ static inline struct drgn_type_member *drgn_type_members(struct drgn_type *type) { assert(drgn_type_has_members(type)); return type->_private.members; } /** * Get the number of members of a type. @ref drgn_type_has_members() must be * true for this type. If the type is incomplete, this is always zero. */ static inline size_t drgn_type_num_members(struct drgn_type *type) { assert(drgn_type_has_members(type)); return type->_private.num_members; } /** * Get whether a kind of type has a wrapped type. This is true for enumerated, * typedef, pointer, array, and function types. */ static inline bool drgn_type_kind_has_type(enum drgn_type_kind kind) { return (kind == DRGN_TYPE_ENUM || kind == DRGN_TYPE_TYPEDEF || kind == DRGN_TYPE_POINTER || kind == DRGN_TYPE_ARRAY || kind == DRGN_TYPE_FUNCTION); } /** Get whether a type has a wrapped type. @sa drgn_type_kind_has_type() */ static inline bool drgn_type_has_type(struct drgn_type *type) { return drgn_type_kind_has_type(drgn_type_kind(type)); } /** * Get the type wrapped by this type. * * For an enumerated type, this is the compatible integer type. It is @c NULL if * the enumerated type is incomplete. * * For a typedef type, this is the aliased type. * * For a pointer type, this is the referenced type. * * For an array type, this is the element type. * * For a function type, this is the return type. */ static inline struct drgn_qualified_type drgn_type_type(struct drgn_type *type) { assert(drgn_type_has_type(type)); return (struct drgn_qualified_type){ .type = type->_private.type, .qualifiers = type->_private.qualifiers, }; } /** * Get whether a kind of type has enumerators. This is true for enumerated * types. */ static inline bool drgn_type_kind_has_enumerators(enum drgn_type_kind kind) { return kind == DRGN_TYPE_ENUM; } /** Get whether a type has enumerators. @sa drgn_type_kind_has_enumerators() */ static inline bool drgn_type_has_enumerators(struct drgn_type *type) { return drgn_type_kind_has_enumerators(drgn_type_kind(type)); } /** * Get the enumerators of a type. @ref drgn_type_has_enumerators() must be true * for this type. */ static inline struct drgn_type_enumerator * drgn_type_enumerators(struct drgn_type *type) { assert(drgn_type_has_enumerators(type)); return type->_private.enumerators; } /** * Get the number of enumerators of a type. @ref drgn_type_has_enumerators() * must be true for this type. If the type is incomplete, this is always zero. */ static inline size_t drgn_type_num_enumerators(struct drgn_type *type) { assert(drgn_type_has_enumerators(type)); return type->_private.num_enumerators; } /** Get whether a kind of type has a length. This is true for array types. */ static inline bool drgn_type_kind_has_length(enum drgn_type_kind kind) { return kind == DRGN_TYPE_ARRAY; } /** Get whether a type has a length. @sa drgn_type_kind_has_length() */ static inline bool drgn_type_has_length(struct drgn_type *type) { return drgn_type_kind_has_length(drgn_type_kind(type)); } /** * Get the length of a type. @ref drgn_type_has_length() must be true for this * type. If the type is incomplete, this is always zero. */ static inline uint64_t drgn_type_length(struct drgn_type *type) { assert(drgn_type_has_length(type)); return type->_private.length; } /** * Get whether a kind of type has parameters. This is true for function types. */ static inline bool drgn_type_kind_has_parameters(enum drgn_type_kind kind) { return kind == DRGN_TYPE_FUNCTION; } /** Get whether a type has parameters. @sa drgn_type_kind_has_parameters() */ static inline bool drgn_type_has_parameters(struct drgn_type *type) { return drgn_type_kind_has_parameters(drgn_type_kind(type)); } /** * Get the parameters of a type. @ref drgn_type_has_parameters() must be true * for this type. */ static inline struct drgn_type_parameter *drgn_type_parameters(struct drgn_type *type) { assert(drgn_type_has_parameters(type)); return type->_private.parameters; } /** * Get the number of parameters of a type. @ref drgn_type_has_parameters() must * be true for this type. */ static inline size_t drgn_type_num_parameters(struct drgn_type *type) { assert(drgn_type_has_parameters(type)); return type->_private.num_parameters; } /** * Get whether a kind of type can be variadic. This is true for function types. */ static inline bool drgn_type_kind_has_is_variadic(enum drgn_type_kind kind) { return kind == DRGN_TYPE_FUNCTION; } /** Get whether a type can be variadic. @sa drgn_type_kind_has_is_variadic() */ static inline bool drgn_type_has_is_variadic(struct drgn_type *type) { return drgn_type_kind_has_is_variadic(drgn_type_kind(type)); } /** * Get whether a type is variadic. @ref drgn_type_has_is_variadic() must be true * for this type. */ static inline bool drgn_type_is_variadic(struct drgn_type *type) { assert(drgn_type_has_is_variadic(type)); return type->_private.is_variadic; } /** Get whether a kind of type can have template parameters. */ static inline bool drgn_type_kind_has_template_parameters(enum drgn_type_kind kind) { return (kind == DRGN_TYPE_STRUCT || kind == DRGN_TYPE_UNION || kind == DRGN_TYPE_CLASS || kind == DRGN_TYPE_FUNCTION); } /** Get whether a type can have template parameters. */ static inline bool drgn_type_has_template_parameters(struct drgn_type *type) { return drgn_type_kind_has_template_parameters(drgn_type_kind(type)); } /** * Get the template parameters of a type. @ref * drgn_type_has_template_parameters() must be true for this type. */ static inline struct drgn_type_template_parameter * drgn_type_template_parameters(struct drgn_type *type) { assert(drgn_type_has_template_parameters(type)); return type->_private.template_parameters; } /** * Get the number of template parameters of a type. @ref * drgn_type_has_template_parameters() must be true for this type. */ static inline size_t drgn_type_num_template_parameters(struct drgn_type *type) { assert(drgn_type_has_template_parameters(type)); return type->_private.num_template_parameters; } /** * Get the object corresponding to a @ref drgn_type_member. * * @param[in] member Member. * @param[out] ret Returned object. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_member_object(struct drgn_type_member *member, const struct drgn_object **ret) __attribute__((__nonnull__(1, 2))); /** * Get the type of a @ref drgn_type_member. * * @param[in] member Member. * @param[out] type_ret Returned type. * @param[out] bit_field_size_ret If the member is a bit field, returned size of * the field in bits. Otherwise, returned as 0. Can be @c NULL if not needed. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_member_type(struct drgn_type_member *member, struct drgn_qualified_type *type_ret, uint64_t *bit_field_size_ret) __attribute__((__nonnull__(1, 2))); /** * Get the default argument of a @ref drgn_type_parameter. * * @param[in] parameter Parameter. * @param[out] ret Returned object. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error * drgn_parameter_default_argument(struct drgn_type_parameter *parameter, const struct drgn_object **ret) __attribute__((__nonnull__(1, 2))); /** * Get the type of a @ref drgn_type_parameter. * * @param[in] parameter Parameter. * @param[out] ret Returned type. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_parameter_type(struct drgn_type_parameter *parameter, struct drgn_qualified_type *ret) __attribute__((__nonnull__(1, 2))); /** * Get the type of a @ref drgn_type_template_parameter. * * If the template parameter is a non-type template parameter, this is the type * of its value. * * @param[in] parameter Template parameter. * @param[out] ret Returned type. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error * drgn_template_parameter_type(struct drgn_type_template_parameter *parameter, struct drgn_qualified_type *ret) __attribute__((__nonnull__(1, 2))); /** * Get the value of a @ref drgn_type_template_parameter. * * @param[in] parameter Template parameter. * @param[out] ret Returned object. If @p parameter is a type template * parameter, this is returned as @c NULL. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error * drgn_template_parameter_object(struct drgn_type_template_parameter *parameter, const struct drgn_object **ret) __attribute__((__nonnull__(1, 2))); /** * Get the size of a type in bytes. * * Unlike @ref drgn_type_size(), this is applicable to any type which has a * meaningful size, including typedefs and arrays. Void, function, and * incomplete types do not have a size; an error is returned for those types. * * @param[in] type Type. * @param[out] ret Returned size. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_type_sizeof(struct drgn_type *type, uint64_t *ret); /** * Get the offset in bytes of a member from the start of a structure, union, or * class type. * * This corresponds to @c offsetof() in C. * * @param[in] type Type which contains the member. * @param[in] member_designator Name of the member in @p type. This can include * one or more member references and zero or more array subscripts. */ struct drgn_error *drgn_type_offsetof(struct drgn_type *type, const char *member_designator, uint64_t *ret); /** * Like @ref drgn_type_find_member(), but takes the length of @p member_name. */ struct drgn_error * drgn_type_find_member_len(struct drgn_type *type, const char *member_name, size_t member_name_len, struct drgn_type_member **member_ret, uint64_t *bit_offset_ret); /** * Find a member in a @ref drgn_type by name. * * If the type has any unnamed members, this also matches members of those * unnamed members, recursively. * * @param[in] type Structure, union, or class type. * @param[in] member_name Name of member. * @param[out] member_ret Returned member. * @param[out] bit_offset_ret Returned offset in bits from the beginning of @p * type to the beginning of the member. This can be different from @ref * drgn_type_member::bit_offset if the returned member was found in an unnamed * member of @p type. */ static inline struct drgn_error * drgn_type_find_member(struct drgn_type *type, const char *member_name, struct drgn_type_member **member_ret, uint64_t *bit_offset_ret) { return drgn_type_find_member_len(type, member_name, strlen(member_name), member_ret, bit_offset_ret); } /** Like @ref drgn_type_has_member(), but takes the length of @p member_name. */ struct drgn_error *drgn_type_has_member_len(struct drgn_type *type, const char *member_name, size_t member_name_len, bool *ret); /** * Return whether a @ref drgn_type has a member with the given name. * * @param[in] type Structure, union, or class type. * @param[in] member_name Name of member. */ static inline struct drgn_error *drgn_type_has_member(struct drgn_type *type, const char *member_name, bool *ret) { return drgn_type_has_member_len(type, member_name, strlen(member_name), ret); } /** * Format the name of a type as a string. * * This will format the name of the type as it would be referred to in its * programming language. * * @param[in] qualified_type Type to format. * @param[out] ret Returned string. On success, it must be freed with @c free(). * On error, it is not modified. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error * drgn_format_type_name(struct drgn_qualified_type qualified_type, char **ret); /** * Format the definition of a type as a string. * * This will format the type as it would be defined in its programming language. * * @param[in] qualified_type Type to format. * @param[out] ret Returned string. On success, it must be freed with @c free(). * On error, it is not modified. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_format_type(struct drgn_qualified_type qualified_type, char **ret); /** @} */ /** * @defgroup Symbols Symbols * * Symbol table entries. * * @sa drgn_program_find_symbol_by_address() * * @{ */ /** Symbol linkage behavior and visibility. */ enum drgn_symbol_binding { DRGN_SYMBOL_BINDING_UNKNOWN, /* * These values match the ELF STB_* definitions (offset by 1). This is * an implementation detail; future values may not correspond 1:1 with * ELF definitions. */ DRGN_SYMBOL_BINDING_LOCAL, DRGN_SYMBOL_BINDING_GLOBAL, DRGN_SYMBOL_BINDING_WEAK, DRGN_SYMBOL_BINDING_UNIQUE = 11, /* STB_GNU_UNIQUE + 1 */ } __attribute__((__packed__)); /** Kind of entity represented by a symbol. */ enum drgn_symbol_kind { /* * Like enum drgn_symbol_binding, these values match the ELF STT_* * definitions, but this will not necessarily be true for future values. */ DRGN_SYMBOL_KIND_UNKNOWN, DRGN_SYMBOL_KIND_OBJECT, DRGN_SYMBOL_KIND_FUNC, DRGN_SYMBOL_KIND_SECTION, DRGN_SYMBOL_KIND_FILE, DRGN_SYMBOL_KIND_COMMON, DRGN_SYMBOL_KIND_TLS, DRGN_SYMBOL_KIND_IFUNC = 10, /* STT_GNU_IFUNC */ } __attribute__((__packed__)); /** Describes the lifetime of an object provided to drgn */ enum drgn_lifetime { /** * DRGN_LIFETIME_STATIC: the object is guaranteed to outlive the * drgn_program itself. drgn will not free or copy the object. */ DRGN_LIFETIME_STATIC, /** * DRGN_LIFETIME_EXTERNAL: the object is externally managed. It will * live as long as the object it is associated with, but may be freed * after. drgn will never free the object. If drgn must copy a data * structure, the object will be duplicated, and drgn will own the new * object. */ DRGN_LIFETIME_EXTERNAL, /** * DRGN_LIFETIME_OWNED: the object lifetime is managed by drgn. It * should be freed when the containing object is freed. If the * containing object is copied, it must also be copied. */ DRGN_LIFETIME_OWNED, } __attribute__((__packed__)); /** * Create a new @ref drgn_symbol with the given values * * All parameters should be self-explanatory, except for @a name_lifetime. * Clients can use this to describe how drgn should treat the string @a name. * Strings with lifetime @c STATIC will never be copied or freed. Strings with * lifetime @c OWNED will always be copied or and freed with the symbol. Strings * with lifetime EXTERNAL will not be freed, but if the Symbol is copied, they * will be copied. */ struct drgn_error * drgn_symbol_create(const char *name, uint64_t address, uint64_t size, enum drgn_symbol_binding binding, enum drgn_symbol_kind kind, enum drgn_lifetime name_lifetime, struct drgn_symbol **ret); /** Destroy a @ref drgn_symbol. */ void drgn_symbol_destroy(struct drgn_symbol *sym); /** * Destroy each @ref drgn_symbol in @syms, and free the array. * * This will ignore any @c NULL entry in the array, allowing you to take * ownership of any symbol from the array prior to freeing the rest. For each * symbol you take ownership of, you must free it with @ref * drgn_symbol_destroy(). */ void drgn_symbols_destroy(struct drgn_symbol **syms, size_t count); /** * Get the name of a @ref drgn_symbol. * * The returned string is valid until @p sym is destroyed. It should not be * freed. */ const char *drgn_symbol_name(struct drgn_symbol *sym); /** Get the start address of a @ref drgn_symbol. */ uint64_t drgn_symbol_address(struct drgn_symbol *sym); /** Get the size in bytes of a @ref drgn_symbol. */ uint64_t drgn_symbol_size(struct drgn_symbol *sym); /** Get the binding of a @ref drgn_symbol. */ enum drgn_symbol_binding drgn_symbol_binding(struct drgn_symbol *sym); /** Get the kind of a @ref drgn_symbol. */ enum drgn_symbol_kind drgn_symbol_kind(struct drgn_symbol *sym); /** Return whether two symbols are identical. */ bool drgn_symbol_eq(struct drgn_symbol *a, struct drgn_symbol *b); /** @} */ /** * @defgroup StackTraces Stack traces * * Call stacks and stack frames. * * @{ */ struct drgn_stack_trace; // IWYU pragma: export /** Destroy a @ref drgn_stack_trace. */ void drgn_stack_trace_destroy(struct drgn_stack_trace *trace); /** Get the @ref drgn_program that a @ref drgn_stack_trace came from. */ struct drgn_program *drgn_stack_trace_program(struct drgn_stack_trace *trace); /** Get the number of stack frames in a stack trace. */ size_t drgn_stack_trace_num_frames(struct drgn_stack_trace *trace); /** * Format a stack trace as a string. * * @param[out] ret Returned string. On success, it must be freed with @c free(). * On error, it is not modified. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_format_stack_trace(struct drgn_stack_trace *trace, char **ret); /** Return whether a stack frame was interrupted (e.g., by a signal). */ bool drgn_stack_frame_interrupted(struct drgn_stack_trace *trace, size_t frame); /** * Format a stack frame as a string. * * @param[out] ret Returned string. On success, it must be freed with @c free(). * On error, it is not modified. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_format_stack_frame(struct drgn_stack_trace *trace, size_t frame, char **ret); /** * Get the name of the function at a stack frame. * * @return Function name. This is valid until the stack trace is destroyed; it * should not be freed. @c NULL if the name could not be determined. */ const char *drgn_stack_frame_name(struct drgn_stack_trace *trace, size_t frame); /** Return whether a stack frame is for an inlined call. */ bool drgn_stack_frame_is_inline(struct drgn_stack_trace *trace, size_t frame); /** * Get the source code location of a stack frame. * * @param[out] line_ret Returned line number. Returned as 0 if unknown. May be * @c NULL if not needed. * @param[out] column_ret Returned column number. Returned as 0 if unknown. May * be @c NULL if not needed. * @return Filename. This is valid until the stack trace is destroyed; it should * not be freed. @c NULL if the location could not be determined (in which case * `*line_ret` and `*column_ret` are undefined). */ const char *drgn_stack_frame_source(struct drgn_stack_trace *trace, size_t frame, int *line_ret, int *column_ret); /** * Get the program counter at a stack frame. * * @param[out] ret Returned program counter. * @return @c true if the program counter is known, @c false if it is not. */ bool drgn_stack_frame_pc(struct drgn_stack_trace *trace, size_t frame, uint64_t *ret); /** * Get the stack pointer at a stack frame. * * @param[out] ret Returned stack pointer. * @return @c true if the stack pointer is known, @c false if it is not. */ bool drgn_stack_frame_sp(struct drgn_stack_trace *trace, size_t frame, uint64_t *ret); /** * Get the function symbol at a stack frame. * * @param[out] ret Returned symbol. On success, it should be freed with @ref * drgn_symbol_destroy(). On error, its contents are undefined. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_stack_frame_symbol(struct drgn_stack_trace *trace, size_t frame, struct drgn_symbol **ret); /** * Get the names of local objects in the scope of this frame. * * The array of names must be freed with @ref drgn_stack_frame_locals_destroy(). * * @param[out] names_ret Returned array of names. On success, must be freed with * @ref drgn_stack_frame_locals_destroy(). * @param[out] count_ret Returned number of names in @p names_ret. * @return @c NULL on success, non-@c NULL on error */ struct drgn_error * drgn_stack_frame_locals(struct drgn_stack_trace *trace, size_t frame, const char ***names_ret, size_t *count_ret); /** * Free an array of names returned by @ref drgn_stack_frame_locals(). * * The individual names from this array are invalid once this function is * called. Any string which will be used later should be copied. * * @param names Array of names returned by @ref drgn_stack_frame_locals(). * @param count Count returned by @ref drgn_stack_frame_locals(). */ void drgn_stack_frame_locals_destroy(const char **names, size_t count); /** * Find an object in the scope of a stack frame. * * @param[in] name Object name. * @param[out] ret Returned object. This must have already been initialized with * @ref drgn_object_init(). * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error * drgn_stack_frame_find_object(struct drgn_stack_trace *trace, size_t frame, const char *name, struct drgn_object *ret); /** * Get the value of a register in a stack frame. * * @param[in] reg Register to get. Must be from the platform of the program that * the trace was taken from. * @param[out] ret Returned register value. * @return @c true on success, @c false if the value is not known or the * register is too large to return in a @c uint64_t. */ bool drgn_stack_frame_register(struct drgn_stack_trace *trace, size_t frame, const struct drgn_register *reg, uint64_t *ret); /** * Get a stack trace for the thread with the given thread ID. * * @param[out] ret Returned stack trace. On success, it should be freed with * @ref drgn_stack_trace_destroy(). On error, its contents are undefined. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_program_stack_trace(struct drgn_program *prog, uint32_t tid, struct drgn_stack_trace **ret); /** * Get a stack trace with the supplied list of program counters. * * @param[out] ret Returned stack trace. On success, it should be freed with * @ref drgn_stack_trace_destroy(). On error, its contents are undefined. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error * drgn_program_stack_trace_from_pcs(struct drgn_program *prog, const uint64_t *pcs, size_t pcs_size, struct drgn_stack_trace **ret); /** * Get a stack trace for the thread represented by @p obj. * * @sa drgn_program_stack_trace(). */ struct drgn_error *drgn_object_stack_trace(const struct drgn_object *obj, struct drgn_stack_trace **ret); /** @} */ /** * @defgroup Threads Threads * * Threads in a program. * * @{ */ /** * @struct drgn_thread * * A thread in a program. */ struct drgn_thread; /** * Create a copy of a @ref drgn_thread. * * @param[in] thread Thread to copy. * @param[out] ret Returned copy. On success, must be destroyed with @ref * drgn_thread_destroy(). * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_thread_dup(const struct drgn_thread *thread, struct drgn_thread **ret); /** Free a @ref drgn_thread. */ void drgn_thread_destroy(struct drgn_thread *thread); /** * @struct drgn_thread_iterator * * An iterator over all the threads in a program. */ struct drgn_thread_iterator; /** * Get an iterator over all of the threads in the program. * * @param[out] ret Returned iterator, which can be advanced with @ref * drgn_thread_iterator_next, and must be destroyed with @ref * drgn_thread_iterator_destroy. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error * drgn_thread_iterator_create(struct drgn_program *prog, struct drgn_thread_iterator **ret); /** Free a @ref drgn_thread_iterator. */ void drgn_thread_iterator_destroy(struct drgn_thread_iterator *it); /** * Get the next thread from a @ref drgn_thread_iterator. * * @param[out] ret Borrowed thread handle, or @c NULL if there are no more * threads. This is valid until until the next call to @ref * drgn_thread_iterator_next() with the same @p it, or until @p it is destroyed. * It may be copied with @ref drgn_thread_dup() if it is needed for longer. This * must NOT be destroyed with @ref drgn_thread_destroy(). * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_thread_iterator_next(struct drgn_thread_iterator *it, struct drgn_thread **ret); /** * Get the thread with the given thread ID. * * @param[in] tid Thread ID. * @param[out] ret New thread handle, or @c NULL if not found. On success, must * be destroyed with @ref drgn_thread_destroy(). * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_program_find_thread(struct drgn_program *prog, uint32_t tid, struct drgn_thread **ret); /** * Get the main program thread. * * @param[out] ret Borrowed thread handle. This is valid for the lifetime of @p * prog. This must NOT be destroyed with @ref drgn_thread_destroy(). * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_program_main_thread(struct drgn_program *prog, struct drgn_thread **ret); /** * Get the thread that caused the program to crash. * * @param[out] ret Borrowed thread handle. This is valid for the lifetime of @p * prog. This must NOT be destroyed with @ref drgn_thread_destroy(). * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_program_crashed_thread(struct drgn_program *prog, struct drgn_thread **ret); /** * Get the object for the given thread. This is currently only defined for the * Linux kernel. * * @param[out] ret Returned object. This must not be modified and is valid for * the lifetime of @p thread. It can be copied with @ref drgn_object_copy() if * it is needed for longer. * @return @c NULL on success, non-@c NULL on error. */ struct drgn_error *drgn_thread_object(struct drgn_thread *thread, const struct drgn_object **ret); /** * Get a stack trace for the thread represented by @p thread. * * @sa drgn_program_stack_trace(). */ struct drgn_error *drgn_thread_stack_trace(struct drgn_thread *thread, struct drgn_stack_trace **ret); /** @} */ #endif /* DRGN_H */