libdrgn: rename drgn_dwarf_type_cache to drgn_dwarf_info_cache

This is preparation for sharing this with the symbol index.
This commit is contained in:
Omar Sandoval 2019-04-28 12:13:29 -07:00
parent a98445c277
commit 52a8681a8d
7 changed files with 293 additions and 259 deletions

View File

@ -7,8 +7,9 @@ noinst_LTLIBRARIES = libdrgnimpl.la
libdrgnimpl_la_SOURCES = cityhash.h \
dwarf_index.c \
dwarf_index.h \
dwarf_info_cache.c \
dwarf_info_cache.h \
dwarf_symbol_index.c \
dwarf_type_cache.c \
error.c \
error.h \
hash_table.c \

View File

@ -1,13 +1,14 @@
// Copyright 2018-2019 - Omar Sandoval
// SPDX-License-Identifier: GPL-3.0+
#include <elfutils/libdw.h>
#include <dwarf.h>
#include <elfutils/libdw.h>
#include <libelf.h>
#include <string.h>
#include "internal.h"
#include "dwarf_index.h"
#include "dwarf_info_cache.h"
#include "hash_table.h"
#include "type_index.h"
@ -23,7 +24,7 @@ DEFINE_HASH_MAP_FUNCTIONS(dwarf_type_map, const void *, struct drgn_dwarf_type,
struct drgn_type_from_dwarf_thunk {
struct drgn_type_thunk thunk;
struct drgn_dwarf_type_cache *dtcache;
struct drgn_dwarf_info_cache *dicache;
Dwarf_Die die;
bool can_be_incomplete_array;
};
@ -99,7 +100,7 @@ drgn_type_from_dwarf_thunk_evaluate_fn(struct drgn_type_thunk *thunk,
struct drgn_type_from_dwarf_thunk *t;
t = container_of(thunk, struct drgn_type_from_dwarf_thunk, thunk);
return drgn_type_from_dwarf_internal(t->dtcache, &t->die,
return drgn_type_from_dwarf_internal(t->dicache, &t->die,
t->can_be_incomplete_array, NULL,
ret);
}
@ -110,7 +111,7 @@ static void drgn_type_from_dwarf_thunk_free_fn(struct drgn_type_thunk *thunk)
}
static struct drgn_error *
drgn_lazy_type_from_dwarf(struct drgn_dwarf_type_cache *dtcache,
drgn_lazy_type_from_dwarf(struct drgn_dwarf_info_cache *dicache,
Dwarf_Die *parent_die, bool can_be_void,
bool can_be_incomplete_array, const char *tag_name,
struct drgn_lazy_type *ret)
@ -142,7 +143,7 @@ drgn_lazy_type_from_dwarf(struct drgn_dwarf_type_cache *dtcache,
thunk->thunk.evaluate_fn = drgn_type_from_dwarf_thunk_evaluate_fn;
thunk->thunk.free_fn = drgn_type_from_dwarf_thunk_free_fn;
thunk->dtcache = dtcache;
thunk->dicache = dicache;
thunk->die = type_die;
thunk->can_be_incomplete_array = can_be_incomplete_array;
drgn_lazy_type_init_thunk(ret, &thunk->thunk);
@ -150,7 +151,7 @@ drgn_lazy_type_from_dwarf(struct drgn_dwarf_type_cache *dtcache,
}
struct drgn_error *
drgn_type_from_dwarf_child_internal(struct drgn_dwarf_type_cache *dtcache,
drgn_type_from_dwarf_child_internal(struct drgn_dwarf_info_cache *dicache,
Dwarf_Die *parent_die, const char *tag_name,
bool can_be_void,
bool can_be_incomplete_array,
@ -178,13 +179,13 @@ drgn_type_from_dwarf_child_internal(struct drgn_dwarf_type_cache *dtcache,
"%s has invalid DW_AT_type", tag_name);
}
return drgn_type_from_dwarf_internal(dtcache, &type_die,
return drgn_type_from_dwarf_internal(dicache, &type_die,
can_be_incomplete_array,
is_incomplete_array_ret, ret);
}
static struct drgn_error *
drgn_base_type_from_dwarf(struct drgn_dwarf_type_cache *dtcache, Dwarf_Die *die,
drgn_base_type_from_dwarf(struct drgn_dwarf_info_cache *dicache, Dwarf_Die *die,
struct drgn_type **ret)
{
struct drgn_type *type;
@ -243,7 +244,7 @@ drgn_base_type_from_dwarf(struct drgn_dwarf_type_cache *dtcache, Dwarf_Die *die,
return drgn_error_create(DRGN_ERROR_DWARF_FORMAT,
"DW_TAG_base_type has missing or invalid DW_AT_type");
}
err = drgn_type_from_dwarf(dtcache, &child, &real_type);
err = drgn_type_from_dwarf(dicache, &child, &real_type);
if (err)
return err;
if (drgn_type_kind(real_type.type) != DRGN_TYPE_FLOAT &&
@ -270,7 +271,7 @@ drgn_base_type_from_dwarf(struct drgn_dwarf_type_cache *dtcache, Dwarf_Die *die,
* type, it returns a DRGN_ERROR_STOP error. Otherwise, it returns an error.
*/
static struct drgn_error *
drgn_dwarf_type_cache_find_complete(struct drgn_dwarf_type_cache *dtcache,
drgn_dwarf_info_cache_find_complete(struct drgn_dwarf_info_cache *dicache,
uint64_t tag, const char *name,
struct drgn_type **ret)
{
@ -279,7 +280,7 @@ drgn_dwarf_type_cache_find_complete(struct drgn_dwarf_type_cache *dtcache,
Dwarf_Die die;
struct drgn_qualified_type qualified_type;
drgn_dwarf_index_iterator_init(&it, dtcache->dindex, name, strlen(name),
drgn_dwarf_index_iterator_init(&it, dicache->dindex, name, strlen(name),
&tag, 1);
/*
* Find a matching DIE. Note that drgn_dwarf_index does not contain DIEs
@ -298,7 +299,7 @@ drgn_dwarf_type_cache_find_complete(struct drgn_dwarf_type_cache *dtcache,
else if (err->code != DRGN_ERROR_STOP)
return err;
err = drgn_type_from_dwarf(dtcache, &die, &qualified_type);
err = drgn_type_from_dwarf(dicache, &die, &qualified_type);
if (err)
return err;
*ret = qualified_type.type;
@ -411,7 +412,7 @@ parse_member_offset(Dwarf_Die *die, struct drgn_lazy_type *member_type,
return NULL;
}
static struct drgn_error *parse_member(struct drgn_dwarf_type_cache *dtcache,
static struct drgn_error *parse_member(struct drgn_dwarf_info_cache *dicache,
Dwarf_Die *die, struct drgn_type *type,
size_t i, bool little_endian)
{
@ -447,7 +448,7 @@ static struct drgn_error *parse_member(struct drgn_dwarf_type_cache *dtcache,
bit_field_size = 0;
}
err = drgn_lazy_type_from_dwarf(dtcache, die, false, false,
err = drgn_lazy_type_from_dwarf(dicache, die, false, false,
"DW_TAG_member", &member_type);
if (err)
return err;
@ -465,7 +466,7 @@ static struct drgn_error *parse_member(struct drgn_dwarf_type_cache *dtcache,
}
static struct drgn_error *
drgn_compound_type_from_dwarf(struct drgn_dwarf_type_cache *dtcache,
drgn_compound_type_from_dwarf(struct drgn_dwarf_info_cache *dicache,
Dwarf_Die *die, bool is_struct,
struct drgn_type **ret, bool *should_free)
{
@ -498,7 +499,7 @@ drgn_compound_type_from_dwarf(struct drgn_dwarf_type_cache *dtcache,
is_struct ? "structure" : "union");
}
if (declaration && tag) {
err = drgn_dwarf_type_cache_find_complete(dtcache,
err = drgn_dwarf_info_cache_find_complete(dicache,
is_struct ?
DW_TAG_structure_type :
DW_TAG_union_type,
@ -549,7 +550,7 @@ drgn_compound_type_from_dwarf(struct drgn_dwarf_type_cache *dtcache,
}
}
err = parse_member(dtcache, &child, type, num_members,
err = parse_member(dicache, &child, type, num_members,
little_endian);
if (err)
goto err;
@ -682,7 +683,7 @@ static void fallback_enum_compatible_types_init(void)
* DIEs, either, so we also have to guess at the sign.
*/
static struct drgn_error *
enum_compatible_type_fallback(struct drgn_dwarf_type_cache *dtcache,
enum_compatible_type_fallback(struct drgn_dwarf_info_cache *dicache,
Dwarf_Die *die, bool is_signed,
struct drgn_type **ret)
{
@ -715,7 +716,7 @@ enum_compatible_type_fallback(struct drgn_dwarf_type_cache *dtcache,
}
static struct drgn_error *
drgn_enum_type_from_dwarf(struct drgn_dwarf_type_cache *dtcache, Dwarf_Die *die,
drgn_enum_type_from_dwarf(struct drgn_dwarf_info_cache *dicache, Dwarf_Die *die,
struct drgn_type **ret, bool *should_free)
{
struct drgn_error *err;
@ -745,7 +746,7 @@ drgn_enum_type_from_dwarf(struct drgn_dwarf_type_cache *dtcache, Dwarf_Die *die,
"DW_TAG_enumeration_type has invalid DW_AT_declaration");
}
if (declaration && tag) {
err = drgn_dwarf_type_cache_find_complete(dtcache,
err = drgn_dwarf_info_cache_find_complete(dicache,
DW_TAG_enumeration_type,
tag, ret);
if (!err) {
@ -810,14 +811,14 @@ drgn_enum_type_from_dwarf(struct drgn_dwarf_type_cache *dtcache, Dwarf_Die *die,
"DW_TAG_enumeration_type has invalid DW_AT_type");
goto err;
} else if (r) {
err = enum_compatible_type_fallback(dtcache, die, is_signed,
err = enum_compatible_type_fallback(dicache, die, is_signed,
&compatible_type);
if (err)
goto err;
} else {
struct drgn_qualified_type qualified_compatible_type;
err = drgn_type_from_dwarf(dtcache, &child,
err = drgn_type_from_dwarf(dicache, &child,
&qualified_compatible_type);
if (err)
goto err;
@ -839,7 +840,7 @@ err:
}
static struct drgn_error *
drgn_typedef_type_from_dwarf(struct drgn_dwarf_type_cache *dtcache,
drgn_typedef_type_from_dwarf(struct drgn_dwarf_info_cache *dicache,
Dwarf_Die *die, bool can_be_incomplete_array,
bool *is_incomplete_array_ret,
struct drgn_type **ret)
@ -859,7 +860,7 @@ drgn_typedef_type_from_dwarf(struct drgn_dwarf_type_cache *dtcache,
if (!type)
return &drgn_enomem;
err = drgn_type_from_dwarf_child_internal(dtcache, die,
err = drgn_type_from_dwarf_child_internal(dicache, die,
"DW_TAG_typedef", true,
can_be_incomplete_array,
is_incomplete_array_ret,
@ -875,18 +876,18 @@ drgn_typedef_type_from_dwarf(struct drgn_dwarf_type_cache *dtcache,
}
static struct drgn_error *
drgn_pointer_type_from_dwarf(struct drgn_dwarf_type_cache *dtcache,
drgn_pointer_type_from_dwarf(struct drgn_dwarf_info_cache *dicache,
Dwarf_Die *die, struct drgn_type **ret)
{
struct drgn_error *err;
struct drgn_qualified_type referenced_type;
err = drgn_type_from_dwarf_child(dtcache, die, "DW_TAG_pointer_type",
err = drgn_type_from_dwarf_child(dicache, die, "DW_TAG_pointer_type",
true, &referenced_type);
if (err)
return err;
return drgn_type_index_pointer_type(dtcache->tindex, referenced_type,
return drgn_type_index_pointer_type(dicache->tindex, referenced_type,
ret);
}
@ -934,7 +935,7 @@ static struct drgn_error *subrange_length(Dwarf_Die *die,
}
static struct drgn_error *
drgn_array_type_from_dwarf(struct drgn_dwarf_type_cache *dtcache,
drgn_array_type_from_dwarf(struct drgn_dwarf_info_cache *dicache,
Dwarf_Die *die, bool can_be_incomplete_array,
bool *is_incomplete_array_ret,
struct drgn_type **ret)
@ -980,7 +981,7 @@ drgn_array_type_from_dwarf(struct drgn_dwarf_type_cache *dtcache,
dimensions[num_dimensions++].is_complete = false;
}
err = drgn_type_from_dwarf_child_internal(dtcache, die,
err = drgn_type_from_dwarf_child_internal(dicache, die,
"DW_TAG_array_type", false,
false, NULL, &element_type);
if (err)
@ -992,14 +993,14 @@ drgn_array_type_from_dwarf(struct drgn_dwarf_type_cache *dtcache,
dimension = &dimensions[--num_dimensions];
if (dimension->is_complete) {
err = drgn_type_index_array_type(dtcache->tindex,
err = drgn_type_index_array_type(dicache->tindex,
dimension->length,
element_type, &type);
} else if (num_dimensions || !can_be_incomplete_array) {
err = drgn_type_index_array_type(dtcache->tindex, 0,
err = drgn_type_index_array_type(dicache->tindex, 0,
element_type, &type);
} else {
err = drgn_type_index_incomplete_array_type(dtcache->tindex,
err = drgn_type_index_incomplete_array_type(dicache->tindex,
element_type,
&type);
}
@ -1018,7 +1019,7 @@ out:
}
static struct drgn_error *
parse_formal_parameter(struct drgn_dwarf_type_cache *dtcache, Dwarf_Die *die,
parse_formal_parameter(struct drgn_dwarf_info_cache *dicache, Dwarf_Die *die,
struct drgn_type *type, size_t i)
{
struct drgn_error *err;
@ -1038,7 +1039,7 @@ parse_formal_parameter(struct drgn_dwarf_type_cache *dtcache, Dwarf_Die *die,
name = NULL;
}
err = drgn_lazy_type_from_dwarf(dtcache, die, false, true,
err = drgn_lazy_type_from_dwarf(dicache, die, false, true,
"DW_TAG_formal_parameter",
&parameter_type);
if (err)
@ -1049,7 +1050,7 @@ parse_formal_parameter(struct drgn_dwarf_type_cache *dtcache, Dwarf_Die *die,
}
static struct drgn_error *
drgn_function_type_from_dwarf(struct drgn_dwarf_type_cache *dtcache,
drgn_function_type_from_dwarf(struct drgn_dwarf_info_cache *dicache,
Dwarf_Die *die, struct drgn_type **ret)
{
struct drgn_error *err;
@ -1095,7 +1096,7 @@ drgn_function_type_from_dwarf(struct drgn_dwarf_type_cache *dtcache,
}
}
err = parse_formal_parameter(dtcache, &child, type,
err = parse_formal_parameter(dicache, &child, type,
num_parameters);
if (err)
goto err;
@ -1122,7 +1123,7 @@ drgn_function_type_from_dwarf(struct drgn_dwarf_type_cache *dtcache,
sizeof(struct drgn_type_parameter));
}
err = drgn_type_from_dwarf_child(dtcache, die, tag_name, true,
err = drgn_type_from_dwarf_child(dicache, die, tag_name, true,
&return_type);
if (err)
goto err;
@ -1139,7 +1140,7 @@ err:
}
struct drgn_error *
drgn_type_from_dwarf_internal(struct drgn_dwarf_type_cache *dtcache,
drgn_type_from_dwarf_internal(struct drgn_dwarf_info_cache *dicache,
Dwarf_Die *die, bool can_be_incomplete_array,
bool *is_incomplete_array_ret,
struct drgn_qualified_type *ret)
@ -1150,16 +1151,16 @@ drgn_type_from_dwarf_internal(struct drgn_dwarf_type_cache *dtcache,
struct drgn_dwarf_type *value, dwarf_type;
struct dwarf_type_map *map;
if (dtcache->depth >= 1000) {
if (dicache->depth >= 1000) {
return drgn_error_create(DRGN_ERROR_RECURSION,
"maximum DWARF type parsing depth exceeded");
}
hp = dwarf_type_map_hash(&key);
value = dwarf_type_map_search_hashed(&dtcache->map, &key, hp);
value = dwarf_type_map_search_hashed(&dicache->map, &key, hp);
if (value) {
if (!can_be_incomplete_array && value->is_incomplete_array) {
map = &dtcache->cant_be_incomplete_array_map;
map = &dicache->cant_be_incomplete_array_map;
value = dwarf_type_map_search_hashed(map, &key, hp);
}
if (value) {
@ -1170,7 +1171,7 @@ drgn_type_from_dwarf_internal(struct drgn_dwarf_type_cache *dtcache,
}
ret->qualifiers = 0;
dtcache->depth++;
dicache->depth++;
dwarf_type.is_incomplete_array = false;
switch (dwarf_tag(die)) {
case DW_TAG_const_type:
@ -1179,53 +1180,53 @@ drgn_type_from_dwarf_internal(struct drgn_dwarf_type_cache *dtcache,
* unqualified type.
*/
dwarf_type.should_free = false;
err = drgn_type_from_dwarf_child(dtcache, die,
err = drgn_type_from_dwarf_child(dicache, die,
"DW_TAG_const_type", true,
ret);
ret->qualifiers |= DRGN_QUALIFIER_CONST;
break;
case DW_TAG_restrict_type:
dwarf_type.should_free = false;
err = drgn_type_from_dwarf_child(dtcache, die,
err = drgn_type_from_dwarf_child(dicache, die,
"DW_TAG_restrict_type", true,
ret);
ret->qualifiers |= DRGN_QUALIFIER_RESTRICT;
break;
case DW_TAG_volatile_type:
dwarf_type.should_free = false;
err = drgn_type_from_dwarf_child(dtcache, die,
err = drgn_type_from_dwarf_child(dicache, die,
"DW_TAG_volatile_type", true,
ret);
ret->qualifiers |= DRGN_QUALIFIER_VOLATILE;
break;
case DW_TAG_atomic_type:
dwarf_type.should_free = false;
err = drgn_type_from_dwarf_child(dtcache, die,
err = drgn_type_from_dwarf_child(dicache, die,
"DW_TAG_atomic_type", true,
ret);
ret->qualifiers |= DRGN_QUALIFIER_ATOMIC;
break;
case DW_TAG_base_type:
dwarf_type.should_free = true;
err = drgn_base_type_from_dwarf(dtcache, die, &ret->type);
err = drgn_base_type_from_dwarf(dicache, die, &ret->type);
break;
case DW_TAG_structure_type:
err = drgn_compound_type_from_dwarf(dtcache, die, true,
err = drgn_compound_type_from_dwarf(dicache, die, true,
&ret->type,
&dwarf_type.should_free);
break;
case DW_TAG_union_type:
err = drgn_compound_type_from_dwarf(dtcache, die, false,
err = drgn_compound_type_from_dwarf(dicache, die, false,
&ret->type,
&dwarf_type.should_free);
break;
case DW_TAG_enumeration_type:
err = drgn_enum_type_from_dwarf(dtcache, die, &ret->type,
err = drgn_enum_type_from_dwarf(dicache, die, &ret->type,
&dwarf_type.should_free);
break;
case DW_TAG_typedef:
dwarf_type.should_free = true;
err = drgn_typedef_type_from_dwarf(dtcache, die,
err = drgn_typedef_type_from_dwarf(dicache, die,
can_be_incomplete_array,
&dwarf_type.is_incomplete_array,
&ret->type);
@ -1233,12 +1234,12 @@ drgn_type_from_dwarf_internal(struct drgn_dwarf_type_cache *dtcache,
case DW_TAG_pointer_type:
/* Pointer types are owned by the type index. */
dwarf_type.should_free = false;
err = drgn_pointer_type_from_dwarf(dtcache, die, &ret->type);
err = drgn_pointer_type_from_dwarf(dicache, die, &ret->type);
break;
case DW_TAG_array_type:
/* Array types are owned by the type index. */
dwarf_type.should_free = false;
err = drgn_array_type_from_dwarf(dtcache, die,
err = drgn_array_type_from_dwarf(dicache, die,
can_be_incomplete_array,
&dwarf_type.is_incomplete_array,
&ret->type);
@ -1246,7 +1247,7 @@ drgn_type_from_dwarf_internal(struct drgn_dwarf_type_cache *dtcache,
case DW_TAG_subroutine_type:
case DW_TAG_subprogram:
dwarf_type.should_free = true;
err = drgn_function_type_from_dwarf(dtcache, die, &ret->type);
err = drgn_function_type_from_dwarf(dicache, die, &ret->type);
break;
default:
err = drgn_error_format(DRGN_ERROR_DWARF_FORMAT,
@ -1254,16 +1255,16 @@ drgn_type_from_dwarf_internal(struct drgn_dwarf_type_cache *dtcache,
dwarf_tag(die));
break;
}
dtcache->depth--;
dicache->depth--;
if (err)
return err;
dwarf_type.type = ret->type;
dwarf_type.qualifiers = ret->qualifiers;
if (!can_be_incomplete_array && dwarf_type.is_incomplete_array)
map = &dtcache->cant_be_incomplete_array_map;
map = &dicache->cant_be_incomplete_array_map;
else
map = &dtcache->map;
map = &dicache->map;
if (!dwarf_type_map_insert_searched(map, &key, &dwarf_type, hp)) {
drgn_dwarf_type_free(&dwarf_type);
return &drgn_enomem;
@ -1279,7 +1280,7 @@ struct drgn_error *drgn_dwarf_type_find(enum drgn_type_kind kind,
struct drgn_qualified_type *ret)
{
struct drgn_error *err;
struct drgn_dwarf_type_cache *dtcache = arg;
struct drgn_dwarf_info_cache *dicache = arg;
struct drgn_dwarf_index_iterator it;
Dwarf_Die die;
uint64_t tag;
@ -1306,11 +1307,11 @@ struct drgn_error *drgn_dwarf_type_find(enum drgn_type_kind kind,
DRGN_UNREACHABLE();
}
drgn_dwarf_index_iterator_init(&it, dtcache->dindex, name, name_len,
drgn_dwarf_index_iterator_init(&it, dicache->dindex, name, name_len,
&tag, 1);
while (!(err = drgn_dwarf_index_iterator_next(&it, &die))) {
if (die_matches_filename(&die, filename)) {
err = drgn_type_from_dwarf(dtcache, &die, ret);
err = drgn_type_from_dwarf(dicache, &die, ret);
if (err)
return err;
/*
@ -1328,36 +1329,36 @@ struct drgn_error *drgn_dwarf_type_find(enum drgn_type_kind kind,
}
struct drgn_error *
drgn_dwarf_type_cache_create(struct drgn_type_index *tindex,
drgn_dwarf_info_cache_create(struct drgn_type_index *tindex,
struct drgn_dwarf_index *dindex,
struct drgn_dwarf_type_cache **ret)
struct drgn_dwarf_info_cache **ret)
{
struct drgn_dwarf_type_cache *dtcache;
struct drgn_dwarf_info_cache *dicache;
dtcache = malloc(sizeof(*dtcache));
if (!dtcache)
dicache = malloc(sizeof(*dicache));
if (!dicache)
return &drgn_enomem;
dtcache->tindex = tindex;
dwarf_type_map_init(&dtcache->map);
dwarf_type_map_init(&dtcache->cant_be_incomplete_array_map);
dtcache->dindex = dindex;
dtcache->depth = 0;
*ret = dtcache;
dicache->tindex = tindex;
dwarf_type_map_init(&dicache->map);
dwarf_type_map_init(&dicache->cant_be_incomplete_array_map);
dicache->dindex = dindex;
dicache->depth = 0;
*ret = dicache;
return NULL;
}
void drgn_dwarf_type_cache_destroy(struct drgn_dwarf_type_cache *dtcache)
void drgn_dwarf_info_cache_destroy(struct drgn_dwarf_info_cache *dicache)
{
struct dwarf_type_map_pos pos;
for (pos = dwarf_type_map_first_pos(&dtcache->map);
for (pos = dwarf_type_map_first_pos(&dicache->map);
pos.item; dwarf_type_map_next_pos(&pos))
drgn_dwarf_type_free(&pos.item->value);
/* Arrays don't need to be freed, but typedefs do. */
for (pos = dwarf_type_map_first_pos(&dtcache->cant_be_incomplete_array_map);
for (pos = dwarf_type_map_first_pos(&dicache->cant_be_incomplete_array_map);
pos.item; dwarf_type_map_next_pos(&pos))
drgn_dwarf_type_free(&pos.item->value);
dwarf_type_map_deinit(&dtcache->cant_be_incomplete_array_map);
dwarf_type_map_deinit(&dtcache->map);
free(dtcache);
dwarf_type_map_deinit(&dicache->cant_be_incomplete_array_map);
dwarf_type_map_deinit(&dicache->map);
free(dicache);
}

186
libdrgn/dwarf_info_cache.h Normal file
View File

@ -0,0 +1,186 @@
// Copyright 2018-2019 - Omar Sandoval
// SPDX-License-Identifier: GPL-3.0+
/**
* @file
*
* Debugging information cache.
*
* See @ref DWARFInfoCache.
*/
#ifndef DRGN_DWARF_INFO_CACHE_H
#define DRGN_DWARF_INFO_CACHE_H
#include "drgn.h"
#include "hash_table.h"
/**
* @ingroup Internals
*
* @defgroup DWARFInfoCache Debugging information cache
*
* 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_symbol_index.
*
* @{
*/
/** Cached type in a @ref drgn_dwarf_info_cache. */
struct drgn_dwarf_type {
struct drgn_type *type;
enum drgn_qualifiers qualifiers;
/**
* Whether this is an incomplete array type or a typedef of one.
*
* This is used to work around a GCC bug; see @ref
* drgn_type_from_dwarf_internal().
*/
bool is_incomplete_array;
/** Whether we need to free @c type. */
bool should_free;
};
DEFINE_HASH_MAP_TYPES(dwarf_type_map, const void *, struct drgn_dwarf_type);
struct drgn_dwarf_index;
/**
* Cache of types and symbols from DWARF debugging information.
*
* This is the argument for @ref drgn_dwarf_type_find() and @ref
* drgn_dwarf_symbol_find().
*/
struct drgn_dwarf_info_cache {
/** Type index. */
struct drgn_type_index *tindex;
/** Index of DWARF debugging information. */
struct drgn_dwarf_index *dindex;
/**
* Cache of parsed types.
*
* The key is the address of the DIE (@c Dwarf_Die::addr). The value is
* a @ref drgn_dwarf_type.
*/
struct dwarf_type_map map;
/**
* Cache of parsed types which appear to be incomplete array types but
* can't be.
*
* See @ref drgn_type_from_dwarf_internal().
*/
struct dwarf_type_map cant_be_incomplete_array_map;
/** Current parsing recursion depth. */
int depth;
};
/** Create a @ref drgn_dwarf_info_cache. */
struct drgn_error *
drgn_dwarf_info_cache_create(struct drgn_type_index *tindex,
struct drgn_dwarf_index *dindex,
struct drgn_dwarf_info_cache **ret);
/** Destroy a @ref drgn_dwarf_info_cache. */
void drgn_dwarf_info_cache_destroy(struct drgn_dwarf_info_cache *dicache);
/** @ref drgn_type_find_fn() that uses DWARF debugging information. */
struct drgn_error *drgn_dwarf_type_find(enum drgn_type_kind kind,
const char *name, size_t name_len,
const char *filename, void *arg,
struct drgn_qualified_type *ret);
/**
* Parse a type from a DWARF debugging information entry.
*
* This is the same as @ref drgn_type_from_dwarf() except that it can be used to
* work around a bug in GCC < 9.0 that zero length array types are encoded the
* same as incomplete array types. There are a few places where GCC allows
* zero-length arrays but not incomplete arrays:
*
* - As the type of a member of a structure with only one member.
* - As the type of a structure member other than the last member.
* - As the type of a union member.
* - As the element type of an array.
*
* In these cases, we know that what appears to be an incomplete array type must
* actually have a length of zero. In other cases, a subrange DIE without
* DW_AT_count or DW_AT_upper_bound is ambiguous; we return an incomplete array
* type.
*
* @param[in] dicache Debugging information cache.
* @param[in] die DIE to parse.
* @param[in] can_be_incomplete_array Whether the type can be an incomplete
* array type. If this is @c false and the type appears to be an incomplete
* array type, its length is set to zero instead.
* @param[out] is_incomplete_array_ret Whether the encoded type is an incomplete
* array type or a typedef of an incomplete array type (regardless of @p
* can_be_incomplete_array).
* @param[out] ret Returned type.
* @return @c NULL on success, non-@c NULL on error.
*/
struct drgn_error *
drgn_type_from_dwarf_internal(struct drgn_dwarf_info_cache *dicache,
Dwarf_Die *die, bool can_be_incomplete_array,
bool *is_incomplete_array_ret,
struct drgn_qualified_type *ret);
/**
* Parse a type from a DWARF debugging information entry.
*
* @param[in] dicache Debugging information cache.
* @param[in] die DIE to parse.
* @param[out] ret Returned type.
* @return @c NULL on success, non-@c NULL on error.
*/
static inline struct drgn_error *
drgn_type_from_dwarf(struct drgn_dwarf_info_cache *dicache, Dwarf_Die *die,
struct drgn_qualified_type *ret)
{
return drgn_type_from_dwarf_internal(dicache, die, true, NULL, ret);
}
/**
* Parse a type from the @c DW_AT_type attribute of a DWARF debugging
* information entry.
*
* See @ref drgn_type_from_dwarf_child() and @ref
* drgn_type_from_dwarf_internal().
*/
struct drgn_error *
drgn_type_from_dwarf_child_internal(struct drgn_dwarf_info_cache *dicache,
Dwarf_Die *parent_die, const char *tag_name,
bool can_be_void,
bool can_be_incomplete_array,
bool *is_incomplete_array_ret,
struct drgn_qualified_type *ret);
/**
* Parse a type from the @c DW_AT_type attribute of a DWARF debugging
* information entry.
*
* @param[in] dicache Debugging information cache.
* @param[in] parent_die Parent DIE.
* @param[in] can_be_void Whether the @c DW_AT_type attribute may be missing,
* which is interpreted as a void type. If this is false and the @c DW_AT_type
* attribute is missing, an error is returned.
* @param[in] tag_name Spelling of the DWARF tag of @p parent_die. Used for
* error messages.
* @param[out] ret Returned type.
* @return @c NULL on success, non-@c NULL on error.
*/
static inline struct drgn_error *
drgn_type_from_dwarf_child(struct drgn_dwarf_info_cache *dicache,
Dwarf_Die *parent_die, const char *tag_name,
bool can_be_void, struct drgn_qualified_type *ret)
{
return drgn_type_from_dwarf_child_internal(dicache, parent_die,
tag_name, can_be_void, true,
NULL, ret);
}
/** @} */
#endif /* DRGN_DWARF_INFO_CACHE_H */

View File

@ -7,6 +7,7 @@
#include "internal.h"
#include "dwarf_index.h"
#include "dwarf_info_cache.h"
#include "symbol_index.h"
#include "type_index.h"
@ -18,7 +19,7 @@ drgn_symbol_from_dwarf_enumerator(struct drgn_dwarf_symbol_index *dsindex,
struct drgn_error *err;
assert(dwarf_tag(die) == DW_TAG_enumeration_type);
err = drgn_type_from_dwarf(dsindex->dtcache, die, &ret->qualified_type);
err = drgn_type_from_dwarf(dsindex->dicache, die, &ret->qualified_type);
if (err)
return err;
return drgn_symbol_from_enumerator(ret, name);
@ -32,7 +33,7 @@ drgn_symbol_from_dwarf_subprogram(struct drgn_dwarf_symbol_index *dsindex,
struct drgn_error *err;
Dwarf_Addr low_pc;
err = drgn_type_from_dwarf(dsindex->dtcache, die, &ret->qualified_type);
err = drgn_type_from_dwarf(dsindex->dicache, die, &ret->qualified_type);
if (err)
return err;
@ -63,7 +64,7 @@ drgn_symbol_from_dwarf_variable(struct drgn_dwarf_symbol_index *dsindex,
Dwarf_Op *loc;
size_t nloc;
err = drgn_type_from_dwarf_child(dsindex->dtcache, die,
err = drgn_type_from_dwarf_child(dsindex->dicache, die,
"DW_TAG_variable", true,
&ret->qualified_type);
if (err)
@ -114,7 +115,7 @@ drgn_dwarf_symbol_index_find(struct drgn_symbol_index *sindex, const char *name,
tags[num_tags++] = DW_TAG_variable;
dsindex = container_of(sindex, struct drgn_dwarf_symbol_index, sindex);
drgn_dwarf_index_iterator_init(&it, dsindex->dtcache->dindex, name,
drgn_dwarf_index_iterator_init(&it, dsindex->dicache->dindex, name,
strlen(name), tags, num_tags);
while (!(err = drgn_dwarf_index_iterator_next(&it, &die))) {
if (!die_matches_filename(&die, filename))
@ -153,7 +154,7 @@ static const struct drgn_symbol_index_ops drgn_dwarf_symbol_index_ops = {
};
struct drgn_error *
drgn_dwarf_symbol_index_create(struct drgn_dwarf_type_cache *dtcache,
drgn_dwarf_symbol_index_create(struct drgn_dwarf_info_cache *dicache,
struct drgn_dwarf_symbol_index **ret)
{
struct drgn_dwarf_symbol_index *dsindex;
@ -162,7 +163,7 @@ drgn_dwarf_symbol_index_create(struct drgn_dwarf_type_cache *dtcache,
if (!dsindex)
return &drgn_enomem;
dsindex->sindex.ops = &drgn_dwarf_symbol_index_ops;
dsindex->dtcache = dtcache;
dsindex->dicache = dicache;
dsindex->prog = NULL;
dsindex->relocation_hook = NULL;

View File

@ -17,6 +17,7 @@
#include "internal.h"
#include "dwarf_index.h"
#include "dwarf_info_cache.h"
#include "language.h"
#include "memory_reader.h"
#include "symbol_index.h"
@ -1063,9 +1064,9 @@ static void cleanup_dwarf_index(void *arg)
drgn_dwarf_index_destroy(arg);
}
static void cleanup_dwarf_type_cache(void *arg)
static void cleanup_dwarf_info_cache(void *arg)
{
drgn_dwarf_type_cache_destroy(arg);
drgn_dwarf_info_cache_destroy(arg);
}
static void cleanup_file_mappings(void *arg)
@ -1108,7 +1109,7 @@ struct drgn_error *drgn_program_init_core_dump(struct drgn_program *prog,
struct drgn_memory_reader *reader;
struct drgn_dwarf_index *dindex;
struct drgn_type_index *tindex;
struct drgn_dwarf_type_cache *dtcache;
struct drgn_dwarf_info_cache *dicache;
struct drgn_dwarf_symbol_index *dsindex;
fd = open(path, O_RDONLY);
@ -1336,15 +1337,15 @@ struct drgn_error *drgn_program_init_core_dump(struct drgn_program *prog,
if (err)
goto out_dindex;
err = drgn_dwarf_type_cache_create(tindex, dindex, &dtcache);
err = drgn_dwarf_info_cache_create(tindex, dindex, &dicache);
if (err)
goto out_tindex;
err = drgn_type_index_add_finder(tindex, drgn_dwarf_type_find, dtcache);
err = drgn_type_index_add_finder(tindex, drgn_dwarf_type_find, dicache);
if (err)
goto out_dtcache;
err = drgn_dwarf_symbol_index_create(dtcache, &dsindex);
err = drgn_dwarf_symbol_index_create(dicache, &dsindex);
if (err)
goto out_dtcache;
@ -1358,7 +1359,7 @@ struct drgn_error *drgn_program_init_core_dump(struct drgn_program *prog,
err = drgn_program_add_cleanup(prog, cleanup_dwarf_index, dindex);
if (err)
goto out_cleanup_file_segments;
err = drgn_program_add_cleanup(prog, cleanup_dwarf_type_cache, dtcache);
err = drgn_program_add_cleanup(prog, cleanup_dwarf_info_cache, dicache);
if (err)
goto out_cleanup_dindex;
dsindex->prog = prog;
@ -1378,7 +1379,7 @@ struct drgn_error *drgn_program_init_core_dump(struct drgn_program *prog,
return NULL;
out_cleanup_dtcache:
drgn_program_remove_cleanup(prog, cleanup_dwarf_type_cache, dtcache);
drgn_program_remove_cleanup(prog, cleanup_dwarf_info_cache, dicache);
out_cleanup_dindex:
drgn_program_remove_cleanup(prog, cleanup_dwarf_index, dindex);
out_cleanup_file_segments:
@ -1388,7 +1389,7 @@ out_cleanup_fd:
out_program:
drgn_program_deinit(prog);
out_dtcache:
drgn_dwarf_type_cache_destroy(dtcache);
drgn_dwarf_info_cache_destroy(dicache);
out_tindex:
drgn_type_index_destroy(tindex);
out_dindex:
@ -1475,7 +1476,7 @@ struct drgn_error *drgn_program_init_pid(struct drgn_program *prog, pid_t pid)
struct drgn_memory_reader *reader;
struct drgn_dwarf_index *dindex;
struct drgn_type_index *tindex;
struct drgn_dwarf_type_cache *dtcache;
struct drgn_dwarf_info_cache *dicache;
struct drgn_dwarf_symbol_index *dsindex;
sprintf(buf, "/proc/%ld/mem", (long)pid);
@ -1523,15 +1524,15 @@ struct drgn_error *drgn_program_init_pid(struct drgn_program *prog, pid_t pid)
if (err)
goto out_dindex;
err = drgn_dwarf_type_cache_create(tindex, dindex, &dtcache);
err = drgn_dwarf_info_cache_create(tindex, dindex, &dicache);
if (err)
goto out_tindex;
err = drgn_type_index_add_finder(tindex, drgn_dwarf_type_find, dtcache);
err = drgn_type_index_add_finder(tindex, drgn_dwarf_type_find, dicache);
if (err)
goto out_dtcache;
err = drgn_dwarf_symbol_index_create(dtcache, &dsindex);
err = drgn_dwarf_symbol_index_create(dicache, &dsindex);
if (err)
goto out_dtcache;
@ -1549,7 +1550,7 @@ struct drgn_error *drgn_program_init_pid(struct drgn_program *prog, pid_t pid)
err = drgn_program_add_cleanup(prog, cleanup_dwarf_index, dindex);
if (err)
goto out_cleanup_file_segment;
err = drgn_program_add_cleanup(prog, cleanup_dwarf_type_cache, dtcache);
err = drgn_program_add_cleanup(prog, cleanup_dwarf_info_cache, dicache);
if (err)
goto out_cleanup_dindex;
err = drgn_program_add_cleanup(prog, cleanup_file_mappings, prog);
@ -1558,7 +1559,7 @@ struct drgn_error *drgn_program_init_pid(struct drgn_program *prog, pid_t pid)
return NULL;
out_cleanup_dtcache:
drgn_program_remove_cleanup(prog, cleanup_dwarf_type_cache, dtcache);
drgn_program_remove_cleanup(prog, cleanup_dwarf_info_cache, dicache);
out_cleanup_dindex:
drgn_program_remove_cleanup(prog, cleanup_dwarf_index, dindex);
out_cleanup_file_segment:
@ -1568,7 +1569,7 @@ out_cleanup_fd:
out_program:
drgn_program_deinit(prog);
out_dtcache:
drgn_dwarf_type_cache_destroy(dtcache);
drgn_dwarf_info_cache_destroy(dicache);
out_tindex:
drgn_type_index_destroy(tindex);
out_dindex:

View File

@ -209,13 +209,8 @@ struct drgn_program;
struct drgn_dwarf_symbol_index {
/** Abstract symbol index. */
struct drgn_symbol_index sindex;
/**
* DWARF type cache.
*
* Used to lookup types and DWARF information through @ref
* drgn_dwarf_type_cache::dindex.
*/
struct drgn_dwarf_type_cache *dtcache;
/** Debugging information cache. */
struct drgn_dwarf_info_cache *dicache;
/** Program to pass to @c relocation_hook(). */
struct drgn_program *prog;
/**
@ -248,7 +243,7 @@ struct drgn_dwarf_symbol_index {
* @return @c NULL on success, non-@c NULL on error.
*/
struct drgn_error *
drgn_dwarf_symbol_index_create(struct drgn_dwarf_type_cache *dcache,
drgn_dwarf_symbol_index_create(struct drgn_dwarf_info_cache *dcache,
struct drgn_dwarf_symbol_index **ret);
/** @} */

View File

@ -302,157 +302,6 @@ struct drgn_mock_type {
const char *filename;
};
/** Cached type in a @ref drgn_dwarf_type_cache. */
struct drgn_dwarf_type {
struct drgn_type *type;
enum drgn_qualifiers qualifiers;
/**
* Whether this is an incomplete array type or a typedef of one.
*
* This is used to work around a GCC bug; see @ref
* drgn_type_from_dwarf_internal().
*/
bool is_incomplete_array;
/** Whether we need to free @c type. */
bool should_free;
};
DEFINE_HASH_MAP_TYPES(dwarf_type_map, const void *, struct drgn_dwarf_type);
struct drgn_dwarf_index;
/**
* Cache of types from DWARF debugging information.
*
* This is the argument for @ref drgn_dwarf_type_find().
*/
struct drgn_dwarf_type_cache {
/** Type index. */
struct drgn_type_index *tindex;
/** Index of DWARF debugging information. */
struct drgn_dwarf_index *dindex;
/**
* Cache of parsed types.
*
* The key is the address of the DIE (@c Dwarf_Die::addr). The value is
* a @ref drgn_dwarf_type.
*/
struct dwarf_type_map map;
/**
* Cache of parsed types which appear to be incomplete array types but
* can't be.
*
* See @ref drgn_type_from_dwarf_internal().
*/
struct dwarf_type_map cant_be_incomplete_array_map;
/** Current parsing recursion depth. */
int depth;
};
/** Create a @ref drgn_dwarf_type_cache. */
struct drgn_error *
drgn_dwarf_type_cache_create(struct drgn_type_index *tindex,
struct drgn_dwarf_index *dindex,
struct drgn_dwarf_type_cache **ret);
/** Destroy a @ref drgn_dwarf_type_cache. */
void drgn_dwarf_type_cache_destroy(struct drgn_dwarf_type_cache *dtcache);
/** @ref drgn_type_find_fn() that uses DWARF debugging information. */
struct drgn_error *drgn_dwarf_type_find(enum drgn_type_kind kind,
const char *name, size_t name_len,
const char *filename, void *arg,
struct drgn_qualified_type *ret);
/**
* Parse a type from a DWARF debugging information entry.
*
* This is the same as @ref drgn_type_from_dwarf() except that it can be used to
* work around a bug in GCC < 9.0 that zero length array types are encoded the
* same as incomplete array types. There are a few places where GCC allows
* zero-length arrays but not incomplete arrays:
*
* - As the type of a member of a structure with only one member.
* - As the type of a structure member other than the last member.
* - As the type of a union member.
* - As the element type of an array.
*
* In these cases, we know that what appears to be an incomplete array type must
* actually have a length of zero. In other cases, a subrange DIE without
* DW_AT_count or DW_AT_upper_bound is ambiguous; we return an incomplete array
* type.
*
* @param[in] dtcache DWARF type cache.
* @param[in] die DIE to parse.
* @param[in] can_be_incomplete_array Whether the type can be an incomplete
* array type. If this is @c false and the type appears to be an incomplete
* array type, its length is set to zero instead.
* @param[out] is_incomplete_array_ret Whether the encoded type is an incomplete
* array type or a typedef of an incomplete array type (regardless of @p
* can_be_incomplete_array).
* @param[out] ret Returned type.
* @return @c NULL on success, non-@c NULL on error.
*/
struct drgn_error *
drgn_type_from_dwarf_internal(struct drgn_dwarf_type_cache *dtcache,
Dwarf_Die *die, bool can_be_incomplete_array,
bool *is_incomplete_array_ret,
struct drgn_qualified_type *ret);
/**
* Parse a type from a DWARF debugging information entry.
*
* @param[in] dtcache DWARF type cache.
* @param[in] die DIE to parse.
* @param[out] ret Returned type.
* @return @c NULL on success, non-@c NULL on error.
*/
static inline struct drgn_error *
drgn_type_from_dwarf(struct drgn_dwarf_type_cache *dtcache, Dwarf_Die *die,
struct drgn_qualified_type *ret)
{
return drgn_type_from_dwarf_internal(dtcache, die, true, NULL, ret);
}
/**
* Parse a type from the @c DW_AT_type attribute of a DWARF debugging
* information entry.
*
* See @ref drgn_type_from_dwarf_child() and @ref
* drgn_type_from_dwarf_internal().
*/
struct drgn_error *
drgn_type_from_dwarf_child_internal(struct drgn_dwarf_type_cache *dtcache,
Dwarf_Die *parent_die, const char *tag_name,
bool can_be_void,
bool can_be_incomplete_array,
bool *is_incomplete_array_ret,
struct drgn_qualified_type *ret);
/**
* Parse a type from the @c DW_AT_type attribute of a DWARF debugging
* information entry.
*
* @param[in] dtcache DWARF type cache.
* @param[in] parent_die Parent DIE.
* @param[in] can_be_void Whether the @c DW_AT_type attribute may be missing,
* which is interpreted as a void type. If this is false and the @c DW_AT_type
* attribute is missing, an error is returned.
* @param[in] tag_name Spelling of the DWARF tag of @p parent_die. Used for
* error messages.
* @param[out] ret Returned type.
* @return @c NULL on success, non-@c NULL on error.
*/
static inline struct drgn_error *
drgn_type_from_dwarf_child(struct drgn_dwarf_type_cache *dtcache,
Dwarf_Die *parent_die, const char *tag_name,
bool can_be_void, struct drgn_qualified_type *ret)
{
return drgn_type_from_dwarf_child_internal(dtcache, parent_die,
tag_name, can_be_void, true,
NULL, ret);
}
/** @} */
#endif /* DRGN_TYPE_INDEX_H */