diff --git a/libdrgn/debug_info.c b/libdrgn/debug_info.c index 64eaf417..4f5948d8 100644 --- a/libdrgn/debug_info.c +++ b/libdrgn/debug_info.c @@ -2044,6 +2044,8 @@ void drgn_debug_info_init(struct drgn_debug_info *dbinfo, drgn_program_add_object_finder_impl(prog, &dbinfo->object_finder, drgn_debug_info_find_object, dbinfo); + drgn_program_add_symbol_finder_impl(prog, &dbinfo->symbol_finder, + elf_symbols_search, prog); drgn_module_table_init(&dbinfo->modules); c_string_set_init(&dbinfo->module_names); drgn_dwarf_info_init(dbinfo); diff --git a/libdrgn/debug_info.h b/libdrgn/debug_info.h index 64e8bb86..0b689106 100644 --- a/libdrgn/debug_info.h +++ b/libdrgn/debug_info.h @@ -23,6 +23,7 @@ #include "object_index.h" #include "orc_info.h" #include "string_builder.h" +#include "symbol.h" #include "type.h" #include "vector.h" @@ -137,6 +138,7 @@ struct drgn_debug_info { struct drgn_type_finder type_finder; struct drgn_object_finder object_finder; + struct drgn_symbol_finder symbol_finder; /** DWARF frontend library handle. */ Dwfl *dwfl; diff --git a/libdrgn/drgn.h b/libdrgn/drgn.h index cdde3e9a..4636899c 100644 --- a/libdrgn/drgn.h +++ b/libdrgn/drgn.h @@ -930,6 +930,73 @@ struct drgn_error *drgn_program_find_symbols_by_address(struct drgn_program *pro struct drgn_symbol ***syms_ret, size_t *count_ret); +/** Flags for @ref drgn_symbol_find_fn() */ +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_find_fn() */ +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); + +/** + * Callback for finding one or more symbols. + * + * The callback should perform a symbol lookup based on the flags given in @a + * flags. When multiple flags are provided, the effect should be treated as a + * logical AND. Symbol results should be added to the result builder @a 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_add_symbol_finder(). + * @param[in] builder Used to build the resulting symbol output + */ +typedef struct drgn_error * +(*drgn_symbol_find_fn)(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. + * + * Callbacks are called in reverse order that they were originally added. 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] fn Symbol search function + * @param[in] arg Argument to pass to the callback + */ +struct drgn_error * +drgn_program_add_symbol_finder(struct drgn_program *prog, + drgn_symbol_find_fn fn, void *arg); + /** Element type and size. */ struct drgn_element_info { /** Type of the element. */ diff --git a/libdrgn/program.c b/libdrgn/program.c index c21c2d99..db7c7704 100644 --- a/libdrgn/program.c +++ b/libdrgn/program.c @@ -112,6 +112,17 @@ void drgn_program_init(struct drgn_program *prog, drgn_object_init(&prog->vmemmap, prog); } +static void drgn_program_deinit_symbol_finders(struct drgn_program *prog) +{ + struct drgn_symbol_finder *finder = prog->symbol_finders; + while (finder) { + struct drgn_symbol_finder *next = finder->next; + if (finder->free) + free(finder); + finder = next; + } +} + void drgn_program_deinit(struct drgn_program *prog) { if (prog->core_dump_notes_cached) { @@ -135,6 +146,7 @@ void drgn_program_deinit(struct drgn_program *prog) drgn_object_deinit(&prog->vmemmap); drgn_object_index_deinit(&prog->oindex); + drgn_program_deinit_symbol_finders(prog); drgn_program_deinit_types(prog); drgn_memory_reader_deinit(&prog->reader); @@ -1798,57 +1810,83 @@ struct drgn_error *drgn_error_symbol_not_found(uint64_t address) address); } -LIBDRGN_PUBLIC struct drgn_error * -drgn_program_find_symbol_by_address(struct drgn_program *prog, uint64_t address, - struct drgn_symbol **ret) -{ - struct drgn_symbol *sym; - - sym = malloc(sizeof(*sym)); - if (!sym) - return &drgn_enomem; - if (!drgn_program_find_symbol_by_address_internal(prog, address, NULL, - sym)) { - free(sym); - return drgn_error_symbol_not_found(address); - } - *ret = sym; - return NULL; -} - -DEFINE_VECTOR(symbolp_vector, struct drgn_symbol *); - -enum { - SYMBOLS_SEARCH_NAME = (1 << 0), - SYMBOLS_SEARCH_ADDRESS = (1 << 1), - SYMBOLS_SEARCH_ALL = (1 << 2), -}; - -struct symbols_search_arg { +struct elf_symbols_search_arg { const char *name; uint64_t address; - struct symbolp_vector results; - unsigned int flags; + enum drgn_find_symbol_flags flags; + struct drgn_error *err; + struct drgn_symbol_result_builder *builder; }; -static bool symbol_match(struct symbols_search_arg *arg, GElf_Addr addr, +static bool elf_symbol_match(struct elf_symbols_search_arg *arg, GElf_Addr addr, const GElf_Sym *sym, const char *name) { - if (arg->flags & SYMBOLS_SEARCH_ALL) - return true; - if ((arg->flags & SYMBOLS_SEARCH_NAME) && strcmp(name, arg->name) == 0) - return true; - if ((arg->flags & SYMBOLS_SEARCH_ADDRESS) && - arg->address >= addr && arg->address < addr + sym->st_size) - return true; - return false; + if ((arg->flags & DRGN_FIND_SYMBOL_NAME) && strcmp(name, arg->name) != 0) + return false; + if ((arg->flags & DRGN_FIND_SYMBOL_ADDR) && + (arg->address < addr || arg->address >= addr + sym->st_size)) + return false; + return true; } -static int symbols_search_cb(Dwfl_Module *dwfl_module, void **userdatap, +static bool elf_symbol_store_match(struct elf_symbols_search_arg *arg, + GElf_Sym *elf_sym, GElf_Addr addr, + const char *name) +{ + struct drgn_symbol *sym; + if (arg->flags == (DRGN_FIND_SYMBOL_ONE | DRGN_FIND_SYMBOL_NAME)) { + int binding = GELF_ST_BIND(elf_sym->st_info); + /* + * The order of precedence is + * GLOBAL = UNIQUE > WEAK > LOCAL = everything else + * + * If we found a global or unique symbol, return it + * immediately. If we found a weak symbol, then save it, + * which may overwrite a previously found weak or local + * symbol. Otherwise, save the symbol only if we haven't + * found another symbol. + */ + if (binding != STB_GLOBAL + && binding != STB_GNU_UNIQUE + && binding != STB_WEAK + && drgn_symbol_result_builder_count(arg->builder) > 0) + return false; + sym = malloc(sizeof(*sym)); + if (!sym) { + arg->err = &drgn_enomem; + return true; + } + drgn_symbol_from_elf(name, addr, elf_sym, sym); + if (!drgn_symbol_result_builder_add(arg->builder, sym)) { + arg->err = &drgn_enomem; + drgn_symbol_destroy(sym); + } + + /* Abort on error, or short-circuit if we found a global or + * unique symbol */ + return (arg->err || sym->binding == DRGN_SYMBOL_BINDING_GLOBAL + || sym->binding == DRGN_SYMBOL_BINDING_UNIQUE); + } else { + sym = malloc(sizeof(*sym)); + if (!sym) { + arg->err = &drgn_enomem; + return true; + } + drgn_symbol_from_elf(name, addr, elf_sym, sym); + if (!drgn_symbol_result_builder_add(arg->builder, sym)) { + arg->err = &drgn_enomem; + drgn_symbol_destroy(sym); + } + /* Abort on error, or short-circuit for single lookup */ + return (arg->err || (arg->flags & DRGN_FIND_SYMBOL_ONE)); + } +} + +static int elf_symbols_search_cb(Dwfl_Module *dwfl_module, void **userdatap, const char *module_name, Dwarf_Addr base, void *cb_arg) { - struct symbols_search_arg *arg = cb_arg; + struct elf_symbols_search_arg *arg = cb_arg; int symtab_len = dwfl_module_getsymtab(dwfl_module); if (symtab_len == -1) @@ -1861,66 +1899,121 @@ static int symbols_search_cb(Dwfl_Module *dwfl_module, void **userdatap, const char *name = dwfl_module_getsym_info(dwfl_module, i, &elf_sym, &elf_addr, NULL, NULL, NULL); - if (!name || !symbol_match(arg, elf_addr, &elf_sym, name)) + if (!name || !elf_symbol_match(arg, elf_addr, &elf_sym, name)) continue; - - struct drgn_symbol *sym = malloc(sizeof(*sym)); - if (!sym) + if (elf_symbol_store_match(arg, &elf_sym, elf_addr, name)) return DWARF_CB_ABORT; - drgn_symbol_from_elf(name, elf_addr, &elf_sym, sym); - if (!symbolp_vector_append(&arg->results, &sym)) { - drgn_symbol_destroy(sym); - return DWARF_CB_ABORT; - } } return DWARF_CB_OK; } -static struct drgn_error * -symbols_search(struct drgn_program *prog, struct symbols_search_arg *arg, - struct drgn_symbol ***syms_ret, size_t *count_ret) +struct drgn_error * +elf_symbols_search(const char *name, uint64_t addr, enum drgn_find_symbol_flags flags, + void *data, struct drgn_symbol_result_builder *builder) { - struct drgn_error *err; + Dwfl_Module *dwfl_module = NULL; + struct drgn_program *prog = data; + struct elf_symbols_search_arg arg = { + .name = name, + .address = addr, + .flags = flags, + .err = NULL, + .builder = builder, + }; - symbolp_vector_init(&arg->results); - - /* - * When searching for addresses, we can identify the exact module to - * search. Otherwise we need to fall back to an exhaustive search. - */ - err = NULL; - if (arg->flags & SYMBOLS_SEARCH_ADDRESS) { - Dwfl_Module *module = dwfl_addrmodule(prog->dbinfo.dwfl, - arg->address); - if (module && symbols_search_cb(module, NULL, NULL, 0, arg)) - err = &drgn_enomem; - } else { - if (dwfl_getmodules(prog->dbinfo.dwfl, symbols_search_cb, arg, - 0)) - err = &drgn_enomem; + if (arg.flags & DRGN_FIND_SYMBOL_ADDR) { + dwfl_module = dwfl_addrmodule(prog->dbinfo.dwfl, arg.address); + if (!dwfl_module) + return NULL; } - if (err) { - vector_for_each(symbolp_vector, symbolp, &arg->results) - drgn_symbol_destroy(*symbolp); - symbolp_vector_deinit(&arg->results); + if ((arg.flags & (DRGN_FIND_SYMBOL_ADDR | DRGN_FIND_SYMBOL_ONE)) + == (DRGN_FIND_SYMBOL_ADDR | DRGN_FIND_SYMBOL_ONE)) { + GElf_Off offset; + GElf_Sym elf_sym; + const char *name = dwfl_module_addrinfo( + dwfl_module, addr, &offset, + &elf_sym, NULL, NULL, NULL); + if (!name) + return NULL; + struct drgn_symbol *sym = malloc(sizeof(*sym)); + if (!sym) + return &drgn_enomem; + drgn_symbol_from_elf(name, addr - offset, &elf_sym, sym); + if (!drgn_symbol_result_builder_add(builder, sym)) { + arg.err = &drgn_enomem; + drgn_symbol_destroy(sym); + } + } else if (dwfl_module) { + elf_symbols_search_cb(dwfl_module, NULL, NULL, 0, &arg); } else { - symbolp_vector_shrink_to_fit(&arg->results); - symbolp_vector_steal(&arg->results, syms_ret, count_ret); + dwfl_getmodules(prog->dbinfo.dwfl, elf_symbols_search_cb, &arg, 0); + } + return arg.err; +} + +static struct drgn_error * +drgn_program_symbols_search(struct drgn_program *prog, const char *name, + uint64_t addr, enum drgn_find_symbol_flags flags, + struct drgn_symbol_result_builder *builder) +{ + struct drgn_error *err = NULL; + struct drgn_symbol_finder *finder = prog->symbol_finders; + while (finder) { + err = finder->fn(name, addr, flags, finder->arg, builder); + if (err || + ((flags & DRGN_FIND_SYMBOL_ONE) + && drgn_symbol_result_builder_count(builder) > 0)) + break; + finder = finder->next; } return err; } +struct drgn_error * +drgn_program_add_symbol_finder_impl(struct drgn_program *prog, + struct drgn_symbol_finder *finder, + drgn_symbol_find_fn fn, void *arg) +{ + if (finder) { + finder->free = false; + } else { + finder = malloc(sizeof(*finder)); + if (!finder) + return &drgn_enomem; + finder->free = true; + } + finder->fn = fn; + finder->arg = arg; + finder->next = prog->symbol_finders; + prog->symbol_finders = finder; + return NULL; +} + +LIBDRGN_PUBLIC struct drgn_error * +drgn_program_add_symbol_finder(struct drgn_program *prog, + drgn_symbol_find_fn fn, + void *arg) +{ + return drgn_program_add_symbol_finder_impl(prog, NULL, fn, arg); +} + LIBDRGN_PUBLIC 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) { - struct symbols_search_arg arg = { - .name = name, - .flags = name ? SYMBOLS_SEARCH_NAME : SYMBOLS_SEARCH_ALL, - }; - return symbols_search(prog, &arg, syms_ret, count_ret); + struct drgn_symbol_result_builder builder; + enum drgn_find_symbol_flags flags = name ? DRGN_FIND_SYMBOL_NAME : 0; + + drgn_symbol_result_builder_init(&builder, false); + struct drgn_error *err = drgn_program_symbols_search(prog, name, 0, + flags, &builder); + if (err) + drgn_symbol_result_builder_abort(&builder); + else + drgn_symbol_result_builder_array(&builder, syms_ret, count_ret); + return err; } LIBDRGN_PUBLIC struct drgn_error * @@ -1929,88 +2022,63 @@ drgn_program_find_symbols_by_address(struct drgn_program *prog, struct drgn_symbol ***syms_ret, size_t *count_ret) { - struct symbols_search_arg arg = { - .address = address, - .flags = SYMBOLS_SEARCH_ADDRESS, - }; - return symbols_search(prog, &arg, syms_ret, count_ret); -} + struct drgn_symbol_result_builder builder; + enum drgn_find_symbol_flags flags = DRGN_FIND_SYMBOL_ADDR; -struct find_symbol_by_name_arg { - const char *name; - GElf_Sym sym; - GElf_Addr addr; - bool found; - bool bad_symtabs; -}; - -static int find_symbol_by_name_cb(Dwfl_Module *dwfl_module, void **userdatap, - const char *module_name, Dwarf_Addr base, - void *cb_arg) -{ - struct find_symbol_by_name_arg *arg = cb_arg; - int symtab_len = dwfl_module_getsymtab(dwfl_module); - if (symtab_len == -1) { - arg->bad_symtabs = true; - return DWARF_CB_OK; - } - /* - * Global symbols are after local symbols, so by iterating backwards we - * might find a global symbol faster. Ignore the zeroth null symbol. - */ - for (int i = symtab_len - 1; i > 0; i--) { - GElf_Sym sym; - GElf_Addr addr; - const char *name = dwfl_module_getsym_info(dwfl_module, i, &sym, - &addr, NULL, NULL, - NULL); - if (name && strcmp(arg->name, name) == 0) { - /* - * The order of precedence is - * GLOBAL = GNU_UNIQUE > WEAK > LOCAL = everything else - * - * If we found a global or unique symbol, return it - * immediately. If we found a weak symbol, then save it, - * which may overwrite a previously found weak or local - * symbol. Otherwise, save the symbol only if we haven't - * found another symbol. - */ - if (GELF_ST_BIND(sym.st_info) == STB_GLOBAL || - GELF_ST_BIND(sym.st_info) == STB_GNU_UNIQUE || - GELF_ST_BIND(sym.st_info) == STB_WEAK || - !arg->found) { - arg->sym = sym; - arg->addr = addr; - arg->found = true; - } - if (GELF_ST_BIND(sym.st_info) == STB_GLOBAL || - GELF_ST_BIND(sym.st_info) == STB_GNU_UNIQUE) - return DWARF_CB_ABORT; - } - } - return DWARF_CB_OK; + drgn_symbol_result_builder_init(&builder, false); + struct drgn_error *err = drgn_program_symbols_search(prog, NULL, address, + flags, &builder); + if (err) + drgn_symbol_result_builder_abort(&builder); + else + drgn_symbol_result_builder_array(&builder, syms_ret, count_ret); + return err; } LIBDRGN_PUBLIC struct drgn_error * drgn_program_find_symbol_by_name(struct drgn_program *prog, - const char *name, struct drgn_symbol **ret) + const char *name, struct drgn_symbol **ret) { - struct find_symbol_by_name_arg arg = { - .name = name, - }; - dwfl_getmodules(prog->dbinfo.dwfl, find_symbol_by_name_cb, &arg, 0); - if (arg.found) { - struct drgn_symbol *sym = malloc(sizeof(*sym)); - if (!sym) - return &drgn_enomem; - drgn_symbol_from_elf(name, arg.addr, &arg.sym, sym); - *ret = sym; - return NULL; + struct drgn_symbol_result_builder builder; + enum drgn_find_symbol_flags flags = DRGN_FIND_SYMBOL_NAME | DRGN_FIND_SYMBOL_ONE; + + drgn_symbol_result_builder_init(&builder, true); + struct drgn_error *err = drgn_program_symbols_search(prog, name, 0, + flags, &builder); + if (err) { + drgn_symbol_result_builder_abort(&builder); + return err; } - return drgn_error_format(DRGN_ERROR_LOOKUP, - "could not find symbol with name '%s'%s", name, - arg.bad_symtabs ? - " (could not get some symbol tables)" : ""); + + if (!drgn_symbol_result_builder_count(&builder)) + return drgn_error_format(DRGN_ERROR_LOOKUP, + "could not find symbol with name '%s'", name); + + *ret = drgn_symbol_result_builder_single(&builder); + return err; +} + +LIBDRGN_PUBLIC struct drgn_error * +drgn_program_find_symbol_by_address(struct drgn_program *prog, uint64_t address, + struct drgn_symbol **ret) +{ + struct drgn_symbol_result_builder builder; + enum drgn_find_symbol_flags flags = DRGN_FIND_SYMBOL_ADDR | DRGN_FIND_SYMBOL_ONE; + + drgn_symbol_result_builder_init(&builder, true); + struct drgn_error *err = drgn_program_symbols_search(prog, NULL, address, + flags, &builder); + + if (err) { + drgn_symbol_result_builder_abort(&builder); + return err; + } + + if (!drgn_symbol_result_builder_count(&builder)) + return drgn_error_symbol_not_found(address); + + *ret = drgn_symbol_result_builder_single(&builder); + return err; } LIBDRGN_PUBLIC struct drgn_error * diff --git a/libdrgn/program.h b/libdrgn/program.h index 0be3d881..3c294b03 100644 --- a/libdrgn/program.h +++ b/libdrgn/program.h @@ -27,6 +27,7 @@ #include "object_index.h" #include "platform.h" #include "pp.h" +#include "symbol.h" #include "type.h" #include "vector.h" @@ -109,6 +110,7 @@ struct drgn_program { */ struct drgn_object_index oindex; struct drgn_debug_info dbinfo; + struct drgn_symbol_finder *symbol_finders; /* * Program information. @@ -377,6 +379,17 @@ bool drgn_program_find_symbol_by_address_internal(struct drgn_program *prog, Dwfl_Module *module, struct drgn_symbol *ret); +/* + * Implementation of the Symbol finder API, based on ELF symbols + */ +struct drgn_error * +elf_symbols_search(const char *name, uint64_t addr, enum drgn_find_symbol_flags flags, + void *data, struct drgn_symbol_result_builder *builder); + +struct drgn_error * +drgn_program_add_symbol_finder_impl(struct drgn_program *prog, + struct drgn_symbol_finder *finder, + drgn_symbol_find_fn fn, void *arg); /** * Call before a blocking (I/O or long-running) operation. * diff --git a/libdrgn/symbol.c b/libdrgn/symbol.c index 89c92532..e6097b44 100644 --- a/libdrgn/symbol.c +++ b/libdrgn/symbol.c @@ -73,3 +73,61 @@ LIBDRGN_PUBLIC bool drgn_symbol_eq(struct drgn_symbol *a, struct drgn_symbol *b) a->size == b->size && a->binding == b->binding && a->kind == b->kind); } + +DEFINE_VECTOR_FUNCTIONS(symbolp_vector); + +LIBDRGN_PUBLIC bool +drgn_symbol_result_builder_add(struct drgn_symbol_result_builder *builder, + struct drgn_symbol *symbol) +{ + if (builder->one) { + if (builder->single) + drgn_symbol_destroy(builder->single); + builder->single = symbol; + } else if (!symbolp_vector_append(&builder->vector, &symbol)) { + return false; + } + return true; +} + +LIBDRGN_PUBLIC size_t +drgn_symbol_result_builder_count(const struct drgn_symbol_result_builder *builder) +{ + if (builder->one) + return builder->single ? 1 : 0; + else + return symbolp_vector_size(&builder->vector); +} + +void drgn_symbol_result_builder_init(struct drgn_symbol_result_builder *builder, + bool one) +{ + memset(builder, 0, sizeof(*builder)); + builder->one = one; + if (!one) + symbolp_vector_init(&builder->vector); +} + +void drgn_symbol_result_builder_abort(struct drgn_symbol_result_builder *builder) +{ + if (builder->one) { + drgn_symbol_destroy(builder->single); + } else { + vector_for_each(symbolp_vector, symbolp, &builder->vector) + drgn_symbol_destroy(*symbolp); + symbolp_vector_deinit(&builder->vector); + } +} + +struct drgn_symbol * +drgn_symbol_result_builder_single(struct drgn_symbol_result_builder *builder) +{ + return builder->single; +} + +void drgn_symbol_result_builder_array(struct drgn_symbol_result_builder *builder, + struct drgn_symbol ***syms_ret, size_t *count_ret) +{ + symbolp_vector_shrink_to_fit(&builder->vector); + symbolp_vector_steal(&builder->vector, syms_ret, count_ret); +} diff --git a/libdrgn/symbol.h b/libdrgn/symbol.h index e136e86e..4241a3ef 100644 --- a/libdrgn/symbol.h +++ b/libdrgn/symbol.h @@ -7,6 +7,7 @@ #include #include "drgn.h" +#include "vector.h" struct drgn_symbol { const char *name; @@ -16,8 +17,40 @@ struct drgn_symbol { enum drgn_symbol_kind kind; }; +struct drgn_symbol_finder { + drgn_symbol_find_fn fn; + void *arg; + struct drgn_symbol_finder *next; + bool free; +}; + +DEFINE_VECTOR_TYPE(symbolp_vector, struct drgn_symbol *); + +struct drgn_symbol_result_builder { + bool one; + union { + struct symbolp_vector vector; + struct drgn_symbol *single; + }; +}; + /** Initialize a @ref drgn_symbol from an ELF symbol. */ void drgn_symbol_from_elf(const char *name, uint64_t address, const GElf_Sym *elf_sym, struct drgn_symbol *ret); +/** Destroy the contents of the result builder */ +void drgn_symbol_result_builder_abort(struct drgn_symbol_result_builder *builder); + +/** Initialize result builder */ +void drgn_symbol_result_builder_init(struct drgn_symbol_result_builder *builder, + bool one); + +/** Return single result */ +struct drgn_symbol * +drgn_symbol_result_builder_single(struct drgn_symbol_result_builder *builder); + +/** Return array result */ +void drgn_symbol_result_builder_array(struct drgn_symbol_result_builder *builder, + struct drgn_symbol ***syms_ret, size_t *count_ret); + #endif /* DRGN_SYMBOL_H */