mirror of
https://github.com/JakeHillion/drgn.git
synced 2024-12-22 09:13:06 +00:00
libdrgn: fold drgn_type_index into drgn_program
This is preparation for associating types with a program. Signed-off-by: Omar Sandoval <osandov@osandov.com>
This commit is contained in:
parent
1c8181e22d
commit
c31208f69c
@ -61,8 +61,6 @@ libdrgnimpl_la_SOURCES = $(ARCH_INS:.c.in=.c) \
|
||||
symbol.h \
|
||||
type.c \
|
||||
type.h \
|
||||
type_index.c \
|
||||
type_index.h \
|
||||
util.h \
|
||||
vector.c \
|
||||
vector.h
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include "hash_table.h"
|
||||
#include "object.h"
|
||||
#include "object_index.h"
|
||||
#include "type_index.h"
|
||||
#include "type.h"
|
||||
#include "vector.h"
|
||||
|
||||
DEFINE_HASH_TABLE_FUNCTIONS(dwarf_type_map, hash_pair_ptr_type,
|
||||
@ -1025,8 +1025,8 @@ drgn_pointer_type_from_dwarf(struct drgn_dwarf_info_cache *dicache,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return drgn_type_index_pointer_type(dicache->tindex, referenced_type,
|
||||
lang, ret);
|
||||
return drgn_program_pointer_type(dicache->prog, referenced_type, lang,
|
||||
ret);
|
||||
}
|
||||
|
||||
struct array_dimension {
|
||||
@ -1129,19 +1129,18 @@ drgn_array_type_from_dwarf(struct drgn_dwarf_info_cache *dicache,
|
||||
do {
|
||||
dimension = array_dimension_vector_pop(&dimensions);
|
||||
if (dimension->is_complete) {
|
||||
err = drgn_type_index_array_type(dicache->tindex,
|
||||
dimension->length,
|
||||
element_type, lang,
|
||||
&type);
|
||||
err = drgn_program_array_type(dicache->prog,
|
||||
dimension->length,
|
||||
element_type, lang,
|
||||
&type);
|
||||
} else if (dimensions.size || !can_be_incomplete_array) {
|
||||
err = drgn_type_index_array_type(dicache->tindex, 0,
|
||||
element_type, lang,
|
||||
&type);
|
||||
err = drgn_program_array_type(dicache->prog, 0,
|
||||
element_type, lang,
|
||||
&type);
|
||||
} else {
|
||||
err = drgn_type_index_incomplete_array_type(dicache->tindex,
|
||||
element_type,
|
||||
lang,
|
||||
&type);
|
||||
err = drgn_program_incomplete_array_type(dicache->prog,
|
||||
element_type,
|
||||
lang, &type);
|
||||
}
|
||||
if (err)
|
||||
goto out;
|
||||
@ -1666,7 +1665,7 @@ drgn_dwarf_object_find(const char *name, size_t name_len, const char *filename,
|
||||
}
|
||||
|
||||
struct drgn_error *
|
||||
drgn_dwarf_info_cache_create(struct drgn_type_index *tindex,
|
||||
drgn_dwarf_info_cache_create(struct drgn_program *prog,
|
||||
const Dwfl_Callbacks *dwfl_callbacks,
|
||||
struct drgn_dwarf_info_cache **ret)
|
||||
{
|
||||
@ -1684,7 +1683,7 @@ drgn_dwarf_info_cache_create(struct drgn_type_index *tindex,
|
||||
dwarf_type_map_init(&dicache->map);
|
||||
dwarf_type_map_init(&dicache->cant_be_incomplete_array_map);
|
||||
dicache->depth = 0;
|
||||
dicache->tindex = tindex;
|
||||
dicache->prog = prog;
|
||||
*ret = dicache;
|
||||
return NULL;
|
||||
}
|
||||
|
@ -23,8 +23,7 @@
|
||||
* Caching of DWARF debugging information.
|
||||
*
|
||||
* @ref drgn_dwarf_info_cache bridges the raw DWARF information indexed by @ref
|
||||
* drgn_dwarf_index to the higher-level @ref drgn_type_index and @ref
|
||||
* drgn_object_index.
|
||||
* drgn_dwarf_index to higher-level type and object finders.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
@ -73,13 +72,13 @@ struct drgn_dwarf_info_cache {
|
||||
struct dwarf_type_map cant_be_incomplete_array_map;
|
||||
/** Current parsing recursion depth. */
|
||||
int depth;
|
||||
/** Type index. */
|
||||
struct drgn_type_index *tindex;
|
||||
/** Program owning this cache. */
|
||||
struct drgn_program *prog;
|
||||
};
|
||||
|
||||
/** Create a @ref drgn_dwarf_info_cache. */
|
||||
struct drgn_error *
|
||||
drgn_dwarf_info_cache_create(struct drgn_type_index *tindex,
|
||||
drgn_dwarf_info_cache_create(struct drgn_program *prog,
|
||||
const Dwfl_Callbacks *dwfl_callbacks,
|
||||
struct drgn_dwarf_info_cache **ret);
|
||||
|
||||
|
@ -12,9 +12,10 @@
|
||||
#ifndef DRGN_LANGUAGE_H
|
||||
#define DRGN_LANGUAGE_H
|
||||
|
||||
#include "drgn.h"
|
||||
#include <dwarf.h>
|
||||
|
||||
#include "drgn.h"
|
||||
|
||||
/**
|
||||
* @ingroup Internals
|
||||
*
|
||||
@ -28,15 +29,13 @@
|
||||
* @{
|
||||
*/
|
||||
|
||||
struct drgn_type_index;
|
||||
|
||||
typedef struct drgn_error *drgn_format_type_fn(struct drgn_qualified_type,
|
||||
char **);
|
||||
typedef struct drgn_error *drgn_format_object_fn(const struct drgn_object *,
|
||||
size_t,
|
||||
enum drgn_format_object_flags,
|
||||
char **);
|
||||
typedef struct drgn_error *drgn_find_type_fn(struct drgn_type_index *tindex,
|
||||
typedef struct drgn_error *drgn_find_type_fn(struct drgn_program *prog,
|
||||
const char *name,
|
||||
const char *filename,
|
||||
struct drgn_qualified_type *ret);
|
||||
@ -78,10 +77,10 @@ struct drgn_language {
|
||||
/** Implement @ref drgn_format_object(). */
|
||||
drgn_format_object_fn *format_object;
|
||||
/**
|
||||
* Implement @ref drgn_type_index_find().
|
||||
* Implement @ref drgn_program_find_type().
|
||||
*
|
||||
* This should parse @p name and call @ref
|
||||
* drgn_type_index_find_parsed().
|
||||
* drgn_program_find_type_impl().
|
||||
*/
|
||||
drgn_find_type_fn *find_type;
|
||||
/**
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include "string_builder.h"
|
||||
#include "symbol.h"
|
||||
#include "type.h"
|
||||
#include "type_index.h"
|
||||
|
||||
static struct drgn_error *
|
||||
c_declare_variable(struct drgn_qualified_type qualified_type,
|
||||
@ -2111,7 +2110,7 @@ out:
|
||||
}
|
||||
|
||||
static struct drgn_error *
|
||||
c_parse_specifier_qualifier_list(struct drgn_type_index *tindex,
|
||||
c_parse_specifier_qualifier_list(struct drgn_program *prog,
|
||||
struct drgn_lexer *lexer, const char *filename,
|
||||
struct drgn_qualified_type *ret)
|
||||
{
|
||||
@ -2206,17 +2205,17 @@ c_parse_specifier_qualifier_list(struct drgn_type_index *tindex,
|
||||
kind = DRGN_TYPE_ENUM;
|
||||
} else if (identifier) {
|
||||
if (strstartswith(identifier, "size_t")) {
|
||||
err = drgn_type_index_find_primitive(tindex,
|
||||
DRGN_C_TYPE_SIZE_T,
|
||||
&ret->type);
|
||||
err = drgn_program_find_primitive_type(prog,
|
||||
DRGN_C_TYPE_SIZE_T,
|
||||
&ret->type);
|
||||
if (err)
|
||||
return err;
|
||||
ret->qualifiers = 0;
|
||||
goto out;
|
||||
} else if (strstartswith(identifier, "ptrdiff_t")) {
|
||||
err = drgn_type_index_find_primitive(tindex,
|
||||
DRGN_C_TYPE_PTRDIFF_T,
|
||||
&ret->type);
|
||||
err = drgn_program_find_primitive_type(prog,
|
||||
DRGN_C_TYPE_PTRDIFF_T,
|
||||
&ret->type);
|
||||
if (err)
|
||||
return err;
|
||||
ret->qualifiers = 0;
|
||||
@ -2229,15 +2228,15 @@ c_parse_specifier_qualifier_list(struct drgn_type_index *tindex,
|
||||
"expected type specifier");
|
||||
}
|
||||
|
||||
err = drgn_type_index_find_parsed(tindex, kind, identifier,
|
||||
err = drgn_program_find_type_impl(prog, kind, identifier,
|
||||
identifier_len, filename,
|
||||
ret);
|
||||
if (err)
|
||||
return err;
|
||||
} else {
|
||||
err = drgn_type_index_find_primitive(tindex,
|
||||
specifier_kind[specifier],
|
||||
&ret->type);
|
||||
err = drgn_program_find_primitive_type(prog,
|
||||
specifier_kind[specifier],
|
||||
&ret->type);
|
||||
if (err)
|
||||
return err;
|
||||
ret->qualifiers = 0;
|
||||
@ -2259,7 +2258,7 @@ struct c_declarator {
|
||||
|
||||
/* These functions don't free the declarator list on error. */
|
||||
static struct drgn_error *
|
||||
c_parse_abstract_declarator(struct drgn_type_index *tindex,
|
||||
c_parse_abstract_declarator(struct drgn_program *prog,
|
||||
struct drgn_lexer *lexer,
|
||||
struct c_declarator **outer,
|
||||
struct c_declarator **inner);
|
||||
@ -2289,7 +2288,7 @@ c_parse_optional_type_qualifier_list(struct drgn_lexer *lexer,
|
||||
}
|
||||
|
||||
static struct drgn_error *
|
||||
c_parse_pointer(struct drgn_type_index *tindex, struct drgn_lexer *lexer,
|
||||
c_parse_pointer(struct drgn_program *prog, struct drgn_lexer *lexer,
|
||||
struct c_declarator **outer, struct c_declarator **inner)
|
||||
{
|
||||
struct drgn_error *err;
|
||||
@ -2329,7 +2328,7 @@ c_parse_pointer(struct drgn_type_index *tindex, struct drgn_lexer *lexer,
|
||||
}
|
||||
|
||||
static struct drgn_error *
|
||||
c_parse_direct_abstract_declarator(struct drgn_type_index *tindex,
|
||||
c_parse_direct_abstract_declarator(struct drgn_program *prog,
|
||||
struct drgn_lexer *lexer,
|
||||
struct c_declarator **outer,
|
||||
struct c_declarator **inner)
|
||||
@ -2351,7 +2350,7 @@ c_parse_direct_abstract_declarator(struct drgn_type_index *tindex,
|
||||
if (token2.kind == C_TOKEN_ASTERISK ||
|
||||
token2.kind == C_TOKEN_LPAREN ||
|
||||
token2.kind == C_TOKEN_LBRACKET) {
|
||||
err = c_parse_abstract_declarator(tindex, lexer, outer,
|
||||
err = c_parse_abstract_declarator(prog, lexer, outer,
|
||||
inner);
|
||||
if (err)
|
||||
return err;
|
||||
@ -2431,7 +2430,7 @@ c_parse_direct_abstract_declarator(struct drgn_type_index *tindex,
|
||||
}
|
||||
|
||||
static struct drgn_error *
|
||||
c_parse_abstract_declarator(struct drgn_type_index *tindex,
|
||||
c_parse_abstract_declarator(struct drgn_program *prog,
|
||||
struct drgn_lexer *lexer,
|
||||
struct c_declarator **outer,
|
||||
struct c_declarator **inner)
|
||||
@ -2443,7 +2442,7 @@ c_parse_abstract_declarator(struct drgn_type_index *tindex,
|
||||
if (err)
|
||||
return err;
|
||||
if (token.kind == C_TOKEN_ASTERISK) {
|
||||
err = c_parse_pointer(tindex, lexer, outer, inner);
|
||||
err = c_parse_pointer(prog, lexer, outer, inner);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -2452,21 +2451,21 @@ c_parse_abstract_declarator(struct drgn_type_index *tindex,
|
||||
token.kind == C_TOKEN_LBRACKET) {
|
||||
struct c_declarator *tmp;
|
||||
|
||||
err = c_parse_direct_abstract_declarator(tindex, lexer,
|
||||
err = c_parse_direct_abstract_declarator(prog, lexer,
|
||||
outer, &tmp);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
return NULL;
|
||||
} else {
|
||||
return c_parse_direct_abstract_declarator(tindex, lexer, outer,
|
||||
return c_parse_direct_abstract_declarator(prog, lexer, outer,
|
||||
inner);
|
||||
}
|
||||
}
|
||||
|
||||
/* This always frees the declarator list regardless of success or failure. */
|
||||
static struct drgn_error *
|
||||
c_type_from_declarator(struct drgn_type_index *tindex,
|
||||
c_type_from_declarator(struct drgn_program *prog,
|
||||
struct c_declarator *declarator,
|
||||
struct drgn_qualified_type *ret)
|
||||
{
|
||||
@ -2475,21 +2474,20 @@ c_type_from_declarator(struct drgn_type_index *tindex,
|
||||
if (!declarator)
|
||||
return NULL;
|
||||
|
||||
err = c_type_from_declarator(tindex, declarator->next, ret);
|
||||
err = c_type_from_declarator(prog, declarator->next, ret);
|
||||
if (err) {
|
||||
free(declarator);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (declarator->kind == C_TOKEN_ASTERISK) {
|
||||
err = drgn_type_index_pointer_type(tindex, *ret, NULL,
|
||||
&ret->type);
|
||||
err = drgn_program_pointer_type(prog, *ret, NULL, &ret->type);
|
||||
} else if (declarator->is_complete) {
|
||||
err = drgn_type_index_array_type(tindex, declarator->length,
|
||||
*ret, NULL, &ret->type);
|
||||
err = drgn_program_array_type(prog, declarator->length, *ret,
|
||||
NULL, &ret->type);
|
||||
} else {
|
||||
err = drgn_type_index_incomplete_array_type(tindex, *ret, NULL,
|
||||
&ret->type);
|
||||
err = drgn_program_incomplete_array_type(prog, *ret, NULL,
|
||||
&ret->type);
|
||||
}
|
||||
|
||||
if (!err)
|
||||
@ -2498,7 +2496,7 @@ c_type_from_declarator(struct drgn_type_index *tindex,
|
||||
return err;
|
||||
}
|
||||
|
||||
struct drgn_error *c_find_type(struct drgn_type_index *tindex, const char *name,
|
||||
struct drgn_error *c_find_type(struct drgn_program *prog, const char *name,
|
||||
const char *filename,
|
||||
struct drgn_qualified_type *ret)
|
||||
{
|
||||
@ -2508,7 +2506,7 @@ struct drgn_error *c_find_type(struct drgn_type_index *tindex, const char *name,
|
||||
|
||||
drgn_lexer_init(&lexer, drgn_lexer_c, name);
|
||||
|
||||
err = c_parse_specifier_qualifier_list(tindex, &lexer, filename, ret);
|
||||
err = c_parse_specifier_qualifier_list(prog, &lexer, filename, ret);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
@ -2522,8 +2520,7 @@ struct drgn_error *c_find_type(struct drgn_type_index *tindex, const char *name,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = c_parse_abstract_declarator(tindex, &lexer, &outer,
|
||||
&inner);
|
||||
err = c_parse_abstract_declarator(prog, &lexer, &outer, &inner);
|
||||
if (err) {
|
||||
while (outer) {
|
||||
struct c_declarator *next;
|
||||
@ -2535,7 +2532,7 @@ struct drgn_error *c_find_type(struct drgn_type_index *tindex, const char *name,
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = c_type_from_declarator(tindex, outer, ret);
|
||||
err = c_type_from_declarator(prog, outer, ret);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
@ -2580,11 +2577,10 @@ struct drgn_error *c_bit_offset(struct drgn_program *prog,
|
||||
struct drgn_member_value *member;
|
||||
struct drgn_qualified_type member_type;
|
||||
|
||||
err = drgn_type_index_find_member(&prog->tindex,
|
||||
type,
|
||||
token.value,
|
||||
token.len,
|
||||
&member);
|
||||
err = drgn_program_find_member(prog, type,
|
||||
token.value,
|
||||
token.len,
|
||||
&member);
|
||||
if (err)
|
||||
goto out;
|
||||
if (__builtin_add_overflow(bit_offset,
|
||||
@ -2703,9 +2699,8 @@ struct drgn_error *c_integer_literal(struct drgn_object *res, uint64_t uvalue)
|
||||
bits = fls(uvalue);
|
||||
qualified_type.qualifiers = 0;
|
||||
for (i = 0; i < ARRAY_SIZE(types); i++) {
|
||||
err = drgn_type_index_find_primitive(&res->prog->tindex,
|
||||
types[i],
|
||||
&qualified_type.type);
|
||||
err = drgn_program_find_primitive_type(res->prog, types[i],
|
||||
&qualified_type.type);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -2729,9 +2724,8 @@ struct drgn_error *c_bool_literal(struct drgn_object *res, bool bvalue)
|
||||
struct drgn_error *err;
|
||||
struct drgn_qualified_type qualified_type;
|
||||
|
||||
err = drgn_type_index_find_primitive(&res->prog->tindex,
|
||||
DRGN_C_TYPE_INT,
|
||||
&qualified_type.type);
|
||||
err = drgn_program_find_primitive_type(res->prog, DRGN_C_TYPE_INT,
|
||||
&qualified_type.type);
|
||||
if (err)
|
||||
return err;
|
||||
qualified_type.qualifiers = 0;
|
||||
@ -2743,9 +2737,8 @@ struct drgn_error *c_float_literal(struct drgn_object *res, double fvalue)
|
||||
struct drgn_error *err;
|
||||
struct drgn_qualified_type qualified_type;
|
||||
|
||||
err = drgn_type_index_find_primitive(&res->prog->tindex,
|
||||
DRGN_C_TYPE_DOUBLE,
|
||||
&qualified_type.type);
|
||||
err = drgn_program_find_primitive_type(res->prog, DRGN_C_TYPE_DOUBLE,
|
||||
&qualified_type.type);
|
||||
if (err)
|
||||
return err;
|
||||
qualified_type.qualifiers = 0;
|
||||
@ -2800,7 +2793,7 @@ static bool c_can_represent_all_values(struct drgn_type *type1,
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct drgn_error *c_integer_promotions(struct drgn_type_index *tindex,
|
||||
static struct drgn_error *c_integer_promotions(struct drgn_program *prog,
|
||||
struct drgn_object_type *type)
|
||||
{
|
||||
struct drgn_error *err;
|
||||
@ -2850,8 +2843,8 @@ static struct drgn_error *c_integer_promotions(struct drgn_type_index *tindex,
|
||||
*/
|
||||
if (primitive >= ARRAY_SIZE(c_integer_conversion_rank) ||
|
||||
type->bit_field_size) {
|
||||
err = drgn_type_index_find_primitive(tindex, DRGN_C_TYPE_INT,
|
||||
&int_type);
|
||||
err = drgn_program_find_primitive_type(prog, DRGN_C_TYPE_INT,
|
||||
&int_type);
|
||||
if (err)
|
||||
return err;
|
||||
if (c_can_represent_all_values(int_type, 0,
|
||||
@ -2862,9 +2855,9 @@ static struct drgn_error *c_integer_promotions(struct drgn_type_index *tindex,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err = drgn_type_index_find_primitive(tindex,
|
||||
DRGN_C_TYPE_UNSIGNED_INT,
|
||||
&int_type);
|
||||
err = drgn_program_find_primitive_type(prog,
|
||||
DRGN_C_TYPE_UNSIGNED_INT,
|
||||
&int_type);
|
||||
if (err)
|
||||
return err;
|
||||
if (c_can_represent_all_values(int_type, 0,
|
||||
@ -2886,16 +2879,16 @@ static struct drgn_error *c_integer_promotions(struct drgn_type_index *tindex,
|
||||
* If int can represent all values of the original type, then the result
|
||||
* is int. Otherwise, the result is unsigned int.
|
||||
*/
|
||||
err = drgn_type_index_find_primitive(tindex, DRGN_C_TYPE_INT,
|
||||
&int_type);
|
||||
err = drgn_program_find_primitive_type(prog, DRGN_C_TYPE_INT,
|
||||
&int_type);
|
||||
if (err)
|
||||
return err;
|
||||
if (c_can_represent_all_values(int_type, 0, type->underlying_type, 0)) {
|
||||
type->type = int_type;
|
||||
} else {
|
||||
err = drgn_type_index_find_primitive(tindex,
|
||||
DRGN_C_TYPE_UNSIGNED_INT,
|
||||
&type->type);
|
||||
err = drgn_program_find_primitive_type(prog,
|
||||
DRGN_C_TYPE_UNSIGNED_INT,
|
||||
&type->type);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
@ -2904,7 +2897,7 @@ static struct drgn_error *c_integer_promotions(struct drgn_type_index *tindex,
|
||||
}
|
||||
|
||||
static struct drgn_error *
|
||||
c_corresponding_unsigned_type(struct drgn_type_index *tindex,
|
||||
c_corresponding_unsigned_type(struct drgn_program *prog,
|
||||
enum drgn_primitive_type type,
|
||||
struct drgn_type **ret)
|
||||
{
|
||||
@ -2914,23 +2907,23 @@ c_corresponding_unsigned_type(struct drgn_type_index *tindex,
|
||||
* handle them here.
|
||||
*/
|
||||
case DRGN_C_TYPE_INT:
|
||||
return drgn_type_index_find_primitive(tindex,
|
||||
DRGN_C_TYPE_UNSIGNED_INT,
|
||||
ret);
|
||||
return drgn_program_find_primitive_type(prog,
|
||||
DRGN_C_TYPE_UNSIGNED_INT,
|
||||
ret);
|
||||
case DRGN_C_TYPE_LONG:
|
||||
return drgn_type_index_find_primitive(tindex,
|
||||
DRGN_C_TYPE_UNSIGNED_LONG,
|
||||
ret);
|
||||
return drgn_program_find_primitive_type(prog,
|
||||
DRGN_C_TYPE_UNSIGNED_LONG,
|
||||
ret);
|
||||
case DRGN_C_TYPE_LONG_LONG:
|
||||
return drgn_type_index_find_primitive(tindex,
|
||||
DRGN_C_TYPE_UNSIGNED_LONG_LONG,
|
||||
ret);
|
||||
return drgn_program_find_primitive_type(prog,
|
||||
DRGN_C_TYPE_UNSIGNED_LONG_LONG,
|
||||
ret);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
static struct drgn_error *c_common_real_type(struct drgn_type_index *tindex,
|
||||
static struct drgn_error *c_common_real_type(struct drgn_program *prog,
|
||||
struct drgn_object_type *type1,
|
||||
struct drgn_object_type *type2,
|
||||
struct drgn_object_type *ret)
|
||||
@ -2980,10 +2973,10 @@ static struct drgn_error *c_common_real_type(struct drgn_type_index *tindex,
|
||||
* Otherwise, the integer promotions are performed before applying the
|
||||
* following rules.
|
||||
*/
|
||||
err = c_integer_promotions(tindex, type1);
|
||||
err = c_integer_promotions(prog, type1);
|
||||
if (err)
|
||||
return err;
|
||||
err = c_integer_promotions(tindex, type2);
|
||||
err = c_integer_promotions(prog, type2);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -3103,7 +3096,7 @@ static struct drgn_error *c_common_real_type(struct drgn_type_index *tindex,
|
||||
* rank, then it must have greater size and thus be able to represent
|
||||
* all values of the unsigned integer type.
|
||||
*/
|
||||
err = c_corresponding_unsigned_type(tindex,
|
||||
err = c_corresponding_unsigned_type(prog,
|
||||
is_signed1 ? primitive1 : primitive2,
|
||||
&ret->type);
|
||||
if (err)
|
||||
@ -3130,10 +3123,10 @@ static struct drgn_error *c_operand_type(const struct drgn_object *obj,
|
||||
*type_ret = drgn_object_type(obj);
|
||||
switch (drgn_type_kind(type_ret->underlying_type)) {
|
||||
case DRGN_TYPE_ARRAY:
|
||||
err = drgn_type_index_pointer_type(&obj->prog->tindex,
|
||||
drgn_type_type(type_ret->underlying_type),
|
||||
drgn_type_language(type_ret->underlying_type),
|
||||
&type_ret->type);
|
||||
err = drgn_program_pointer_type(obj->prog,
|
||||
drgn_type_type(type_ret->underlying_type),
|
||||
drgn_type_language(type_ret->underlying_type),
|
||||
&type_ret->type);
|
||||
if (err)
|
||||
return err;
|
||||
type_ret->underlying_type = type_ret->type;
|
||||
@ -3144,10 +3137,9 @@ static struct drgn_error *c_operand_type(const struct drgn_object *obj,
|
||||
.qualifiers = type_ret->qualifiers,
|
||||
};
|
||||
|
||||
err = drgn_type_index_pointer_type(&obj->prog->tindex,
|
||||
function_type,
|
||||
drgn_type_language(type_ret->underlying_type),
|
||||
&type_ret->type);
|
||||
err = drgn_program_pointer_type(obj->prog, function_type,
|
||||
drgn_type_language(type_ret->underlying_type),
|
||||
&type_ret->type);
|
||||
if (err)
|
||||
return err;
|
||||
type_ret->underlying_type = type_ret->type;
|
||||
@ -3257,8 +3249,8 @@ struct drgn_error *c_op_cmp(const struct drgn_object *lhs,
|
||||
if (!drgn_type_is_arithmetic(lhs_type.underlying_type) ||
|
||||
!drgn_type_is_arithmetic(rhs_type.underlying_type))
|
||||
goto type_error;
|
||||
err = c_common_real_type(&lhs->prog->tindex, &lhs_type,
|
||||
&rhs_type, &type);
|
||||
err = c_common_real_type(lhs->prog, &lhs_type, &rhs_type,
|
||||
&type);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -3299,8 +3291,8 @@ struct drgn_error *c_op_add(struct drgn_object *res,
|
||||
if (!drgn_type_is_arithmetic(lhs_type.underlying_type) ||
|
||||
!drgn_type_is_arithmetic(rhs_type.underlying_type))
|
||||
goto type_error;
|
||||
err = c_common_real_type(&lhs->prog->tindex, &lhs_type,
|
||||
&rhs_type, &type);
|
||||
err = c_common_real_type(lhs->prog, &lhs_type, &rhs_type,
|
||||
&type);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -3330,9 +3322,9 @@ struct drgn_error *c_op_sub(struct drgn_object *res,
|
||||
if (lhs_pointer && rhs_pointer) {
|
||||
struct drgn_object_type type = {};
|
||||
|
||||
err = drgn_type_index_find_primitive(&lhs->prog->tindex,
|
||||
DRGN_C_TYPE_PTRDIFF_T,
|
||||
&type.type);
|
||||
err = drgn_program_find_primitive_type(lhs->prog,
|
||||
DRGN_C_TYPE_PTRDIFF_T,
|
||||
&type.type);
|
||||
if (err)
|
||||
return err;
|
||||
type.underlying_type = drgn_underlying_type(type.type);
|
||||
@ -3351,8 +3343,8 @@ struct drgn_error *c_op_sub(struct drgn_object *res,
|
||||
if (!drgn_type_is_arithmetic(lhs_type.underlying_type) ||
|
||||
!drgn_type_is_arithmetic(rhs_type.underlying_type))
|
||||
goto type_error;
|
||||
err = c_common_real_type(&lhs->prog->tindex, &lhs_type,
|
||||
&rhs_type, &type);
|
||||
err = c_common_real_type(lhs->prog, &lhs_type, &rhs_type,
|
||||
&type);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -3382,8 +3374,7 @@ struct drgn_error *c_op_##op_name(struct drgn_object *res, \
|
||||
return drgn_error_binary_op("binary "#op, &lhs_type, \
|
||||
&rhs_type); \
|
||||
\
|
||||
err = c_common_real_type(&lhs->prog->tindex, &lhs_type, &rhs_type, \
|
||||
&type); \
|
||||
err = c_common_real_type(lhs->prog, &lhs_type, &rhs_type, &type); \
|
||||
if (err) \
|
||||
return err; \
|
||||
\
|
||||
@ -3416,10 +3407,10 @@ struct drgn_error *c_op_##op_name(struct drgn_object *res, \
|
||||
return drgn_error_binary_op("binary " #op, &lhs_type, \
|
||||
&rhs_type); \
|
||||
\
|
||||
err = c_integer_promotions(&lhs->prog->tindex, &lhs_type); \
|
||||
err = c_integer_promotions(lhs->prog, &lhs_type); \
|
||||
if (err) \
|
||||
return err; \
|
||||
err = c_integer_promotions(&lhs->prog->tindex, &rhs_type); \
|
||||
err = c_integer_promotions(lhs->prog, &rhs_type); \
|
||||
if (err) \
|
||||
return err; \
|
||||
\
|
||||
@ -3442,7 +3433,7 @@ struct drgn_error *c_op_##op_name(struct drgn_object *res, \
|
||||
if (!drgn_type_is_##check(type.underlying_type)) \
|
||||
return drgn_error_unary_op("unary " #op, &type); \
|
||||
\
|
||||
err = c_integer_promotions(&obj->prog->tindex, &type); \
|
||||
err = c_integer_promotions(obj->prog, &type); \
|
||||
if (err) \
|
||||
return err; \
|
||||
\
|
||||
|
@ -286,18 +286,18 @@ struct drgn_error *linux_kernel_object_find(const char *name, size_t name_len,
|
||||
}
|
||||
}
|
||||
|
||||
err = drgn_type_index_find_primitive(&prog->tindex,
|
||||
DRGN_C_TYPE_UNSIGNED_LONG,
|
||||
&qualified_type.type);
|
||||
err = drgn_program_find_primitive_type(prog,
|
||||
DRGN_C_TYPE_UNSIGNED_LONG,
|
||||
&qualified_type.type);
|
||||
if (err)
|
||||
return err;
|
||||
return drgn_object_set_unsigned(ret, qualified_type,
|
||||
prog->page_offset, 0);
|
||||
} else if (name_len == strlen("PAGE_SHIFT") &&
|
||||
memcmp(name, "PAGE_SHIFT", name_len) == 0) {
|
||||
err = drgn_type_index_find_primitive(&prog->tindex,
|
||||
DRGN_C_TYPE_INT,
|
||||
&qualified_type.type);
|
||||
err = drgn_program_find_primitive_type(prog,
|
||||
DRGN_C_TYPE_INT,
|
||||
&qualified_type.type);
|
||||
if (err)
|
||||
return err;
|
||||
return drgn_object_set_signed(ret, qualified_type,
|
||||
@ -305,9 +305,9 @@ struct drgn_error *linux_kernel_object_find(const char *name, size_t name_len,
|
||||
0);
|
||||
} else if (name_len == strlen("PAGE_SIZE") &&
|
||||
memcmp(name, "PAGE_SIZE", name_len) == 0) {
|
||||
err = drgn_type_index_find_primitive(&prog->tindex,
|
||||
DRGN_C_TYPE_UNSIGNED_LONG,
|
||||
&qualified_type.type);
|
||||
err = drgn_program_find_primitive_type(prog,
|
||||
DRGN_C_TYPE_UNSIGNED_LONG,
|
||||
&qualified_type.type);
|
||||
if (err)
|
||||
return err;
|
||||
return drgn_object_set_unsigned(ret, qualified_type,
|
||||
@ -315,9 +315,9 @@ struct drgn_error *linux_kernel_object_find(const char *name, size_t name_len,
|
||||
0);
|
||||
} else if (name_len == strlen("PAGE_MASK") &&
|
||||
memcmp(name, "PAGE_MASK", name_len) == 0) {
|
||||
err = drgn_type_index_find_primitive(&prog->tindex,
|
||||
DRGN_C_TYPE_UNSIGNED_LONG,
|
||||
&qualified_type.type);
|
||||
err = drgn_program_find_primitive_type(prog,
|
||||
DRGN_C_TYPE_UNSIGNED_LONG,
|
||||
&qualified_type.type);
|
||||
if (err)
|
||||
return err;
|
||||
return drgn_object_set_unsigned(ret, qualified_type,
|
||||
@ -330,9 +330,9 @@ struct drgn_error *linux_kernel_object_find(const char *name, size_t name_len,
|
||||
err = linux_kernel_get_thread_size(prog, &thread_size);
|
||||
if (err)
|
||||
return err;
|
||||
err = drgn_type_index_find_primitive(&prog->tindex,
|
||||
DRGN_C_TYPE_UNSIGNED_LONG,
|
||||
&qualified_type.type);
|
||||
err = drgn_program_find_primitive_type(prog,
|
||||
DRGN_C_TYPE_UNSIGNED_LONG,
|
||||
&qualified_type.type);
|
||||
if (err)
|
||||
return err;
|
||||
return drgn_object_set_unsigned(ret, qualified_type,
|
||||
@ -341,16 +341,16 @@ struct drgn_error *linux_kernel_object_find(const char *name, size_t name_len,
|
||||
memcmp(name, "UTS_RELEASE", name_len) == 0) {
|
||||
size_t len;
|
||||
|
||||
err = drgn_type_index_find_primitive(&prog->tindex,
|
||||
DRGN_C_TYPE_CHAR,
|
||||
&qualified_type.type);
|
||||
err = drgn_program_find_primitive_type(prog,
|
||||
DRGN_C_TYPE_CHAR,
|
||||
&qualified_type.type);
|
||||
if (err)
|
||||
return err;
|
||||
qualified_type.qualifiers = DRGN_QUALIFIER_CONST;
|
||||
len = strlen(prog->vmcoreinfo.osrelease);
|
||||
err = drgn_type_index_array_type(&prog->tindex, len + 1,
|
||||
qualified_type, NULL,
|
||||
&qualified_type.type);
|
||||
err = drgn_program_array_type(prog, len + 1,
|
||||
qualified_type, NULL,
|
||||
&qualified_type.type);
|
||||
if (err)
|
||||
return err;
|
||||
qualified_type.qualifiers = 0;
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include "program.h"
|
||||
#include "serialize.h"
|
||||
#include "type.h"
|
||||
#include "type_index.h"
|
||||
|
||||
LIBDRGN_PUBLIC void drgn_object_init(struct drgn_object *obj,
|
||||
struct drgn_program *prog)
|
||||
@ -1291,9 +1290,9 @@ drgn_object_address_of(struct drgn_object *res, const struct drgn_object *obj)
|
||||
"cannot take address of bit field");
|
||||
}
|
||||
|
||||
err = drgn_type_index_pointer_type(&obj->prog->tindex,
|
||||
drgn_object_qualified_type(obj),
|
||||
NULL, &qualified_type.type);
|
||||
err = drgn_program_pointer_type(obj->prog,
|
||||
drgn_object_qualified_type(obj), NULL,
|
||||
&qualified_type.type);
|
||||
if (err)
|
||||
return err;
|
||||
qualified_type.qualifiers = 0;
|
||||
@ -1368,10 +1367,10 @@ struct drgn_error *drgn_object_member_dereference(struct drgn_object *res,
|
||||
obj->type);
|
||||
}
|
||||
|
||||
err = drgn_type_index_find_member(&obj->prog->tindex,
|
||||
drgn_type_type(underlying_type).type,
|
||||
member_name, strlen(member_name),
|
||||
&member);
|
||||
err = drgn_program_find_member(obj->prog,
|
||||
drgn_type_type(underlying_type).type,
|
||||
member_name, strlen(member_name),
|
||||
&member);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -1418,8 +1417,8 @@ drgn_object_container_of(struct drgn_object *res, const struct drgn_object *obj,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = drgn_type_index_pointer_type(&obj->prog->tindex, qualified_type,
|
||||
NULL, &result_type.type);
|
||||
err = drgn_program_pointer_type(obj->prog, qualified_type, NULL,
|
||||
&result_type.type);
|
||||
if (err)
|
||||
return err;
|
||||
result_type.qualifiers = 0;
|
||||
|
@ -41,6 +41,13 @@ drgn_object_index_add_finder(struct drgn_object_index *oindex,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void drgn_object_index_remove_finder(struct drgn_object_index *oindex)
|
||||
{
|
||||
struct drgn_object_finder *finder = oindex->finders->next;
|
||||
free(oindex->finders);
|
||||
oindex->finders = finder;
|
||||
}
|
||||
|
||||
struct drgn_error *drgn_object_index_find(struct drgn_object_index *oindex,
|
||||
const char *name,
|
||||
const char *filename,
|
||||
|
@ -41,7 +41,7 @@ struct drgn_object_finder {
|
||||
* Object index.
|
||||
*
|
||||
* A object index is used to find objects (variables, constants, and functions)
|
||||
* by name. The types are found using callbacks which are registered with @ref
|
||||
* by name. The objects are found using callbacks which are registered with @ref
|
||||
* drgn_object_index_add_finder(). @ref drgn_object_index_find() searches for an
|
||||
* object.
|
||||
*/
|
||||
@ -61,6 +61,9 @@ struct drgn_error *
|
||||
drgn_object_index_add_finder(struct drgn_object_index *oindex,
|
||||
drgn_object_find_fn fn, void *arg);
|
||||
|
||||
/** Remove the most recently added object finding callback. */
|
||||
void drgn_object_index_remove_finder(struct drgn_object_index *oindex);
|
||||
|
||||
/**
|
||||
* Find an object in a @ref drgn_object_index.
|
||||
*
|
||||
|
@ -25,7 +25,6 @@
|
||||
#include "read.h"
|
||||
#include "string_builder.h"
|
||||
#include "symbol.h"
|
||||
#include "type_index.h"
|
||||
#include "vector.h"
|
||||
|
||||
DEFINE_VECTOR_FUNCTIONS(drgn_prstatus_vector)
|
||||
@ -63,8 +62,6 @@ void drgn_program_set_platform(struct drgn_program *prog,
|
||||
if (!prog->has_platform) {
|
||||
prog->platform = *platform;
|
||||
prog->has_platform = true;
|
||||
prog->tindex.word_size =
|
||||
platform->flags & DRGN_PLATFORM_IS_64_BIT ? 8 : 4;
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,7 +70,7 @@ void drgn_program_init(struct drgn_program *prog,
|
||||
{
|
||||
memset(prog, 0, sizeof(*prog));
|
||||
drgn_memory_reader_init(&prog->reader);
|
||||
drgn_type_index_init(&prog->tindex);
|
||||
drgn_program_init_types(prog);
|
||||
drgn_object_index_init(&prog->oindex);
|
||||
prog->core_fd = -1;
|
||||
if (platform)
|
||||
@ -92,7 +89,7 @@ void drgn_program_deinit(struct drgn_program *prog)
|
||||
free(prog->pgtable_it);
|
||||
|
||||
drgn_object_index_deinit(&prog->oindex);
|
||||
drgn_type_index_deinit(&prog->tindex);
|
||||
drgn_program_deinit_types(prog);
|
||||
drgn_memory_reader_deinit(&prog->reader);
|
||||
|
||||
free(prog->file_segments);
|
||||
@ -139,13 +136,6 @@ drgn_program_add_memory_segment(struct drgn_program *prog, uint64_t address,
|
||||
read_fn, arg, physical);
|
||||
}
|
||||
|
||||
LIBDRGN_PUBLIC struct drgn_error *
|
||||
drgn_program_add_type_finder(struct drgn_program *prog, drgn_type_find_fn fn,
|
||||
void *arg)
|
||||
{
|
||||
return drgn_type_index_add_finder(&prog->tindex, fn, arg);
|
||||
}
|
||||
|
||||
LIBDRGN_PUBLIC struct drgn_error *
|
||||
drgn_program_add_object_finder(struct drgn_program *prog,
|
||||
drgn_object_find_fn fn, void *arg)
|
||||
@ -552,21 +542,21 @@ static struct drgn_error *drgn_program_get_dindex(struct drgn_program *prog,
|
||||
else
|
||||
dwfl_callbacks = &drgn_userspace_core_dump_dwfl_callbacks;
|
||||
|
||||
err = drgn_dwarf_info_cache_create(&prog->tindex,
|
||||
dwfl_callbacks, &dicache);
|
||||
err = drgn_dwarf_info_cache_create(prog, dwfl_callbacks,
|
||||
&dicache);
|
||||
if (err)
|
||||
return err;
|
||||
err = drgn_program_add_type_finder(prog, drgn_dwarf_type_find,
|
||||
dicache);
|
||||
if (err) {
|
||||
drgn_dwarf_info_cache_destroy(dicache);
|
||||
return err;
|
||||
}
|
||||
err = drgn_program_add_object_finder(prog,
|
||||
drgn_dwarf_object_find,
|
||||
dicache);
|
||||
if (err) {
|
||||
drgn_type_index_remove_finder(&prog->tindex);
|
||||
drgn_dwarf_info_cache_destroy(dicache);
|
||||
return err;
|
||||
}
|
||||
err = drgn_program_add_type_finder(prog, drgn_dwarf_type_find,
|
||||
dicache);
|
||||
if (err) {
|
||||
drgn_object_index_remove_finder(&prog->oindex);
|
||||
drgn_dwarf_info_cache_destroy(dicache);
|
||||
return err;
|
||||
}
|
||||
@ -1132,14 +1122,6 @@ drgn_program_read_word(struct drgn_program *prog, uint64_t address,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LIBDRGN_PUBLIC struct drgn_error *
|
||||
drgn_program_find_type(struct drgn_program *prog, const char *name,
|
||||
const char *filename, struct drgn_qualified_type *ret)
|
||||
{
|
||||
return drgn_type_index_find(&prog->tindex, name, filename,
|
||||
drgn_program_language(prog), ret);
|
||||
}
|
||||
|
||||
LIBDRGN_PUBLIC struct drgn_error *
|
||||
drgn_program_find_object(struct drgn_program *prog, const char *name,
|
||||
const char *filename,
|
||||
@ -1297,8 +1279,8 @@ drgn_program_member_info(struct drgn_program *prog, struct drgn_type *type,
|
||||
struct drgn_error *err;
|
||||
struct drgn_member_value *member;
|
||||
|
||||
err = drgn_type_index_find_member(&prog->tindex, type, member_name,
|
||||
strlen(member_name), &member);
|
||||
err = drgn_program_find_member(prog, type, member_name,
|
||||
strlen(member_name), &member);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
||||
#include "memory_reader.h"
|
||||
#include "object_index.h"
|
||||
#include "platform.h"
|
||||
#include "type_index.h"
|
||||
#include "type.h"
|
||||
#include "vector.h"
|
||||
|
||||
/**
|
||||
@ -79,10 +79,30 @@ struct drgn_program {
|
||||
kdump_ctx_t *kdump_ctx;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Types.
|
||||
*/
|
||||
/** Callbacks for finding types. */
|
||||
struct drgn_type_finder *type_finders;
|
||||
/** Cache of primitive types. */
|
||||
struct drgn_type *primitive_types[DRGN_PRIMITIVE_TYPE_NUM];
|
||||
struct drgn_type default_size_t;
|
||||
struct drgn_type default_ptrdiff_t;
|
||||
/** Cache of created pointer types. */
|
||||
struct drgn_pointer_type_table pointer_types;
|
||||
/** Cache of created array types. */
|
||||
struct drgn_array_type_table array_types;
|
||||
/** Cache for @ref drgn_program_find_member(). */
|
||||
struct drgn_member_map members;
|
||||
/**
|
||||
* Set of types which have been already cached in @ref
|
||||
* drgn_program::members.
|
||||
*/
|
||||
struct drgn_type_set members_cached;
|
||||
|
||||
/*
|
||||
* Debugging information.
|
||||
*/
|
||||
struct drgn_type_index tindex;
|
||||
struct drgn_object_index oindex;
|
||||
struct drgn_dwarf_info_cache *_dicache;
|
||||
|
||||
|
@ -620,8 +620,8 @@ static PyObject *Program_pointer_type(Program *self, PyObject *args,
|
||||
&referenced_type) == -1)
|
||||
return NULL;
|
||||
|
||||
err = drgn_type_index_pointer_type(&self->prog.tindex, referenced_type,
|
||||
language, &qualified_type.type);
|
||||
err = drgn_program_pointer_type(&self->prog, referenced_type, language,
|
||||
&qualified_type.type);
|
||||
if (err)
|
||||
return set_drgn_error(err);
|
||||
qualified_type.qualifiers = qualifiers;
|
||||
|
585
libdrgn/type.c
585
libdrgn/type.c
@ -6,8 +6,8 @@
|
||||
#include "internal.h"
|
||||
#include "hash_table.h"
|
||||
#include "language.h"
|
||||
#include "program.h"
|
||||
#include "type.h"
|
||||
#include "type_index.h"
|
||||
|
||||
const char * const drgn_type_kind_spelling[] = {
|
||||
[DRGN_TYPE_VOID] = "void",
|
||||
@ -25,7 +25,17 @@ const char * const drgn_type_kind_spelling[] = {
|
||||
[DRGN_TYPE_FUNCTION] = "function",
|
||||
};
|
||||
|
||||
const char * const * const
|
||||
/**
|
||||
* Names of primitive types.
|
||||
*
|
||||
* In some languages, like C, the same primitive type can be spelled in multiple
|
||||
* ways. For example, "int" can also be spelled "signed int" or "int signed".
|
||||
*
|
||||
* This maps each @ref drgn_primitive_type to a ``NULL``-terminated array of the
|
||||
* different ways to spell that type. The spelling at index zero is the
|
||||
* preferred spelling.
|
||||
*/
|
||||
static const char * const * const
|
||||
drgn_primitive_type_spellings[DRGN_PRIMITIVE_TYPE_NUM] = {
|
||||
[DRGN_C_TYPE_VOID] = (const char * []){ "void", NULL, },
|
||||
[DRGN_C_TYPE_CHAR] = (const char * []){ "char", NULL, },
|
||||
@ -93,7 +103,11 @@ drgn_primitive_type_spellings[DRGN_PRIMITIVE_TYPE_NUM] = {
|
||||
[DRGN_C_TYPE_PTRDIFF_T] = (const char * []){ "ptrdiff_t", NULL, },
|
||||
};
|
||||
|
||||
const enum drgn_type_kind
|
||||
/**
|
||||
* Mapping from a @ref drgn_type_primitive to the corresponding @ref
|
||||
* drgn_type_kind.
|
||||
*/
|
||||
static const enum drgn_type_kind
|
||||
drgn_primitive_type_kind[DRGN_PRIMITIVE_TYPE_NUM + 1] = {
|
||||
[DRGN_C_TYPE_CHAR] = DRGN_TYPE_INT,
|
||||
[DRGN_C_TYPE_SIGNED_CHAR] = DRGN_TYPE_INT,
|
||||
@ -133,6 +147,75 @@ drgn_primitive_type_is_signed(enum drgn_primitive_type primitive)
|
||||
}
|
||||
}
|
||||
|
||||
/* These functions compare the underlying type by reference, not by value. */
|
||||
|
||||
static struct hash_pair
|
||||
drgn_pointer_type_key_hash(const struct drgn_pointer_type_key *key)
|
||||
{
|
||||
size_t hash;
|
||||
|
||||
hash = hash_combine((uintptr_t)key->type, key->qualifiers);
|
||||
hash = hash_combine(hash, (uintptr_t)key->lang);
|
||||
return hash_pair_from_avalanching_hash(hash);
|
||||
}
|
||||
|
||||
static bool drgn_pointer_type_key_eq(const struct drgn_pointer_type_key *a,
|
||||
const struct drgn_pointer_type_key *b)
|
||||
{
|
||||
return (a->type == b->type && a->qualifiers == b->qualifiers &&
|
||||
a->lang == b->lang);
|
||||
}
|
||||
|
||||
DEFINE_HASH_TABLE_FUNCTIONS(drgn_pointer_type_table, drgn_pointer_type_key_hash,
|
||||
drgn_pointer_type_key_eq)
|
||||
|
||||
static struct hash_pair
|
||||
drgn_array_type_key_hash(const struct drgn_array_type_key *key)
|
||||
{
|
||||
size_t hash;
|
||||
|
||||
hash = hash_combine((uintptr_t)key->type, key->qualifiers);
|
||||
hash = hash_combine(hash, key->is_complete);
|
||||
hash = hash_combine(hash, key->length);
|
||||
hash = hash_combine(hash, (uintptr_t)key->lang);
|
||||
return hash_pair_from_avalanching_hash(hash);
|
||||
}
|
||||
|
||||
static bool drgn_array_type_key_eq(const struct drgn_array_type_key *a,
|
||||
const struct drgn_array_type_key *b)
|
||||
{
|
||||
return (a->type == b->type && a->qualifiers == b->qualifiers &&
|
||||
a->is_complete == b->is_complete && a->length == b->length &&
|
||||
a->lang == b->lang);
|
||||
}
|
||||
|
||||
DEFINE_HASH_TABLE_FUNCTIONS(drgn_array_type_table, drgn_array_type_key_hash,
|
||||
drgn_array_type_key_eq)
|
||||
|
||||
static struct hash_pair drgn_member_hash_pair(const struct drgn_member_key *key)
|
||||
{
|
||||
size_t hash;
|
||||
if (key->name)
|
||||
hash = cityhash_size_t(key->name, key->name_len);
|
||||
else
|
||||
hash = 0;
|
||||
hash = hash_combine((uintptr_t)key->type, hash);
|
||||
return hash_pair_from_avalanching_hash(hash);
|
||||
}
|
||||
|
||||
static bool drgn_member_eq(const struct drgn_member_key *a,
|
||||
const struct drgn_member_key *b)
|
||||
{
|
||||
return (a->type == b->type && a->name_len == b->name_len &&
|
||||
(!a->name_len || memcmp(a->name, b->name, a->name_len) == 0));
|
||||
}
|
||||
|
||||
DEFINE_HASH_TABLE_FUNCTIONS(drgn_member_map, drgn_member_hash_pair,
|
||||
drgn_member_eq)
|
||||
|
||||
DEFINE_HASH_TABLE_FUNCTIONS(drgn_type_set, hash_pair_ptr_type,
|
||||
hash_table_scalar_eq)
|
||||
|
||||
void drgn_type_thunk_free(struct drgn_type_thunk *thunk)
|
||||
{
|
||||
thunk->free_fn(thunk);
|
||||
@ -948,3 +1031,499 @@ struct drgn_error *drgn_error_member_not_found(struct drgn_type *type,
|
||||
free(name);
|
||||
return err;
|
||||
}
|
||||
|
||||
void drgn_program_init_types(struct drgn_program *prog)
|
||||
{
|
||||
drgn_pointer_type_table_init(&prog->pointer_types);
|
||||
drgn_array_type_table_init(&prog->array_types);
|
||||
drgn_member_map_init(&prog->members);
|
||||
drgn_type_set_init(&prog->members_cached);
|
||||
}
|
||||
|
||||
static void free_pointer_types(struct drgn_program *prog)
|
||||
{
|
||||
struct drgn_pointer_type_table_iterator it;
|
||||
|
||||
for (it = drgn_pointer_type_table_first(&prog->pointer_types);
|
||||
it.entry; it = drgn_pointer_type_table_next(it))
|
||||
free(*it.entry);
|
||||
drgn_pointer_type_table_deinit(&prog->pointer_types);
|
||||
}
|
||||
|
||||
static void free_array_types(struct drgn_program *prog)
|
||||
{
|
||||
struct drgn_array_type_table_iterator it;
|
||||
for (it = drgn_array_type_table_first(&prog->array_types); it.entry;
|
||||
it = drgn_array_type_table_next(it))
|
||||
free(*it.entry);
|
||||
drgn_array_type_table_deinit(&prog->array_types);
|
||||
}
|
||||
|
||||
void drgn_program_deinit_types(struct drgn_program *prog)
|
||||
{
|
||||
drgn_member_map_deinit(&prog->members);
|
||||
drgn_type_set_deinit(&prog->members_cached);
|
||||
free_array_types(prog);
|
||||
free_pointer_types(prog);
|
||||
|
||||
struct drgn_type_finder *finder = prog->type_finders;
|
||||
while (finder) {
|
||||
struct drgn_type_finder *next = finder->next;
|
||||
free(finder);
|
||||
finder = next;
|
||||
}
|
||||
}
|
||||
|
||||
LIBDRGN_PUBLIC struct drgn_error *
|
||||
drgn_program_add_type_finder(struct drgn_program *prog, drgn_type_find_fn fn,
|
||||
void *arg)
|
||||
{
|
||||
struct drgn_type_finder *finder = malloc(sizeof(*finder));
|
||||
if (!finder)
|
||||
return &drgn_enomem;
|
||||
finder->fn = fn;
|
||||
finder->arg = arg;
|
||||
finder->next = prog->type_finders;
|
||||
prog->type_finders = finder;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct drgn_error *
|
||||
drgn_program_find_type_impl(struct drgn_program *prog,
|
||||
enum drgn_type_kind kind, const char *name,
|
||||
size_t name_len, const char *filename,
|
||||
struct drgn_qualified_type *ret)
|
||||
{
|
||||
struct drgn_type_finder *finder = prog->type_finders;
|
||||
while (finder) {
|
||||
struct drgn_error *err =
|
||||
finder->fn(kind, name, name_len, filename, finder->arg,
|
||||
ret);
|
||||
if (!err) {
|
||||
if (drgn_type_kind(ret->type) != kind) {
|
||||
return drgn_error_create(DRGN_ERROR_TYPE,
|
||||
"type find callback returned wrong kind of type");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
if (err != &drgn_not_found)
|
||||
return err;
|
||||
finder = finder->next;
|
||||
}
|
||||
return &drgn_not_found;
|
||||
}
|
||||
|
||||
LIBDRGN_PUBLIC struct drgn_error *
|
||||
drgn_program_find_type(struct drgn_program *prog, const char *name,
|
||||
const char *filename, struct drgn_qualified_type *ret)
|
||||
{
|
||||
struct drgn_error *err;
|
||||
err = drgn_program_language(prog)->find_type(prog, name, filename, ret);
|
||||
if (err != &drgn_not_found)
|
||||
return err;
|
||||
|
||||
if (filename) {
|
||||
return drgn_error_format(DRGN_ERROR_LOOKUP,
|
||||
"could not find '%s' in '%s'", name,
|
||||
filename);
|
||||
} else {
|
||||
return drgn_error_format(DRGN_ERROR_LOOKUP,
|
||||
"could not find '%s'", name);
|
||||
}
|
||||
}
|
||||
|
||||
/* Default long and unsigned long are 64 bits. */
|
||||
static struct drgn_type default_primitive_types[DRGN_PRIMITIVE_TYPE_NUM];
|
||||
/* 32-bit versions of long and unsigned long. */
|
||||
static struct drgn_type default_long_32bit;
|
||||
static struct drgn_type default_unsigned_long_32bit;
|
||||
|
||||
__attribute__((constructor(200)))
|
||||
static void default_primitive_types_init(void)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
drgn_int_type_init(&default_primitive_types[DRGN_C_TYPE_CHAR],
|
||||
drgn_primitive_type_spellings[DRGN_C_TYPE_CHAR][0],
|
||||
1, true, &drgn_language_c);
|
||||
drgn_int_type_init(&default_primitive_types[DRGN_C_TYPE_SIGNED_CHAR],
|
||||
drgn_primitive_type_spellings[DRGN_C_TYPE_SIGNED_CHAR][0],
|
||||
1, true, &drgn_language_c);
|
||||
drgn_int_type_init(&default_primitive_types[DRGN_C_TYPE_UNSIGNED_CHAR],
|
||||
drgn_primitive_type_spellings[DRGN_C_TYPE_UNSIGNED_CHAR][0],
|
||||
1, false, &drgn_language_c);
|
||||
drgn_int_type_init(&default_primitive_types[DRGN_C_TYPE_SHORT],
|
||||
drgn_primitive_type_spellings[DRGN_C_TYPE_SHORT][0],
|
||||
2, true, &drgn_language_c);
|
||||
drgn_int_type_init(&default_primitive_types[DRGN_C_TYPE_UNSIGNED_SHORT],
|
||||
drgn_primitive_type_spellings[DRGN_C_TYPE_UNSIGNED_SHORT][0],
|
||||
2, false, &drgn_language_c);
|
||||
drgn_int_type_init(&default_primitive_types[DRGN_C_TYPE_INT],
|
||||
drgn_primitive_type_spellings[DRGN_C_TYPE_INT][0], 4,
|
||||
true, &drgn_language_c);
|
||||
drgn_int_type_init(&default_primitive_types[DRGN_C_TYPE_UNSIGNED_INT],
|
||||
drgn_primitive_type_spellings[DRGN_C_TYPE_UNSIGNED_INT][0],
|
||||
4, false, &drgn_language_c);
|
||||
drgn_int_type_init(&default_primitive_types[DRGN_C_TYPE_LONG],
|
||||
drgn_primitive_type_spellings[DRGN_C_TYPE_LONG][0],
|
||||
8, true, &drgn_language_c);
|
||||
drgn_int_type_init(&default_primitive_types[DRGN_C_TYPE_UNSIGNED_LONG],
|
||||
drgn_primitive_type_spellings[DRGN_C_TYPE_UNSIGNED_LONG][0],
|
||||
8, false, &drgn_language_c);
|
||||
drgn_int_type_init(&default_primitive_types[DRGN_C_TYPE_LONG_LONG],
|
||||
drgn_primitive_type_spellings[DRGN_C_TYPE_LONG_LONG][0],
|
||||
8, true, &drgn_language_c);
|
||||
drgn_int_type_init(&default_primitive_types[DRGN_C_TYPE_UNSIGNED_LONG_LONG],
|
||||
drgn_primitive_type_spellings[DRGN_C_TYPE_UNSIGNED_LONG_LONG][0],
|
||||
8, false, &drgn_language_c);
|
||||
drgn_bool_type_init(&default_primitive_types[DRGN_C_TYPE_BOOL],
|
||||
drgn_primitive_type_spellings[DRGN_C_TYPE_BOOL][0],
|
||||
1, &drgn_language_c);
|
||||
drgn_float_type_init(&default_primitive_types[DRGN_C_TYPE_FLOAT],
|
||||
drgn_primitive_type_spellings[DRGN_C_TYPE_FLOAT][0],
|
||||
4, &drgn_language_c);
|
||||
drgn_float_type_init(&default_primitive_types[DRGN_C_TYPE_DOUBLE],
|
||||
drgn_primitive_type_spellings[DRGN_C_TYPE_DOUBLE][0],
|
||||
8, &drgn_language_c);
|
||||
drgn_float_type_init(&default_primitive_types[DRGN_C_TYPE_LONG_DOUBLE],
|
||||
drgn_primitive_type_spellings[DRGN_C_TYPE_LONG_DOUBLE][0],
|
||||
16, &drgn_language_c);
|
||||
for (i = 0; i < ARRAY_SIZE(default_primitive_types); i++) {
|
||||
if (drgn_primitive_type_kind[i] == DRGN_TYPE_VOID ||
|
||||
i == DRGN_C_TYPE_SIZE_T || i == DRGN_C_TYPE_PTRDIFF_T)
|
||||
continue;
|
||||
assert(drgn_type_primitive(&default_primitive_types[i]) == i);
|
||||
}
|
||||
|
||||
drgn_int_type_init(&default_long_32bit,
|
||||
drgn_primitive_type_spellings[DRGN_C_TYPE_LONG][0],
|
||||
4, true, &drgn_language_c);
|
||||
assert(drgn_type_primitive(&default_long_32bit) ==
|
||||
DRGN_C_TYPE_LONG);
|
||||
|
||||
drgn_int_type_init(&default_unsigned_long_32bit,
|
||||
drgn_primitive_type_spellings[DRGN_C_TYPE_UNSIGNED_LONG][0],
|
||||
4, false, &drgn_language_c);
|
||||
assert(drgn_type_primitive(&default_unsigned_long_32bit) ==
|
||||
DRGN_C_TYPE_UNSIGNED_LONG);
|
||||
}
|
||||
|
||||
struct drgn_error *
|
||||
drgn_program_find_primitive_type(struct drgn_program *prog,
|
||||
enum drgn_primitive_type type,
|
||||
struct drgn_type **ret)
|
||||
{
|
||||
struct drgn_error *err;
|
||||
struct drgn_qualified_type qualified_type;
|
||||
enum drgn_type_kind kind;
|
||||
const char * const *spellings;
|
||||
uint8_t word_size;
|
||||
size_t i;
|
||||
|
||||
if (prog->primitive_types[type]) {
|
||||
*ret = prog->primitive_types[type];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
kind = drgn_primitive_type_kind[type];
|
||||
if (kind == DRGN_TYPE_VOID) {
|
||||
*ret = drgn_void_type(&drgn_language_c);
|
||||
goto out;
|
||||
}
|
||||
|
||||
spellings = drgn_primitive_type_spellings[type];
|
||||
for (i = 0; spellings[i]; i++) {
|
||||
err = drgn_program_find_type_impl(prog, kind, spellings[i],
|
||||
strlen(spellings[i]), NULL,
|
||||
&qualified_type);
|
||||
if (!err && drgn_type_primitive(qualified_type.type) == type) {
|
||||
*ret = qualified_type.type;
|
||||
goto out;
|
||||
} else if (err && err != &drgn_not_found) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
if (!prog->has_platform) {
|
||||
return drgn_error_create(DRGN_ERROR_INVALID_ARGUMENT,
|
||||
"program word size is not known");
|
||||
}
|
||||
word_size = drgn_program_is_64_bit(prog) ? 8 : 4;
|
||||
|
||||
/* long and unsigned long default to the word size. */
|
||||
if (type == DRGN_C_TYPE_LONG || type == DRGN_C_TYPE_UNSIGNED_LONG) {
|
||||
if (word_size == 4) {
|
||||
*ret = (type == DRGN_C_TYPE_LONG ?
|
||||
&default_long_32bit :
|
||||
&default_unsigned_long_32bit);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* size_t and ptrdiff_t default to typedefs of whatever integer type
|
||||
* matches the word size.
|
||||
*/
|
||||
if (type == DRGN_C_TYPE_SIZE_T || type == DRGN_C_TYPE_PTRDIFF_T) {
|
||||
static enum drgn_primitive_type integer_types[2][3] = {
|
||||
{
|
||||
DRGN_C_TYPE_UNSIGNED_LONG,
|
||||
DRGN_C_TYPE_UNSIGNED_LONG_LONG,
|
||||
DRGN_C_TYPE_UNSIGNED_INT,
|
||||
},
|
||||
{
|
||||
DRGN_C_TYPE_LONG,
|
||||
DRGN_C_TYPE_LONG_LONG,
|
||||
DRGN_C_TYPE_INT,
|
||||
},
|
||||
};
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
enum drgn_primitive_type integer_type;
|
||||
|
||||
integer_type = integer_types[type == DRGN_C_TYPE_PTRDIFF_T][i];
|
||||
err = drgn_program_find_primitive_type(prog,
|
||||
integer_type,
|
||||
&qualified_type.type);
|
||||
if (err)
|
||||
return err;
|
||||
if (drgn_type_size(qualified_type.type) == word_size) {
|
||||
qualified_type.qualifiers = 0;
|
||||
*ret = (type == DRGN_C_TYPE_SIZE_T ?
|
||||
&prog->default_size_t :
|
||||
&prog->default_ptrdiff_t);
|
||||
drgn_typedef_type_init(*ret, spellings[0],
|
||||
qualified_type, &drgn_language_c);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
return drgn_error_format(DRGN_ERROR_INVALID_ARGUMENT,
|
||||
"no suitable integer type for %s",
|
||||
spellings[0]);
|
||||
}
|
||||
|
||||
*ret = &default_primitive_types[type];
|
||||
out:
|
||||
prog->primitive_types[type] = *ret;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct drgn_error *
|
||||
drgn_program_pointer_type(struct drgn_program *prog,
|
||||
struct drgn_qualified_type referenced_type,
|
||||
const struct drgn_language *lang,
|
||||
struct drgn_type **ret)
|
||||
{
|
||||
const struct drgn_pointer_type_key key = {
|
||||
.type = referenced_type.type,
|
||||
.qualifiers = referenced_type.qualifiers,
|
||||
.lang = lang ? lang : drgn_type_language(referenced_type.type),
|
||||
};
|
||||
struct drgn_pointer_type_table_iterator it;
|
||||
struct drgn_type *type;
|
||||
struct hash_pair hp;
|
||||
|
||||
if (!prog->has_platform) {
|
||||
return drgn_error_create(DRGN_ERROR_INVALID_ARGUMENT,
|
||||
"program word size is not known");
|
||||
}
|
||||
|
||||
hp = drgn_pointer_type_table_hash(&key);
|
||||
it = drgn_pointer_type_table_search_hashed(&prog->pointer_types, &key,
|
||||
hp);
|
||||
if (it.entry) {
|
||||
type = *it.entry;
|
||||
goto out;
|
||||
}
|
||||
|
||||
type = malloc(sizeof(*type));
|
||||
if (!type)
|
||||
return &drgn_enomem;
|
||||
drgn_pointer_type_init(type, drgn_program_is_64_bit(prog) ? 8 : 4,
|
||||
referenced_type, key.lang);
|
||||
if (drgn_pointer_type_table_insert_searched(&prog->pointer_types, &type,
|
||||
hp, NULL) == -1) {
|
||||
free(type);
|
||||
return &drgn_enomem;
|
||||
}
|
||||
out:
|
||||
*ret = type;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct drgn_error *
|
||||
drgn_program_array_type(struct drgn_program *prog, uint64_t length,
|
||||
struct drgn_qualified_type element_type,
|
||||
const struct drgn_language *lang,
|
||||
struct drgn_type **ret)
|
||||
{
|
||||
const struct drgn_array_type_key key = {
|
||||
.type = element_type.type,
|
||||
.qualifiers = element_type.qualifiers,
|
||||
.is_complete = true,
|
||||
.length = length,
|
||||
.lang = lang ? lang : drgn_type_language(element_type.type),
|
||||
};
|
||||
struct drgn_array_type_table_iterator it;
|
||||
struct drgn_type *type;
|
||||
struct hash_pair hp;
|
||||
|
||||
hp = drgn_array_type_table_hash(&key);
|
||||
it = drgn_array_type_table_search_hashed(&prog->array_types, &key, hp);
|
||||
if (it.entry) {
|
||||
type = *it.entry;
|
||||
goto out;
|
||||
}
|
||||
|
||||
type = malloc(sizeof(*type));
|
||||
if (!type)
|
||||
return &drgn_enomem;
|
||||
drgn_array_type_init(type, length, element_type, key.lang);
|
||||
if (drgn_array_type_table_insert_searched(&prog->array_types, &type, hp,
|
||||
NULL) == -1) {
|
||||
free(type);
|
||||
return &drgn_enomem;
|
||||
}
|
||||
out:
|
||||
*ret = type;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct drgn_error *
|
||||
drgn_program_incomplete_array_type(struct drgn_program *prog,
|
||||
struct drgn_qualified_type element_type,
|
||||
const struct drgn_language *lang,
|
||||
struct drgn_type **ret)
|
||||
{
|
||||
const struct drgn_array_type_key key = {
|
||||
.type = element_type.type,
|
||||
.qualifiers = element_type.qualifiers,
|
||||
.is_complete = false,
|
||||
.lang = lang ? lang : drgn_type_language(element_type.type),
|
||||
};
|
||||
struct drgn_array_type_table_iterator it;
|
||||
struct drgn_type *type;
|
||||
struct hash_pair hp;
|
||||
|
||||
hp = drgn_array_type_table_hash(&key);
|
||||
it = drgn_array_type_table_search_hashed(&prog->array_types, &key, hp);
|
||||
if (it.entry) {
|
||||
type = *it.entry;
|
||||
goto out;
|
||||
}
|
||||
|
||||
type = malloc(sizeof(*type));
|
||||
if (!type)
|
||||
return &drgn_enomem;
|
||||
drgn_array_type_init_incomplete(type, element_type, key.lang);
|
||||
if (drgn_array_type_table_insert_searched(&prog->array_types, &type, hp,
|
||||
NULL) == -1) {
|
||||
free(type);
|
||||
return &drgn_enomem;
|
||||
}
|
||||
out:
|
||||
*ret = type;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct drgn_error *
|
||||
drgn_program_cache_members(struct drgn_program *prog,
|
||||
struct drgn_type *outer_type,
|
||||
struct drgn_type *type, uint64_t bit_offset)
|
||||
{
|
||||
if (!drgn_type_has_members(type))
|
||||
return NULL;
|
||||
|
||||
struct drgn_type_member *members = drgn_type_members(type);
|
||||
size_t num_members = drgn_type_num_members(type);
|
||||
for (size_t i = 0; i < num_members; i++) {
|
||||
struct drgn_type_member *member = &members[i];
|
||||
if (member->name) {
|
||||
struct drgn_member_map_entry entry = {
|
||||
.key = {
|
||||
.type = outer_type,
|
||||
.name = member->name,
|
||||
.name_len = strlen(member->name),
|
||||
},
|
||||
.value = {
|
||||
.type = &member->type,
|
||||
.bit_offset =
|
||||
bit_offset + member->bit_offset,
|
||||
.bit_field_size =
|
||||
member->bit_field_size,
|
||||
},
|
||||
};
|
||||
if (drgn_member_map_insert(&prog->members, &entry,
|
||||
NULL) == -1)
|
||||
return &drgn_enomem;
|
||||
} else {
|
||||
struct drgn_qualified_type member_type;
|
||||
struct drgn_error *err = drgn_member_type(member,
|
||||
&member_type);
|
||||
if (err)
|
||||
return err;
|
||||
err = drgn_program_cache_members(prog, outer_type,
|
||||
member_type.type,
|
||||
bit_offset +
|
||||
member->bit_offset);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct drgn_error *drgn_program_find_member(struct drgn_program *prog,
|
||||
struct drgn_type *type,
|
||||
const char *member_name,
|
||||
size_t member_name_len,
|
||||
struct drgn_member_value **ret)
|
||||
{
|
||||
const struct drgn_member_key key = {
|
||||
.type = drgn_underlying_type(type),
|
||||
.name = member_name,
|
||||
.name_len = member_name_len,
|
||||
};
|
||||
struct hash_pair hp = drgn_member_map_hash(&key);
|
||||
struct drgn_member_map_iterator it =
|
||||
drgn_member_map_search_hashed(&prog->members, &key, hp);
|
||||
if (it.entry) {
|
||||
*ret = &it.entry->value;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cache miss. One of the following is true:
|
||||
*
|
||||
* 1. The type isn't a structure, union, or class, which is a type
|
||||
* error.
|
||||
* 2. The type hasn't been cached, which means we need to cache it and
|
||||
* check again.
|
||||
* 3. The type has already been cached, which means the member doesn't
|
||||
* exist.
|
||||
*/
|
||||
if (!drgn_type_has_members(key.type)) {
|
||||
return drgn_type_error("'%s' is not a structure, union, or class",
|
||||
type);
|
||||
}
|
||||
struct hash_pair cached_hp = drgn_type_set_hash(&key.type);
|
||||
if (drgn_type_set_search_hashed(&prog->members_cached, &key.type,
|
||||
cached_hp).entry)
|
||||
return drgn_error_member_not_found(type, member_name);
|
||||
|
||||
struct drgn_error *err = drgn_program_cache_members(prog, key.type,
|
||||
key.type, 0);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (drgn_type_set_insert_searched(&prog->members_cached, &key.type,
|
||||
cached_hp, NULL) == -1)
|
||||
return &drgn_enomem;
|
||||
|
||||
it = drgn_member_map_search_hashed(&prog->members, &key, hp);
|
||||
if (it.entry) {
|
||||
*ret = &it.entry->value;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return drgn_error_member_not_found(type, member_name);
|
||||
}
|
||||
|
223
libdrgn/type.h
223
libdrgn/type.h
@ -13,6 +13,7 @@
|
||||
#define DRGN_TYPE_H
|
||||
|
||||
#include "drgn.h"
|
||||
#include "hash_table.h"
|
||||
#include "language.h"
|
||||
|
||||
/**
|
||||
@ -29,6 +30,92 @@
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Registered type finding callback in a @ref drgn_program. */
|
||||
struct drgn_type_finder {
|
||||
/** The callback. */
|
||||
drgn_type_find_fn fn;
|
||||
/** Argument to pass to @ref drgn_type_finder::fn. */
|
||||
void *arg;
|
||||
/** Next callback to try. */
|
||||
struct drgn_type_finder *next;
|
||||
};
|
||||
|
||||
struct drgn_pointer_type_key {
|
||||
struct drgn_type *type;
|
||||
enum drgn_qualifiers qualifiers;
|
||||
const struct drgn_language *lang;
|
||||
};
|
||||
|
||||
static struct drgn_pointer_type_key
|
||||
drgn_pointer_type_entry_to_key(struct drgn_type * const *entry)
|
||||
{
|
||||
struct drgn_qualified_type referenced_type = drgn_type_type(*entry);
|
||||
|
||||
return (struct drgn_pointer_type_key){
|
||||
.type = referenced_type.type,
|
||||
.qualifiers = referenced_type.qualifiers,
|
||||
.lang = drgn_type_language(*entry),
|
||||
};
|
||||
}
|
||||
|
||||
struct drgn_array_type_key {
|
||||
struct drgn_type *type;
|
||||
enum drgn_qualifiers qualifiers;
|
||||
bool is_complete;
|
||||
uint64_t length;
|
||||
const struct drgn_language *lang;
|
||||
};
|
||||
|
||||
static struct drgn_array_type_key
|
||||
drgn_array_type_entry_to_key(struct drgn_type * const *entry)
|
||||
{
|
||||
struct drgn_qualified_type element_type = drgn_type_type(*entry);
|
||||
|
||||
return (struct drgn_array_type_key){
|
||||
.type = element_type.type,
|
||||
.qualifiers = element_type.qualifiers,
|
||||
.is_complete = drgn_type_is_complete(*entry),
|
||||
.length = drgn_type_length(*entry),
|
||||
.lang = drgn_type_language(*entry),
|
||||
};
|
||||
}
|
||||
|
||||
DEFINE_HASH_TABLE_TYPE(drgn_pointer_type_table, struct drgn_type *,
|
||||
drgn_pointer_type_entry_to_key)
|
||||
DEFINE_HASH_TABLE_TYPE(drgn_array_type_table, struct drgn_type *,
|
||||
drgn_array_type_entry_to_key)
|
||||
|
||||
/** <tt>(type, member name)</tt> pair. */
|
||||
struct drgn_member_key {
|
||||
struct drgn_type *type;
|
||||
const char *name;
|
||||
size_t name_len;
|
||||
};
|
||||
|
||||
/** Type, offset, and bit field size of a type member. */
|
||||
struct drgn_member_value {
|
||||
struct drgn_lazy_type *type;
|
||||
uint64_t bit_offset, bit_field_size;
|
||||
};
|
||||
|
||||
#ifdef DOXYGEN
|
||||
/**
|
||||
* @struct drgn_member_map
|
||||
*
|
||||
* Map of compound type members.
|
||||
*
|
||||
* The key is a @ref drgn_member_key, and the value is a @ref drgn_member_value.
|
||||
*
|
||||
* @struct drgn_type_set
|
||||
*
|
||||
* Set of types compared by address.
|
||||
*/
|
||||
#else
|
||||
DEFINE_HASH_MAP_TYPE(drgn_member_map, struct drgn_member_key,
|
||||
struct drgn_member_value)
|
||||
DEFINE_HASH_SET_TYPE(drgn_type_set, struct drgn_type *)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @defgroup LazyTypes Lazy types
|
||||
*
|
||||
@ -482,26 +569,6 @@ void drgn_function_type_init(struct drgn_type *type,
|
||||
/** Mapping from @ref drgn_type_kind to the spelling of that kind. */
|
||||
extern const char * const drgn_type_kind_spelling[];
|
||||
|
||||
/**
|
||||
* Names of primitive types.
|
||||
*
|
||||
* In some languages, like C, the same primitive type can be spelled in multiple
|
||||
* ways. For example, "int" can also be spelled "signed int" or "int signed".
|
||||
*
|
||||
* This maps each @ref drgn_primitive_type to a ``NULL``-terminated array of the
|
||||
* different ways to spell that type. The spelling at index zero is the
|
||||
* preferred spelling.
|
||||
*/
|
||||
extern const char * const * const
|
||||
drgn_primitive_type_spellings[DRGN_PRIMITIVE_TYPE_NUM];
|
||||
|
||||
/**
|
||||
* Mapping from a @ref drgn_type_primitive to the corresponding @ref
|
||||
* drgn_type_kind.
|
||||
*/
|
||||
extern const enum drgn_type_kind
|
||||
drgn_primitive_type_kind[DRGN_PRIMITIVE_TYPE_NUM + 1];
|
||||
|
||||
/**
|
||||
* Parse the name of an unqualified primitive C type.
|
||||
*
|
||||
@ -594,6 +661,122 @@ struct drgn_error *drgn_type_bit_size(struct drgn_type *type,
|
||||
/** Get the appropriate @ref drgn_object_kind for a @ref drgn_type. */
|
||||
enum drgn_object_kind drgn_type_object_kind(struct drgn_type *type);
|
||||
|
||||
/** Initialize type-related fields in a @ref drgn_program. */
|
||||
void drgn_program_init_types(struct drgn_program *prog);
|
||||
/** Deinitialize type-related fields in a @ref drgn_program. */
|
||||
void drgn_program_deinit_types(struct drgn_program *prog);
|
||||
|
||||
/**
|
||||
* Find a parsed type in a @ref drgn_program.
|
||||
*
|
||||
* This should only be called by implementations of @ref
|
||||
* drgn_language::find_type()
|
||||
*
|
||||
* @param[in] kind Kind of type to find. Must be @ref DRGN_TYPE_STRUCT, @ref
|
||||
* DRGN_TYPE_UNION, @ref DRGN_TYPE_CLASS, @ref DRGN_TYPE_ENUM, or @ref
|
||||
* DRGN_TYPE_TYPEDEF.
|
||||
* @param[in] name Name of the type.
|
||||
* @param[in] name_len Length of @p name in bytes.
|
||||
* @param[in] filename See @ref drgn_program_find_type().
|
||||
* @param[out] ret Returned type.
|
||||
* @return @c NULL on success, &@ref drgn_not_found if the type wasn't found,
|
||||
* non-@c NULL on other error.
|
||||
*/
|
||||
struct drgn_error *
|
||||
drgn_program_find_type_impl(struct drgn_program *prog,
|
||||
enum drgn_type_kind kind, const char *name,
|
||||
size_t name_len, const char *filename,
|
||||
struct drgn_qualified_type *ret);
|
||||
|
||||
/** Find a primitive type in a @ref drgn_program. */
|
||||
struct drgn_error *
|
||||
drgn_program_find_primitive_type(struct drgn_program *prog,
|
||||
enum drgn_primitive_type type,
|
||||
struct drgn_type **ret);
|
||||
|
||||
/**
|
||||
* Create a pointer type.
|
||||
*
|
||||
* The created type is cached for the lifetime of the @ref drgn_program. If the
|
||||
* same @p referenced_type and @p lang are passed, the same type will be
|
||||
* returned.
|
||||
*
|
||||
* If this succeeds, @p referenced_type must remain valid until @p prog is
|
||||
* destroyed.
|
||||
*
|
||||
* @param[in] referenced_type Type referenced by the pointer type.
|
||||
* @param[in] lang Language of the pointer type. If @c NULL, the language of @p
|
||||
* referenced_type is used.
|
||||
* @param[out] ret Returned type.
|
||||
* @return @c NULL on success, non-@c NULL on error.
|
||||
*/
|
||||
struct drgn_error *
|
||||
drgn_program_pointer_type(struct drgn_program *prog,
|
||||
struct drgn_qualified_type referenced_type,
|
||||
const struct drgn_language *lang,
|
||||
struct drgn_type **ret);
|
||||
|
||||
/**
|
||||
* Create an array type.
|
||||
*
|
||||
* The created type is cached for the lifetime of the @ref drgn_program. If the
|
||||
* same @p length, @p element_type, and @p lang are passed, the same type will
|
||||
* be returned.
|
||||
*
|
||||
* @param[in] length Number of elements in the array type.
|
||||
* @param[in] element_type Type of an element in the array type.
|
||||
* @param[in] lang Language of the array type. If @c NULL, the language of @p
|
||||
* element_type is used.
|
||||
* @param[out] ret Returned type.
|
||||
* @return @c NULL on success, non-@c NULL on error.
|
||||
*/
|
||||
struct drgn_error *
|
||||
drgn_program_array_type(struct drgn_program *prog, uint64_t length,
|
||||
struct drgn_qualified_type element_type,
|
||||
const struct drgn_language *lang,
|
||||
struct drgn_type **ret);
|
||||
|
||||
/**
|
||||
* Create an incomplete array type.
|
||||
*
|
||||
* The created type is cached for the lifetime of the @ref drgn_program. If the
|
||||
* same @p element_type and @p lang are passed, the same type will be returned.
|
||||
*
|
||||
* If this succeeds, @p element_type must remain valid until @p prog is
|
||||
* destroyed.
|
||||
*
|
||||
* @param[in] element_type Type of an element in the array type.
|
||||
* @param[in] lang Language of the array type. If @c NULL, the language of @p
|
||||
* element_type is used.
|
||||
* @param[out] ret Returned type.
|
||||
* @return @c NULL on success, non-@c NULL on error.
|
||||
*/
|
||||
struct drgn_error *
|
||||
drgn_program_incomplete_array_type(struct drgn_program *prog,
|
||||
struct drgn_qualified_type element_type,
|
||||
const struct drgn_language *lang,
|
||||
struct drgn_type **ret);
|
||||
|
||||
/**
|
||||
* Find the type, offset, and bit field size of a type member.
|
||||
*
|
||||
* This matches the members of the type itself as well as the members of any
|
||||
* unnamed members of the type.
|
||||
*
|
||||
* This caches all members of @p type for subsequent calls.
|
||||
*
|
||||
* @param[in] type Compound type to search in.
|
||||
* @param[in] member_name Name of member.
|
||||
* @param[in] member_name_len Length of @p member_name
|
||||
* @param[out] ret Returned member information.
|
||||
* @return @c NULL on success, non-@c NULL on error.
|
||||
*/
|
||||
struct drgn_error *drgn_program_find_member(struct drgn_program *prog,
|
||||
struct drgn_type *type,
|
||||
const char *member_name,
|
||||
size_t member_name_len,
|
||||
struct drgn_member_value **ret);
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif /* DRGN_TYPE_H */
|
||||
|
@ -1,622 +0,0 @@
|
||||
// Copyright (c) Facebook, Inc. and its affiliates.
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "internal.h"
|
||||
#include "language.h"
|
||||
#include "type_index.h"
|
||||
|
||||
/* These functions compare the underlying type by reference, not by value. */
|
||||
|
||||
static struct hash_pair
|
||||
drgn_pointer_type_key_hash(const struct drgn_pointer_type_key *key)
|
||||
{
|
||||
size_t hash;
|
||||
|
||||
hash = hash_combine((uintptr_t)key->type, key->qualifiers);
|
||||
hash = hash_combine(hash, (uintptr_t)key->lang);
|
||||
return hash_pair_from_avalanching_hash(hash);
|
||||
}
|
||||
|
||||
static bool drgn_pointer_type_key_eq(const struct drgn_pointer_type_key *a,
|
||||
const struct drgn_pointer_type_key *b)
|
||||
{
|
||||
return (a->type == b->type && a->qualifiers == b->qualifiers &&
|
||||
a->lang == b->lang);
|
||||
}
|
||||
|
||||
DEFINE_HASH_TABLE_FUNCTIONS(drgn_pointer_type_table, drgn_pointer_type_key_hash,
|
||||
drgn_pointer_type_key_eq)
|
||||
|
||||
static struct hash_pair
|
||||
drgn_array_type_key_hash(const struct drgn_array_type_key *key)
|
||||
{
|
||||
size_t hash;
|
||||
|
||||
hash = hash_combine((uintptr_t)key->type, key->qualifiers);
|
||||
hash = hash_combine(hash, key->is_complete);
|
||||
hash = hash_combine(hash, key->length);
|
||||
hash = hash_combine(hash, (uintptr_t)key->lang);
|
||||
return hash_pair_from_avalanching_hash(hash);
|
||||
}
|
||||
|
||||
static bool drgn_array_type_key_eq(const struct drgn_array_type_key *a,
|
||||
const struct drgn_array_type_key *b)
|
||||
{
|
||||
return (a->type == b->type && a->qualifiers == b->qualifiers &&
|
||||
a->is_complete == b->is_complete && a->length == b->length &&
|
||||
a->lang == b->lang);
|
||||
}
|
||||
|
||||
DEFINE_HASH_TABLE_FUNCTIONS(drgn_array_type_table, drgn_array_type_key_hash,
|
||||
drgn_array_type_key_eq)
|
||||
|
||||
static struct hash_pair drgn_member_hash_pair(const struct drgn_member_key *key)
|
||||
{
|
||||
size_t hash;
|
||||
|
||||
if (key->name)
|
||||
hash = cityhash_size_t(key->name, key->name_len);
|
||||
else
|
||||
hash = 0;
|
||||
hash = hash_combine((uintptr_t)key->type, hash);
|
||||
return hash_pair_from_avalanching_hash(hash);
|
||||
}
|
||||
|
||||
static bool drgn_member_eq(const struct drgn_member_key *a,
|
||||
const struct drgn_member_key *b)
|
||||
{
|
||||
return (a->type == b->type && a->name_len == b->name_len &&
|
||||
(!a->name_len || memcmp(a->name, b->name, a->name_len) == 0));
|
||||
}
|
||||
|
||||
DEFINE_HASH_TABLE_FUNCTIONS(drgn_member_map, drgn_member_hash_pair,
|
||||
drgn_member_eq)
|
||||
|
||||
DEFINE_HASH_TABLE_FUNCTIONS(drgn_type_set, hash_pair_ptr_type,
|
||||
hash_table_scalar_eq)
|
||||
|
||||
void drgn_type_index_init(struct drgn_type_index *tindex)
|
||||
{
|
||||
tindex->finders = NULL;
|
||||
memset(tindex->primitive_types, 0, sizeof(tindex->primitive_types));
|
||||
drgn_pointer_type_table_init(&tindex->pointer_types);
|
||||
drgn_array_type_table_init(&tindex->array_types);
|
||||
drgn_member_map_init(&tindex->members);
|
||||
drgn_type_set_init(&tindex->members_cached);
|
||||
tindex->word_size = 0;
|
||||
}
|
||||
|
||||
static void free_pointer_types(struct drgn_type_index *tindex)
|
||||
{
|
||||
struct drgn_pointer_type_table_iterator it;
|
||||
|
||||
for (it = drgn_pointer_type_table_first(&tindex->pointer_types);
|
||||
it.entry; it = drgn_pointer_type_table_next(it))
|
||||
free(*it.entry);
|
||||
drgn_pointer_type_table_deinit(&tindex->pointer_types);
|
||||
}
|
||||
|
||||
static void free_array_types(struct drgn_type_index *tindex)
|
||||
{
|
||||
struct drgn_array_type_table_iterator it;
|
||||
|
||||
for (it = drgn_array_type_table_first(&tindex->array_types); it.entry;
|
||||
it = drgn_array_type_table_next(it))
|
||||
free(*it.entry);
|
||||
drgn_array_type_table_deinit(&tindex->array_types);
|
||||
}
|
||||
|
||||
void drgn_type_index_deinit(struct drgn_type_index *tindex)
|
||||
{
|
||||
struct drgn_type_finder *finder;
|
||||
|
||||
drgn_member_map_deinit(&tindex->members);
|
||||
drgn_type_set_deinit(&tindex->members_cached);
|
||||
free_array_types(tindex);
|
||||
free_pointer_types(tindex);
|
||||
|
||||
finder = tindex->finders;
|
||||
while (finder) {
|
||||
struct drgn_type_finder *next = finder->next;
|
||||
|
||||
free(finder);
|
||||
finder = next;
|
||||
}
|
||||
}
|
||||
|
||||
struct drgn_error *drgn_type_index_add_finder(struct drgn_type_index *tindex,
|
||||
drgn_type_find_fn fn, void *arg)
|
||||
{
|
||||
struct drgn_type_finder *finder;
|
||||
|
||||
finder = malloc(sizeof(*finder));
|
||||
if (!finder)
|
||||
return &drgn_enomem;
|
||||
finder->fn = fn;
|
||||
finder->arg = arg;
|
||||
finder->next = tindex->finders;
|
||||
tindex->finders = finder;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void drgn_type_index_remove_finder(struct drgn_type_index *tindex)
|
||||
{
|
||||
struct drgn_type_finder *finder;
|
||||
|
||||
finder = tindex->finders->next;
|
||||
free(tindex->finders);
|
||||
tindex->finders = finder;
|
||||
}
|
||||
|
||||
/* Default long and unsigned long are 64 bits. */
|
||||
static struct drgn_type default_primitive_types[DRGN_PRIMITIVE_TYPE_NUM];
|
||||
/* 32-bit versions of long and unsigned long. */
|
||||
static struct drgn_type default_long_32bit;
|
||||
static struct drgn_type default_unsigned_long_32bit;
|
||||
|
||||
__attribute__((constructor(200)))
|
||||
static void default_primitive_types_init(void)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
drgn_int_type_init(&default_primitive_types[DRGN_C_TYPE_CHAR],
|
||||
drgn_primitive_type_spellings[DRGN_C_TYPE_CHAR][0],
|
||||
1, true, &drgn_language_c);
|
||||
drgn_int_type_init(&default_primitive_types[DRGN_C_TYPE_SIGNED_CHAR],
|
||||
drgn_primitive_type_spellings[DRGN_C_TYPE_SIGNED_CHAR][0],
|
||||
1, true, &drgn_language_c);
|
||||
drgn_int_type_init(&default_primitive_types[DRGN_C_TYPE_UNSIGNED_CHAR],
|
||||
drgn_primitive_type_spellings[DRGN_C_TYPE_UNSIGNED_CHAR][0],
|
||||
1, false, &drgn_language_c);
|
||||
drgn_int_type_init(&default_primitive_types[DRGN_C_TYPE_SHORT],
|
||||
drgn_primitive_type_spellings[DRGN_C_TYPE_SHORT][0],
|
||||
2, true, &drgn_language_c);
|
||||
drgn_int_type_init(&default_primitive_types[DRGN_C_TYPE_UNSIGNED_SHORT],
|
||||
drgn_primitive_type_spellings[DRGN_C_TYPE_UNSIGNED_SHORT][0],
|
||||
2, false, &drgn_language_c);
|
||||
drgn_int_type_init(&default_primitive_types[DRGN_C_TYPE_INT],
|
||||
drgn_primitive_type_spellings[DRGN_C_TYPE_INT][0], 4,
|
||||
true, &drgn_language_c);
|
||||
drgn_int_type_init(&default_primitive_types[DRGN_C_TYPE_UNSIGNED_INT],
|
||||
drgn_primitive_type_spellings[DRGN_C_TYPE_UNSIGNED_INT][0],
|
||||
4, false, &drgn_language_c);
|
||||
drgn_int_type_init(&default_primitive_types[DRGN_C_TYPE_LONG],
|
||||
drgn_primitive_type_spellings[DRGN_C_TYPE_LONG][0],
|
||||
8, true, &drgn_language_c);
|
||||
drgn_int_type_init(&default_primitive_types[DRGN_C_TYPE_UNSIGNED_LONG],
|
||||
drgn_primitive_type_spellings[DRGN_C_TYPE_UNSIGNED_LONG][0],
|
||||
8, false, &drgn_language_c);
|
||||
drgn_int_type_init(&default_primitive_types[DRGN_C_TYPE_LONG_LONG],
|
||||
drgn_primitive_type_spellings[DRGN_C_TYPE_LONG_LONG][0],
|
||||
8, true, &drgn_language_c);
|
||||
drgn_int_type_init(&default_primitive_types[DRGN_C_TYPE_UNSIGNED_LONG_LONG],
|
||||
drgn_primitive_type_spellings[DRGN_C_TYPE_UNSIGNED_LONG_LONG][0],
|
||||
8, false, &drgn_language_c);
|
||||
drgn_bool_type_init(&default_primitive_types[DRGN_C_TYPE_BOOL],
|
||||
drgn_primitive_type_spellings[DRGN_C_TYPE_BOOL][0],
|
||||
1, &drgn_language_c);
|
||||
drgn_float_type_init(&default_primitive_types[DRGN_C_TYPE_FLOAT],
|
||||
drgn_primitive_type_spellings[DRGN_C_TYPE_FLOAT][0],
|
||||
4, &drgn_language_c);
|
||||
drgn_float_type_init(&default_primitive_types[DRGN_C_TYPE_DOUBLE],
|
||||
drgn_primitive_type_spellings[DRGN_C_TYPE_DOUBLE][0],
|
||||
8, &drgn_language_c);
|
||||
drgn_float_type_init(&default_primitive_types[DRGN_C_TYPE_LONG_DOUBLE],
|
||||
drgn_primitive_type_spellings[DRGN_C_TYPE_LONG_DOUBLE][0],
|
||||
16, &drgn_language_c);
|
||||
for (i = 0; i < ARRAY_SIZE(default_primitive_types); i++) {
|
||||
if (drgn_primitive_type_kind[i] == DRGN_TYPE_VOID ||
|
||||
i == DRGN_C_TYPE_SIZE_T || i == DRGN_C_TYPE_PTRDIFF_T)
|
||||
continue;
|
||||
assert(drgn_type_primitive(&default_primitive_types[i]) == i);
|
||||
}
|
||||
|
||||
drgn_int_type_init(&default_long_32bit,
|
||||
drgn_primitive_type_spellings[DRGN_C_TYPE_LONG][0],
|
||||
4, true, &drgn_language_c);
|
||||
assert(drgn_type_primitive(&default_long_32bit) ==
|
||||
DRGN_C_TYPE_LONG);
|
||||
|
||||
drgn_int_type_init(&default_unsigned_long_32bit,
|
||||
drgn_primitive_type_spellings[DRGN_C_TYPE_UNSIGNED_LONG][0],
|
||||
4, false, &drgn_language_c);
|
||||
assert(drgn_type_primitive(&default_unsigned_long_32bit) ==
|
||||
DRGN_C_TYPE_UNSIGNED_LONG);
|
||||
}
|
||||
|
||||
/*
|
||||
* Like @ref drgn_type_index_find_parsed(), but returns
|
||||
* <tt>&drgn_error_not_found</tt> instead of a more informative error message.
|
||||
*/
|
||||
static struct drgn_error *
|
||||
drgn_type_index_find_parsed_internal(struct drgn_type_index *tindex,
|
||||
enum drgn_type_kind kind, const char *name,
|
||||
size_t name_len, const char *filename,
|
||||
struct drgn_qualified_type *ret)
|
||||
{
|
||||
struct drgn_error *err;
|
||||
struct drgn_type_finder *finder;
|
||||
|
||||
finder = tindex->finders;
|
||||
while (finder) {
|
||||
err = finder->fn(kind, name, name_len, filename, finder->arg,
|
||||
ret);
|
||||
if (!err) {
|
||||
if (drgn_type_kind(ret->type) != kind) {
|
||||
return drgn_error_create(DRGN_ERROR_TYPE,
|
||||
"type find callback returned wrong kind of type");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
if (err != &drgn_not_found)
|
||||
return err;
|
||||
finder = finder->next;
|
||||
}
|
||||
return &drgn_not_found;
|
||||
}
|
||||
|
||||
struct drgn_error *
|
||||
drgn_type_index_find_primitive(struct drgn_type_index *tindex,
|
||||
enum drgn_primitive_type type,
|
||||
struct drgn_type **ret)
|
||||
{
|
||||
struct drgn_error *err;
|
||||
struct drgn_qualified_type qualified_type;
|
||||
enum drgn_type_kind kind;
|
||||
const char * const *spellings;
|
||||
size_t i;
|
||||
|
||||
if (tindex->primitive_types[type]) {
|
||||
*ret = tindex->primitive_types[type];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
kind = drgn_primitive_type_kind[type];
|
||||
if (kind == DRGN_TYPE_VOID) {
|
||||
*ret = drgn_void_type(&drgn_language_c);
|
||||
goto out;
|
||||
}
|
||||
|
||||
spellings = drgn_primitive_type_spellings[type];
|
||||
for (i = 0; spellings[i]; i++) {
|
||||
err = drgn_type_index_find_parsed_internal(tindex, kind,
|
||||
spellings[i],
|
||||
strlen(spellings[i]),
|
||||
NULL,
|
||||
&qualified_type);
|
||||
if (!err && drgn_type_primitive(qualified_type.type) == type) {
|
||||
*ret = qualified_type.type;
|
||||
goto out;
|
||||
} else if (err && err != &drgn_not_found) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
/* long and unsigned long default to the word size. */
|
||||
if (type == DRGN_C_TYPE_LONG || type == DRGN_C_TYPE_UNSIGNED_LONG) {
|
||||
if (!tindex->word_size) {
|
||||
return drgn_error_create(DRGN_ERROR_INVALID_ARGUMENT,
|
||||
"word size has not been set");
|
||||
}
|
||||
if (tindex->word_size == 4) {
|
||||
*ret = (type == DRGN_C_TYPE_LONG ?
|
||||
&default_long_32bit :
|
||||
&default_unsigned_long_32bit);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* size_t and ptrdiff_t default to typedefs of whatever integer type
|
||||
* matches the word size.
|
||||
*/
|
||||
if (type == DRGN_C_TYPE_SIZE_T || type == DRGN_C_TYPE_PTRDIFF_T) {
|
||||
static enum drgn_primitive_type integer_types[2][3] = {
|
||||
{
|
||||
DRGN_C_TYPE_UNSIGNED_LONG,
|
||||
DRGN_C_TYPE_UNSIGNED_LONG_LONG,
|
||||
DRGN_C_TYPE_UNSIGNED_INT,
|
||||
},
|
||||
{
|
||||
DRGN_C_TYPE_LONG,
|
||||
DRGN_C_TYPE_LONG_LONG,
|
||||
DRGN_C_TYPE_INT,
|
||||
},
|
||||
};
|
||||
|
||||
if (!tindex->word_size) {
|
||||
return drgn_error_create(DRGN_ERROR_INVALID_ARGUMENT,
|
||||
"word size has not been set");
|
||||
}
|
||||
for (i = 0; i < 3; i++) {
|
||||
enum drgn_primitive_type integer_type;
|
||||
|
||||
integer_type = integer_types[type == DRGN_C_TYPE_PTRDIFF_T][i];
|
||||
err = drgn_type_index_find_primitive(tindex,
|
||||
integer_type,
|
||||
&qualified_type.type);
|
||||
if (err)
|
||||
return err;
|
||||
if (drgn_type_size(qualified_type.type) ==
|
||||
tindex->word_size) {
|
||||
qualified_type.qualifiers = 0;
|
||||
*ret = (type == DRGN_C_TYPE_SIZE_T ?
|
||||
&tindex->default_size_t :
|
||||
&tindex->default_ptrdiff_t);
|
||||
drgn_typedef_type_init(*ret, spellings[0],
|
||||
qualified_type, &drgn_language_c);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
return drgn_error_format(DRGN_ERROR_INVALID_ARGUMENT,
|
||||
"no suitable integer type for %s",
|
||||
spellings[0]);
|
||||
}
|
||||
|
||||
*ret = &default_primitive_types[type];
|
||||
|
||||
out:
|
||||
tindex->primitive_types[type] = *ret;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct drgn_error *
|
||||
drgn_type_index_find_parsed(struct drgn_type_index *tindex,
|
||||
enum drgn_type_kind kind, const char *name,
|
||||
size_t name_len, const char *filename,
|
||||
struct drgn_qualified_type *ret)
|
||||
{
|
||||
struct drgn_error *err;
|
||||
int precision;
|
||||
|
||||
err = drgn_type_index_find_parsed_internal(tindex, kind, name, name_len,
|
||||
filename, ret);
|
||||
if (err != &drgn_not_found)
|
||||
return err;
|
||||
|
||||
precision = name_len < INT_MAX ? (int)name_len : INT_MAX;
|
||||
if (filename) {
|
||||
return drgn_error_format(DRGN_ERROR_LOOKUP,
|
||||
"could not find '%s %.*s' in '%s'",
|
||||
drgn_type_kind_spelling[kind], precision, name,
|
||||
filename);
|
||||
} else {
|
||||
return drgn_error_format(DRGN_ERROR_LOOKUP,
|
||||
"could not find '%s %.*s'",
|
||||
drgn_type_kind_spelling[kind], precision, name);
|
||||
}
|
||||
}
|
||||
|
||||
struct drgn_error *
|
||||
drgn_type_index_pointer_type(struct drgn_type_index *tindex,
|
||||
struct drgn_qualified_type referenced_type,
|
||||
const struct drgn_language *lang,
|
||||
struct drgn_type **ret)
|
||||
{
|
||||
const struct drgn_pointer_type_key key = {
|
||||
.type = referenced_type.type,
|
||||
.qualifiers = referenced_type.qualifiers,
|
||||
.lang = lang ? lang : drgn_type_language(referenced_type.type),
|
||||
};
|
||||
struct drgn_pointer_type_table_iterator it;
|
||||
struct drgn_type *type;
|
||||
struct hash_pair hp;
|
||||
|
||||
if (!tindex->word_size) {
|
||||
return drgn_error_create(DRGN_ERROR_INVALID_ARGUMENT,
|
||||
"word size has not been set");
|
||||
}
|
||||
|
||||
hp = drgn_pointer_type_table_hash(&key);
|
||||
it = drgn_pointer_type_table_search_hashed(&tindex->pointer_types, &key,
|
||||
hp);
|
||||
if (it.entry) {
|
||||
type = *it.entry;
|
||||
goto out;
|
||||
}
|
||||
|
||||
type = malloc(sizeof(*type));
|
||||
if (!type)
|
||||
return &drgn_enomem;
|
||||
drgn_pointer_type_init(type, tindex->word_size, referenced_type,
|
||||
key.lang);
|
||||
if (drgn_pointer_type_table_insert_searched(&tindex->pointer_types,
|
||||
&type, hp, NULL) == -1) {
|
||||
free(type);
|
||||
return &drgn_enomem;
|
||||
}
|
||||
out:
|
||||
*ret = type;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct drgn_error *
|
||||
drgn_type_index_array_type(struct drgn_type_index *tindex, uint64_t length,
|
||||
struct drgn_qualified_type element_type,
|
||||
const struct drgn_language *lang,
|
||||
struct drgn_type **ret)
|
||||
{
|
||||
const struct drgn_array_type_key key = {
|
||||
.type = element_type.type,
|
||||
.qualifiers = element_type.qualifiers,
|
||||
.is_complete = true,
|
||||
.length = length,
|
||||
.lang = lang ? lang : drgn_type_language(element_type.type),
|
||||
};
|
||||
struct drgn_array_type_table_iterator it;
|
||||
struct drgn_type *type;
|
||||
struct hash_pair hp;
|
||||
|
||||
hp = drgn_array_type_table_hash(&key);
|
||||
it = drgn_array_type_table_search_hashed(&tindex->array_types, &key,
|
||||
hp);
|
||||
if (it.entry) {
|
||||
type = *it.entry;
|
||||
goto out;
|
||||
}
|
||||
|
||||
type = malloc(sizeof(*type));
|
||||
if (!type)
|
||||
return &drgn_enomem;
|
||||
drgn_array_type_init(type, length, element_type, key.lang);
|
||||
if (drgn_array_type_table_insert_searched(&tindex->array_types, &type,
|
||||
hp, NULL) == -1) {
|
||||
free(type);
|
||||
return &drgn_enomem;
|
||||
}
|
||||
out:
|
||||
*ret = type;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct drgn_error *
|
||||
drgn_type_index_incomplete_array_type(struct drgn_type_index *tindex,
|
||||
struct drgn_qualified_type element_type,
|
||||
const struct drgn_language *lang,
|
||||
struct drgn_type **ret)
|
||||
{
|
||||
const struct drgn_array_type_key key = {
|
||||
.type = element_type.type,
|
||||
.qualifiers = element_type.qualifiers,
|
||||
.is_complete = false,
|
||||
.lang = lang ? lang : drgn_type_language(element_type.type),
|
||||
};
|
||||
struct drgn_array_type_table_iterator it;
|
||||
struct drgn_type *type;
|
||||
struct hash_pair hp;
|
||||
|
||||
hp = drgn_array_type_table_hash(&key);
|
||||
it = drgn_array_type_table_search_hashed(&tindex->array_types, &key,
|
||||
hp);
|
||||
if (it.entry) {
|
||||
type = *it.entry;
|
||||
goto out;
|
||||
}
|
||||
|
||||
type = malloc(sizeof(*type));
|
||||
if (!type)
|
||||
return &drgn_enomem;
|
||||
drgn_array_type_init_incomplete(type, element_type, key.lang);
|
||||
if (drgn_array_type_table_insert_searched(&tindex->array_types, &type,
|
||||
hp, NULL) == -1) {
|
||||
free(type);
|
||||
return &drgn_enomem;
|
||||
}
|
||||
out:
|
||||
*ret = type;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct drgn_error *
|
||||
drgn_type_index_cache_members(struct drgn_type_index *tindex,
|
||||
struct drgn_type *outer_type,
|
||||
struct drgn_type *type, uint64_t bit_offset)
|
||||
{
|
||||
struct drgn_error *err;
|
||||
struct drgn_type_member *members;
|
||||
size_t num_members, i;
|
||||
|
||||
if (!drgn_type_has_members(type))
|
||||
return NULL;
|
||||
|
||||
members = drgn_type_members(type);
|
||||
num_members = drgn_type_num_members(type);
|
||||
for (i = 0; i < num_members; i++) {
|
||||
struct drgn_type_member *member;
|
||||
|
||||
member = &members[i];
|
||||
if (member->name) {
|
||||
struct drgn_member_map_entry entry = {
|
||||
.key = {
|
||||
.type = outer_type,
|
||||
.name = member->name,
|
||||
.name_len = strlen(member->name),
|
||||
},
|
||||
.value = {
|
||||
.type = &member->type,
|
||||
.bit_offset =
|
||||
bit_offset + member->bit_offset,
|
||||
.bit_field_size =
|
||||
member->bit_field_size,
|
||||
},
|
||||
};
|
||||
|
||||
if (drgn_member_map_insert(&tindex->members, &entry,
|
||||
NULL) == -1)
|
||||
return &drgn_enomem;
|
||||
} else {
|
||||
struct drgn_qualified_type member_type;
|
||||
|
||||
err = drgn_member_type(member, &member_type);
|
||||
if (err)
|
||||
return err;
|
||||
err = drgn_type_index_cache_members(tindex, outer_type,
|
||||
member_type.type,
|
||||
bit_offset +
|
||||
member->bit_offset);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct drgn_error *drgn_type_index_find_member(struct drgn_type_index *tindex,
|
||||
struct drgn_type *type,
|
||||
const char *member_name,
|
||||
size_t member_name_len,
|
||||
struct drgn_member_value **ret)
|
||||
{
|
||||
struct drgn_error *err;
|
||||
const struct drgn_member_key key = {
|
||||
.type = drgn_underlying_type(type),
|
||||
.name = member_name,
|
||||
.name_len = member_name_len,
|
||||
};
|
||||
struct hash_pair hp, cached_hp;
|
||||
struct drgn_member_map_iterator it;
|
||||
|
||||
hp = drgn_member_map_hash(&key);
|
||||
it = drgn_member_map_search_hashed(&tindex->members, &key, hp);
|
||||
if (it.entry) {
|
||||
*ret = &it.entry->value;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cache miss. One of the following is true:
|
||||
*
|
||||
* 1. The type isn't a structure, union, or class, which is a type
|
||||
* error.
|
||||
* 2. The type hasn't been cached, which means we need to cache it and
|
||||
* check again.
|
||||
* 3. The type has already been cached, which means the member doesn't
|
||||
* exist.
|
||||
*/
|
||||
if (!drgn_type_has_members(key.type)) {
|
||||
return drgn_type_error("'%s' is not a structure, union, or class",
|
||||
type);
|
||||
}
|
||||
cached_hp = drgn_type_set_hash(&key.type);
|
||||
if (drgn_type_set_search_hashed(&tindex->members_cached, &key.type,
|
||||
cached_hp).entry)
|
||||
return drgn_error_member_not_found(type, member_name);
|
||||
|
||||
err = drgn_type_index_cache_members(tindex, key.type, key.type, 0);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (drgn_type_set_insert_searched(&tindex->members_cached, &key.type,
|
||||
cached_hp, NULL) == -1)
|
||||
return &drgn_enomem;
|
||||
|
||||
it = drgn_member_map_search_hashed(&tindex->members, &key, hp);
|
||||
if (it.entry) {
|
||||
*ret = &it.entry->value;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return drgn_error_member_not_found(type, member_name);
|
||||
}
|
@ -1,323 +0,0 @@
|
||||
// Copyright (c) Facebook, Inc. and its affiliates.
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* Type lookup and caching.
|
||||
*
|
||||
* See @ref TypeIndex.
|
||||
*/
|
||||
|
||||
#ifndef DRGN_TYPE_INDEX_H
|
||||
#define DRGN_TYPE_INDEX_H
|
||||
|
||||
#include <elfutils/libdw.h>
|
||||
|
||||
#include "drgn.h"
|
||||
#include "hash_table.h"
|
||||
#include "language.h"
|
||||
#include "type.h"
|
||||
|
||||
/**
|
||||
* @ingroup Internals
|
||||
*
|
||||
* @defgroup TypeIndex Type index
|
||||
*
|
||||
* Type lookup and caching.
|
||||
*
|
||||
* @ref drgn_type_index provides a common interface for finding types in a
|
||||
* program.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
struct drgn_pointer_type_key {
|
||||
struct drgn_type *type;
|
||||
enum drgn_qualifiers qualifiers;
|
||||
const struct drgn_language *lang;
|
||||
};
|
||||
|
||||
static struct drgn_pointer_type_key
|
||||
drgn_pointer_type_entry_to_key(struct drgn_type * const *entry)
|
||||
{
|
||||
struct drgn_qualified_type referenced_type = drgn_type_type(*entry);
|
||||
|
||||
return (struct drgn_pointer_type_key){
|
||||
.type = referenced_type.type,
|
||||
.qualifiers = referenced_type.qualifiers,
|
||||
.lang = drgn_type_language(*entry),
|
||||
};
|
||||
}
|
||||
|
||||
struct drgn_array_type_key {
|
||||
struct drgn_type *type;
|
||||
enum drgn_qualifiers qualifiers;
|
||||
bool is_complete;
|
||||
uint64_t length;
|
||||
const struct drgn_language *lang;
|
||||
};
|
||||
|
||||
static struct drgn_array_type_key
|
||||
drgn_array_type_entry_to_key(struct drgn_type * const *entry)
|
||||
{
|
||||
struct drgn_qualified_type element_type = drgn_type_type(*entry);
|
||||
|
||||
return (struct drgn_array_type_key){
|
||||
.type = element_type.type,
|
||||
.qualifiers = element_type.qualifiers,
|
||||
.is_complete = drgn_type_is_complete(*entry),
|
||||
.length = drgn_type_length(*entry),
|
||||
.lang = drgn_type_language(*entry),
|
||||
};
|
||||
}
|
||||
|
||||
DEFINE_HASH_TABLE_TYPE(drgn_pointer_type_table, struct drgn_type *,
|
||||
drgn_pointer_type_entry_to_key)
|
||||
DEFINE_HASH_TABLE_TYPE(drgn_array_type_table, struct drgn_type *,
|
||||
drgn_array_type_entry_to_key)
|
||||
|
||||
/** <tt>(type, member name)</tt> pair. */
|
||||
struct drgn_member_key {
|
||||
struct drgn_type *type;
|
||||
const char *name;
|
||||
size_t name_len;
|
||||
};
|
||||
|
||||
/** Type, offset, and bit field size of a type member. */
|
||||
struct drgn_member_value {
|
||||
struct drgn_lazy_type *type;
|
||||
uint64_t bit_offset, bit_field_size;
|
||||
};
|
||||
|
||||
#ifdef DOXYGEN
|
||||
/**
|
||||
* @struct drgn_member_map
|
||||
*
|
||||
* Map of compound type members.
|
||||
*
|
||||
* The key is a @ref drgn_member_key, and the value is a @ref drgn_member_value.
|
||||
*
|
||||
* @struct drgn_type_set
|
||||
*
|
||||
* Set of types compared by address.
|
||||
*/
|
||||
#else
|
||||
DEFINE_HASH_MAP_TYPE(drgn_member_map, struct drgn_member_key,
|
||||
struct drgn_member_value)
|
||||
DEFINE_HASH_SET_TYPE(drgn_type_set, struct drgn_type *)
|
||||
#endif
|
||||
|
||||
/** Registered callback in a @ref drgn_type_index. */
|
||||
struct drgn_type_finder {
|
||||
/** The callback. */
|
||||
drgn_type_find_fn fn;
|
||||
/** Argument to pass to @ref drgn_type_finder::fn. */
|
||||
void *arg;
|
||||
/** Next callback to try. */
|
||||
struct drgn_type_finder *next;
|
||||
};
|
||||
|
||||
/**
|
||||
* Type index.
|
||||
*
|
||||
* A type index is used to find types by name and cache the results. The types
|
||||
* are found using callbacks which are registered with @ref
|
||||
* drgn_type_index_add_finder().
|
||||
*
|
||||
* @ref drgn_type_index_find() searches for a type. @ref
|
||||
* drgn_type_index_pointer_type(), @ref drgn_type_index_array_type(), and @ref
|
||||
* drgn_type_index_incomplete_array_type() create derived types. Any type
|
||||
* returned by these is valid until the type index is destroyed with @ref
|
||||
* drgn_type_index_destroy().
|
||||
*/
|
||||
struct drgn_type_index {
|
||||
/** Callbacks for finding types. */
|
||||
struct drgn_type_finder *finders;
|
||||
/** Cache of primitive types. */
|
||||
struct drgn_type *primitive_types[DRGN_PRIMITIVE_TYPE_NUM];
|
||||
struct drgn_type default_size_t;
|
||||
struct drgn_type default_ptrdiff_t;
|
||||
/** Cache of created pointer types. */
|
||||
struct drgn_pointer_type_table pointer_types;
|
||||
/** Cache of created array types. */
|
||||
struct drgn_array_type_table array_types;
|
||||
/** Cache for @ref drgn_type_index_find_member(). */
|
||||
struct drgn_member_map members;
|
||||
/**
|
||||
* Set of types which have been already cached in @ref
|
||||
* drgn_type_index::members.
|
||||
*/
|
||||
struct drgn_type_set members_cached;
|
||||
/**
|
||||
* Size of a pointer in bytes.
|
||||
*
|
||||
* This is zero if it has not been set yet.
|
||||
*/
|
||||
uint8_t word_size;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize a @ref drgn_type_index.
|
||||
*
|
||||
* @param[in] tindex Type index to initialize.
|
||||
*/
|
||||
void drgn_type_index_init(struct drgn_type_index *tindex);
|
||||
|
||||
/** Deinitialize a @ref drgn_type_index. */
|
||||
void drgn_type_index_deinit(struct drgn_type_index *tindex);
|
||||
|
||||
/** @sa drgn_program_add_type_finder() */
|
||||
struct drgn_error *drgn_type_index_add_finder(struct drgn_type_index *tindex,
|
||||
drgn_type_find_fn fn, void *arg);
|
||||
|
||||
/**
|
||||
* Remove the most recently added type finding callback.
|
||||
*
|
||||
* This must only be called if the type index hasn't been used since the finder
|
||||
* was added.
|
||||
*/
|
||||
void drgn_type_index_remove_finder(struct drgn_type_index *tindex);
|
||||
|
||||
/** Find a primitive type in a @ref drgn_type_index. */
|
||||
struct drgn_error *
|
||||
drgn_type_index_find_primitive(struct drgn_type_index *tindex,
|
||||
enum drgn_primitive_type type,
|
||||
struct drgn_type **ret);
|
||||
|
||||
/**
|
||||
* Find a parsed type in a @ref drgn_type_index.
|
||||
*
|
||||
* This should only be called by implementations of @ref
|
||||
* drgn_language::find_type().
|
||||
*
|
||||
* @param[in] kind Kind of type to find. Must be @ref DRGN_TYPE_STRUCT, @ref
|
||||
* DRGN_TYPE_UNION, @ref DRGN_TYPE_CLASS, @ref DRGN_TYPE_ENUM, or @ref
|
||||
* DRGN_TYPE_TYPEDEF.
|
||||
* @param[in] name Name of the type.
|
||||
* @param[in] name_len Length of @p name in bytes.
|
||||
* @param[in] filename See @ref drgn_type_index_find().
|
||||
* @param[out] ret Returned type.
|
||||
* @return @c NULL on success, non-@c NULL on error.
|
||||
*/
|
||||
struct drgn_error *
|
||||
drgn_type_index_find_parsed(struct drgn_type_index *tindex,
|
||||
enum drgn_type_kind kind, const char *name,
|
||||
size_t name_len, const char *filename,
|
||||
struct drgn_qualified_type *ret);
|
||||
|
||||
/**
|
||||
* Find a type in a @ref drgn_type_index.
|
||||
*
|
||||
* The returned type is valid for the lifetime of the @ref drgn_type_index.
|
||||
*
|
||||
* @param[in] tindex Type index.
|
||||
* @param[in] name Name of the type.
|
||||
* @param[in] filename Exact filename containing the type definition, or @c NULL
|
||||
* for any definition.
|
||||
* @param[in] lang Language to use to parse @p name.
|
||||
* @param[out] ret Returned type.
|
||||
* @return @c NULL on success, non-@c NULL on error.
|
||||
*/
|
||||
static inline struct drgn_error *
|
||||
drgn_type_index_find(struct drgn_type_index *tindex, const char *name,
|
||||
const char *filename, const struct drgn_language *lang,
|
||||
struct drgn_qualified_type *ret)
|
||||
{
|
||||
return lang->find_type(tindex, name, filename, ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a pointer type.
|
||||
*
|
||||
* The created type is cached for the lifetime of the @ref drgn_type_index. If
|
||||
* the same @p referenced_type and @p lang are passed, the same type will be
|
||||
* returned.
|
||||
*
|
||||
* If this succeeds, @p referenced_type must remain valid until @p tindex is
|
||||
* destroyed.
|
||||
*
|
||||
* @param[in] tindex Type index.
|
||||
* @param[in] referenced_type Type referenced by the pointer type.
|
||||
* @param[in] lang Language of the pointer type. If @c NULL, the language of @p
|
||||
* referenced_type is used.
|
||||
* @param[out] ret Returned type.
|
||||
* @return @c NULL on success, non-@c NULL on error.
|
||||
*/
|
||||
struct drgn_error *
|
||||
drgn_type_index_pointer_type(struct drgn_type_index *tindex,
|
||||
struct drgn_qualified_type referenced_type,
|
||||
const struct drgn_language *lang,
|
||||
struct drgn_type **ret);
|
||||
|
||||
/**
|
||||
* Create an array type.
|
||||
*
|
||||
* The created type is cached for the lifetime of the @ref drgn_type_index. If
|
||||
* the same @p length, @p element_type, and @p lang are passed, the same type
|
||||
* will be returned.
|
||||
*
|
||||
* If this succeeds, @p element_type must remain valid until @p tindex is
|
||||
* destroyed.
|
||||
*
|
||||
* @param[in] tindex Type index.
|
||||
* @param[in] length Number of elements in the array type.
|
||||
* @param[in] element_type Type of an element in the array type.
|
||||
* @param[in] lang Language of the array type. If @c NULL, the language of @p
|
||||
* element_type is used.
|
||||
* @param[out] ret Returned type.
|
||||
* @return @c NULL on success, non-@c NULL on error.
|
||||
*/
|
||||
struct drgn_error *
|
||||
drgn_type_index_array_type(struct drgn_type_index *tindex, uint64_t length,
|
||||
struct drgn_qualified_type element_type,
|
||||
const struct drgn_language *lang,
|
||||
struct drgn_type **ret);
|
||||
|
||||
/**
|
||||
* Create an incomplete array type.
|
||||
*
|
||||
* The created type is cached for the lifetime of the @ref drgn_type_index. If
|
||||
* the same @p element_type and @p lang are passed, the same type will be
|
||||
* returned.
|
||||
*
|
||||
* If this succeeds, @p element_type must remain valid until @p tindex is
|
||||
* destroyed.
|
||||
*
|
||||
* @param[in] tindex Type index.
|
||||
* @param[in] element_type Type of an element in the array type.
|
||||
* @param[in] lang Language of the array type. If @c NULL, the language of @p
|
||||
* element_type is used.
|
||||
* @param[out] ret Returned type.
|
||||
* @return @c NULL on success, non-@c NULL on error.
|
||||
*/
|
||||
struct drgn_error *
|
||||
drgn_type_index_incomplete_array_type(struct drgn_type_index *tindex,
|
||||
struct drgn_qualified_type element_type,
|
||||
const struct drgn_language *lang,
|
||||
struct drgn_type **ret);
|
||||
|
||||
/**
|
||||
* Find the type, offset, and bit field size of a type member.
|
||||
*
|
||||
* This matches the members of the type itself as well as the members of any
|
||||
* unnamed members of the type.
|
||||
*
|
||||
* This caches all members of @p type for subsequent calls.
|
||||
*
|
||||
* @param[in] tindex Type index.
|
||||
* @param[in] type Compound type to search in.
|
||||
* @param[in] member_name Name of member.
|
||||
* @param[in] member_name_len Length of @p member_name
|
||||
* @param[out] ret Returned member information.
|
||||
* @return @c NULL on success, non-@c NULL on error.
|
||||
*/
|
||||
struct drgn_error *drgn_type_index_find_member(struct drgn_type_index *tindex,
|
||||
struct drgn_type *type,
|
||||
const char *member_name,
|
||||
size_t member_name_len,
|
||||
struct drgn_member_value **ret);
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif /* DRGN_TYPE_INDEX_H */
|
@ -91,11 +91,11 @@ class TestProgram(unittest.TestCase):
|
||||
"foo.c",
|
||||
)
|
||||
self.assertRaisesRegex(
|
||||
LookupError, "^could not find 'typedef foo'$", prog.type, "foo"
|
||||
LookupError, "^could not find 'foo'$", prog.type, "foo"
|
||||
)
|
||||
self.assertRaisesRegex(
|
||||
LookupError,
|
||||
"^could not find 'typedef foo' in 'foo.c'$",
|
||||
"^could not find 'foo' in 'foo.c'$",
|
||||
prog.type,
|
||||
"foo",
|
||||
"foo.c",
|
||||
|
Loading…
Reference in New Issue
Block a user