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:
Omar Sandoval 2020-04-22 16:23:26 -07:00
parent 1c8181e22d
commit c31208f69c
17 changed files with 974 additions and 1160 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
/**

View File

@ -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; \
\

View File

@ -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;

View File

@ -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;

View File

@ -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,

View File

@ -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.
*

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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);
}

View File

@ -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 */

View File

@ -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);
}

View File

@ -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 */

View File

@ -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",