aboutsummaryrefslogtreecommitdiff
path: root/dwarf_loader.c
diff options
context:
space:
mode:
Diffstat (limited to 'dwarf_loader.c')
-rw-r--r--dwarf_loader.c1405
1 files changed, 1036 insertions, 369 deletions
diff --git a/dwarf_loader.c b/dwarf_loader.c
index 4638df7..e30b03c 100644
--- a/dwarf_loader.c
+++ b/dwarf_loader.c
@@ -12,7 +12,8 @@
#include <fcntl.h>
#include <fnmatch.h>
#include <libelf.h>
-#include <obstack.h>
+#include <limits.h>
+#include <pthread.h>
#include <search.h>
#include <stdio.h>
#include <stdlib.h>
@@ -23,11 +24,8 @@
#include "list.h"
#include "dwarves.h"
#include "dutil.h"
-#include "pahole_strings.h"
#include "hash.h"
-struct strings *strings;
-
#ifndef DW_AT_alignment
#define DW_AT_alignment 0x88
#endif
@@ -41,7 +39,28 @@ struct strings *strings;
#define DW_TAG_GNU_call_site_parameter 0x410a
#endif
-#define hashtags__fn(key) hash_64(key, HASHTAGS__BITS)
+#ifndef DW_TAG_call_site
+#define DW_TAG_call_site 0x48
+#define DW_TAG_call_site_parameter 0x49
+#endif
+
+#ifndef DW_FORM_implicit_const
+#define DW_FORM_implicit_const 0x21
+#endif
+
+#ifndef DW_OP_addrx
+#define DW_OP_addrx 0xa1
+#endif
+
+static pthread_mutex_t libdw__lock = PTHREAD_MUTEX_INITIALIZER;
+
+static uint32_t hashtags__bits = 12;
+static uint32_t max_hashtags__bits = 21;
+
+static uint32_t hashtags__fn(Dwarf_Off key)
+{
+ return hash_64(key, hashtags__bits);
+}
bool no_bitfield_type_recode = true;
@@ -79,8 +98,8 @@ struct dwarf_tag {
};
struct tag *tag;
uint32_t small_id;
- strings_t decl_file;
uint16_t decl_line;
+ const char *decl_file;
};
static dwarf_off_ref dwarf_tag__spec(struct dwarf_tag *dtag)
@@ -93,40 +112,77 @@ static void dwarf_tag__set_spec(struct dwarf_tag *dtag, dwarf_off_ref spec)
*(dwarf_off_ref *)(dtag + 1) = spec;
}
-#define HASHTAGS__BITS 15
-#define HASHTAGS__SIZE (1UL << HASHTAGS__BITS)
-
-#define obstack_chunk_alloc malloc
-#define obstack_chunk_free free
-
-static void *obstack_zalloc(struct obstack *obstack, size_t size)
-{
- void *o = obstack_alloc(obstack, size);
-
- if (o)
- memset(o, 0, size);
- return o;
-}
-
struct dwarf_cu {
- struct hlist_head hash_tags[HASHTAGS__SIZE];
- struct hlist_head hash_types[HASHTAGS__SIZE];
- struct obstack obstack;
+ struct hlist_head *hash_tags;
+ struct hlist_head *hash_types;
+ struct dwarf_tag *last_type_lookup;
struct cu *cu;
struct dwarf_cu *type_unit;
};
-static void dwarf_cu__init(struct dwarf_cu *dcu)
+static int dwarf_cu__init(struct dwarf_cu *dcu, struct cu *cu)
{
+ static struct dwarf_tag sentinel_dtag = { .id = ULLONG_MAX, };
+ uint64_t hashtags_size = 1UL << hashtags__bits;
+
+ dcu->cu = cu;
+
+ dcu->hash_tags = cu__malloc(cu, sizeof(struct hlist_head) * hashtags_size);
+ if (!dcu->hash_tags)
+ return -ENOMEM;
+
+ dcu->hash_types = cu__malloc(cu, sizeof(struct hlist_head) * hashtags_size);
+ if (!dcu->hash_types) {
+ cu__free(cu, dcu->hash_tags);
+ return -ENOMEM;
+ }
+
unsigned int i;
- for (i = 0; i < HASHTAGS__SIZE; ++i) {
+ for (i = 0; i < hashtags_size; ++i) {
INIT_HLIST_HEAD(&dcu->hash_tags[i]);
INIT_HLIST_HEAD(&dcu->hash_types[i]);
}
- obstack_init(&dcu->obstack);
dcu->type_unit = NULL;
+ // To avoid a per-lookup check against NULL in dwarf_cu__find_type_by_ref()
+ dcu->last_type_lookup = &sentinel_dtag;
+ return 0;
+}
+
+static struct dwarf_cu *dwarf_cu__new(struct cu *cu)
+{
+ struct dwarf_cu *dwarf_cu = cu__zalloc(cu, sizeof(*dwarf_cu));
+
+ if (dwarf_cu != NULL && dwarf_cu__init(dwarf_cu, cu) != 0) {
+ cu__free(cu, dwarf_cu);
+ dwarf_cu = NULL;
+ }
+
+ return dwarf_cu;
+}
+
+static void dwarf_cu__delete(struct cu *cu)
+{
+ if (cu == NULL || cu->priv == NULL)
+ return;
+
+ struct dwarf_cu *dcu = cu->priv;
+
+ // dcu->hash_tags & dcu->hash_types are on cu->obstack
+ cu__free(cu, dcu);
+ cu->priv = NULL;
+}
+
+static void __tag__print_type_not_found(struct tag *tag, const char *func)
+{
+ struct dwarf_tag *dtag = tag->priv;
+ fprintf(stderr, "%s: couldn't find %#llx type for %#llx (%s)!\n", func,
+ (unsigned long long)dtag->type.off, (unsigned long long)dtag->id,
+ dwarf_tag_name(tag->tag));
}
+#define tag__print_type_not_found(tag) \
+ __tag__print_type_not_found(tag, __func__)
+
static void hashtags__hash(struct hlist_head *hashtable,
struct dwarf_tag *dtag)
{
@@ -142,7 +198,7 @@ static struct dwarf_tag *hashtags__find(const struct hlist_head *hashtable,
struct dwarf_tag *tpos;
struct hlist_node *pos;
- uint16_t bucket = hashtags__fn(id);
+ uint32_t bucket = hashtags__fn(id);
const struct hlist_head *head = hashtable + bucket;
hlist_for_each_entry(tpos, pos, head, hash_node) {
@@ -173,7 +229,7 @@ static struct dwarf_tag *dwarf_cu__find_tag_by_ref(const struct dwarf_cu *cu,
return hashtags__find(cu->hash_tags, ref->off);
}
-static struct dwarf_tag *dwarf_cu__find_type_by_ref(const struct dwarf_cu *dcu,
+static struct dwarf_tag *dwarf_cu__find_type_by_ref(struct dwarf_cu *dcu,
const struct dwarf_off_ref *ref)
{
if (dcu == NULL)
@@ -184,14 +240,21 @@ static struct dwarf_tag *dwarf_cu__find_type_by_ref(const struct dwarf_cu *dcu,
return NULL;
}
}
- return hashtags__find(dcu->hash_types, ref->off);
-}
-extern struct strings *strings;
+ if (dcu->last_type_lookup->id == ref->off)
+ return dcu->last_type_lookup;
+
+ struct dwarf_tag *dtag = hashtags__find(dcu->hash_types, ref->off);
+
+ if (dtag)
+ dcu->last_type_lookup = dtag;
+
+ return dtag;
+}
static void *memdup(const void *src, size_t len, struct cu *cu)
{
- void *s = obstack_alloc(&cu->obstack, len);
+ void *s = cu__malloc(cu, len);
if (s != NULL)
memcpy(s, src, len);
return s;
@@ -248,6 +311,7 @@ static uint64_t attr_numeric(Dwarf_Die *die, uint32_t name)
return addr;
}
break;
+ case DW_FORM_implicit_const:
case DW_FORM_data1:
case DW_FORM_data2:
case DW_FORM_data4:
@@ -274,7 +338,12 @@ static uint64_t attr_numeric(Dwarf_Die *die, uint32_t name)
return 0;
}
-static uint64_t dwarf_expr(const uint8_t *expr, uint32_t len __unused)
+static uint64_t attr_alignment(Dwarf_Die *die, struct conf_load *conf)
+{
+ return conf->ignore_alignment_attr ? 0 : attr_numeric(die, DW_AT_alignment);
+}
+
+static uint64_t dwarf_expr(const uint8_t *expr, uint32_t len __maybe_unused)
{
/* Common case: offset from start of the class */
if (expr[0] == DW_OP_plus_uconst ||
@@ -290,15 +359,12 @@ static uint64_t dwarf_expr(const uint8_t *expr, uint32_t len __unused)
return UINT64_MAX;
}
-static Dwarf_Off attr_offset(Dwarf_Die *die, const uint32_t name)
+static Dwarf_Off __attr_offset(Dwarf_Attribute *attr)
{
- Dwarf_Attribute attr;
Dwarf_Block block;
- if (dwarf_attr(die, name, &attr) == NULL)
- return 0;
-
- switch (dwarf_whatform(&attr)) {
+ switch (dwarf_whatform(attr)) {
+ case DW_FORM_implicit_const:
case DW_FORM_data1:
case DW_FORM_data2:
case DW_FORM_data4:
@@ -306,24 +372,41 @@ static Dwarf_Off attr_offset(Dwarf_Die *die, const uint32_t name)
case DW_FORM_sdata:
case DW_FORM_udata: {
Dwarf_Word value;
- if (dwarf_formudata(&attr, &value) == 0)
+ if (dwarf_formudata(attr, &value) == 0)
return value;
break;
}
default:
- if (dwarf_formblock(&attr, &block) == 0)
+ if (dwarf_formblock(attr, &block) == 0)
return dwarf_expr(block.data, block.length);
}
return 0;
}
-static const char *attr_string(Dwarf_Die *die, uint32_t name)
+static Dwarf_Off attr_offset(Dwarf_Die *die, const uint32_t name)
{
Dwarf_Attribute attr;
- if (dwarf_attr(die, name, &attr) != NULL)
- return dwarf_formstring(&attr);
- return NULL;
+
+ if (dwarf_attr(die, name, &attr) == NULL)
+ return 0;
+
+ return __attr_offset(&attr);
+}
+
+static const char *attr_string(Dwarf_Die *die, uint32_t name, struct conf_load *conf __maybe_unused)
+{
+ const char *str = NULL;
+ Dwarf_Attribute attr;
+
+ if (dwarf_attr(die, name, &attr) != NULL) {
+ str = dwarf_formstring(&attr);
+
+ if (conf && conf->kabi_prefix && str && strncmp(str, conf->kabi_prefix, conf->kabi_prefix_len) == 0)
+ return conf->kabi_prefix;
+ }
+
+ return str;
}
static struct dwarf_off_ref attr_type(Dwarf_Die *die, uint32_t attr_name)
@@ -346,8 +429,19 @@ static int attr_location(Dwarf_Die *die, Dwarf_Op **expr, size_t *exprlen)
{
Dwarf_Attribute attr;
if (dwarf_attr(die, DW_AT_location, &attr) != NULL) {
- if (dwarf_getlocation(&attr, expr, exprlen) == 0)
+ if (dwarf_getlocation(&attr, expr, exprlen) == 0) {
+ /* DW_OP_addrx needs additional lookup for real addr. */
+ if (*exprlen != 0 && expr[0]->atom == DW_OP_addrx) {
+ Dwarf_Attribute addr_attr;
+ dwarf_getlocation_attr(&attr, expr[0], &addr_attr);
+
+ Dwarf_Addr address;
+ dwarf_formaddr (&addr_attr, &address);
+
+ expr[0]->number = address;
+ }
return 0;
+ }
}
return 1;
@@ -355,13 +449,12 @@ static int attr_location(Dwarf_Die *die, Dwarf_Op **expr, size_t *exprlen)
static void *__tag__alloc(struct dwarf_cu *dcu, size_t size, bool spec)
{
- struct dwarf_tag *dtag = obstack_zalloc(&dcu->obstack,
- (sizeof(*dtag) +
- (spec ? sizeof(dwarf_off_ref) : 0)));
+ struct dwarf_tag *dtag = cu__zalloc(dcu->cu, (sizeof(*dtag) + (spec ? sizeof(dwarf_off_ref) : 0)));
+
if (dtag == NULL)
return NULL;
- struct tag *tag = obstack_zalloc(&dcu->cu->obstack, size);
+ struct tag *tag = cu__zalloc(dcu->cu, size);
if (tag == NULL)
return NULL;
@@ -402,19 +495,22 @@ static void tag__init(struct tag *tag, struct cu *cu, Dwarf_Die *die)
tag->recursivity_level = 0;
if (cu->extra_dbg_info) {
+ pthread_mutex_lock(&libdw__lock);
+
int32_t decl_line;
const char *decl_file = dwarf_decl_file(die);
- static const char *last_decl_file;
- static uint32_t last_decl_file_idx;
+ static const char *last_decl_file, *last_decl_file_ptr;
- if (decl_file != last_decl_file) {
- last_decl_file_idx = strings__add(strings, decl_file);
- last_decl_file = decl_file;
+ if (decl_file != last_decl_file_ptr) {
+ last_decl_file = decl_file ? strdup(decl_file) : NULL;
+ last_decl_file_ptr = decl_file;
}
- dtag->decl_file = last_decl_file_idx;
+ dtag->decl_file = last_decl_file;
dwarf_decl_line(die, &decl_line);
dtag->decl_line = decl_line;
+
+ pthread_mutex_unlock(&libdw__lock);
}
INIT_LIST_HEAD(&tag->node);
@@ -444,19 +540,30 @@ static struct ptr_to_member_type *ptr_to_member_type__new(Dwarf_Die *die,
return ptr;
}
-static struct base_type *base_type__new(Dwarf_Die *die, struct cu *cu)
+static uint8_t encoding_to_float_type(uint64_t encoding)
+{
+ switch (encoding) {
+ case DW_ATE_complex_float: return BT_FP_CMPLX;
+ case DW_ATE_float: return BT_FP_SINGLE;
+ case DW_ATE_imaginary_float: return BT_FP_IMGRY;
+ default: return 0;
+ }
+}
+
+static struct base_type *base_type__new(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
struct base_type *bt = tag__alloc(cu, sizeof(*bt));
if (bt != NULL) {
tag__init(&bt->tag, cu, die);
- bt->name = strings__add(strings, attr_string(die, DW_AT_name));
+ bt->name = attr_string(die, DW_AT_name, conf);
bt->bit_size = attr_numeric(die, DW_AT_byte_size) * 8;
uint64_t encoding = attr_numeric(die, DW_AT_encoding);
bt->is_bool = encoding == DW_ATE_boolean;
bt->is_signed = encoding == DW_ATE_signed;
bt->is_varargs = false;
bt->name_has_encoding = true;
+ bt->float_type = encoding_to_float_type(encoding);
}
return bt;
@@ -491,32 +598,32 @@ static struct string_type *string_type__new(Dwarf_Die *die, struct cu *cu)
}
static void namespace__init(struct namespace *namespace, Dwarf_Die *die,
- struct cu *cu)
+ struct cu *cu, struct conf_load *conf)
{
tag__init(&namespace->tag, cu, die);
INIT_LIST_HEAD(&namespace->tags);
- namespace->sname = 0;
- namespace->name = strings__add(strings, attr_string(die, DW_AT_name));
+ INIT_LIST_HEAD(&namespace->annots);
+ namespace->name = attr_string(die, DW_AT_name, conf);
namespace->nr_tags = 0;
namespace->shared_tags = 0;
}
-static struct namespace *namespace__new(Dwarf_Die *die, struct cu *cu)
+static struct namespace *namespace__new(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
struct namespace *namespace = tag__alloc(cu, sizeof(*namespace));
if (namespace != NULL)
- namespace__init(namespace, die, cu);
+ namespace__init(namespace, die, cu, conf);
return namespace;
}
-static void type__init(struct type *type, Dwarf_Die *die, struct cu *cu)
+static void type__init(struct type *type, Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
- namespace__init(&type->namespace, die, cu);
+ namespace__init(&type->namespace, die, cu, conf);
__type__init(type);
type->size = attr_numeric(die, DW_AT_byte_size);
- type->alignment = attr_numeric(die, DW_AT_alignment);
+ type->alignment = attr_alignment(die, conf);
type->declaration = attr_numeric(die, DW_AT_declaration);
dwarf_tag__set_spec(type->namespace.tag.priv,
attr_type(die, DW_AT_specification));
@@ -527,23 +634,23 @@ static void type__init(struct type *type, Dwarf_Die *die, struct cu *cu)
type->nr_static_members = 0;
}
-static struct type *type__new(Dwarf_Die *die, struct cu *cu)
+static struct type *type__new(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
struct type *type = tag__alloc_with_spec(cu, sizeof(*type));
if (type != NULL)
- type__init(type, die, cu);
+ type__init(type, die, cu, conf);
return type;
}
-static struct enumerator *enumerator__new(Dwarf_Die *die, struct cu *cu)
+static struct enumerator *enumerator__new(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
struct enumerator *enumerator = tag__alloc(cu, sizeof(*enumerator));
if (enumerator != NULL) {
tag__init(&enumerator->tag, cu, die);
- enumerator->name = strings__add(strings, attr_string(die, DW_AT_name));
+ enumerator->name = attr_string(die, DW_AT_name, conf);
enumerator->value = attr_numeric(die, DW_AT_const_value);
}
@@ -560,6 +667,7 @@ static enum vscope dwarf__location(Dwarf_Die *die, uint64_t *addr, struct locati
Dwarf_Op *expr = location->expr;
switch (expr->atom) {
case DW_OP_addr:
+ case DW_OP_addrx:
scope = VSCOPE_GLOBAL;
*addr = expr[0].number;
break;
@@ -592,7 +700,7 @@ const char *variable__scope_str(const struct variable *var)
return "unknown";
}
-static struct variable *variable__new(Dwarf_Die *die, struct cu *cu)
+static struct variable *variable__new(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
struct variable *var;
bool has_specification;
@@ -606,12 +714,14 @@ static struct variable *variable__new(Dwarf_Die *die, struct cu *cu)
if (var != NULL) {
tag__init(&var->ip.tag, cu, die);
- var->name = strings__add(strings, attr_string(die, DW_AT_name));
+ var->name = attr_string(die, DW_AT_name, conf);
/* variable is visible outside of its enclosing cu */
var->external = dwarf_hasattr(die, DW_AT_external);
/* non-defining declaration of an object */
var->declaration = dwarf_hasattr(die, DW_AT_declaration);
+ var->has_specification = has_specification;
var->scope = VSCOPE_UNKNOWN;
+ INIT_LIST_HEAD(&var->annots);
var->ip.addr = 0;
if (!var->declaration && cu->has_addr_info)
var->scope = dwarf__location(die, &var->ip.addr, &var->location);
@@ -630,21 +740,25 @@ static int tag__recode_dwarf_bitfield(struct tag *tag, struct cu *cu, uint16_t b
type_id_t short_id;
struct tag *recoded;
/* in all the cases the name is at the same offset */
- strings_t name = tag__namespace(tag)->name;
+ const char *name = namespace__name(tag__namespace(tag));
switch (tag->tag) {
case DW_TAG_typedef: {
const struct dwarf_tag *dtag = tag->priv;
- struct dwarf_tag *dtype = dwarf_cu__find_type_by_ref(cu->priv,
- &dtag->type);
+ struct dwarf_tag *dtype = dwarf_cu__find_type_by_ref(cu->priv, &dtag->type);
+
+ if (dtype == NULL) {
+ tag__print_type_not_found(tag);
+ return -ENOENT;
+ }
+
struct tag *type = dtype->tag;
id = tag__recode_dwarf_bitfield(type, cu, bit_size);
if (id < 0)
return id;
- struct type *new_typedef = obstack_zalloc(&cu->obstack,
- sizeof(*new_typedef));
+ struct type *new_typedef = cu__zalloc(cu, sizeof(*new_typedef));
if (new_typedef == NULL)
return -ENOMEM;
@@ -659,13 +773,19 @@ static int tag__recode_dwarf_bitfield(struct tag *tag, struct cu *cu, uint16_t b
case DW_TAG_volatile_type: {
const struct dwarf_tag *dtag = tag->priv;
struct dwarf_tag *dtype = dwarf_cu__find_type_by_ref(cu->priv, &dtag->type);
+
+ if (dtype == NULL) {
+ tag__print_type_not_found(tag);
+ return -ENOENT;
+ }
+
struct tag *type = dtype->tag;
id = tag__recode_dwarf_bitfield(type, cu, bit_size);
- if (id == tag->type)
+ if (id >= 0 && (uint32_t)id == tag->type)
return id;
- recoded = obstack_zalloc(&cu->obstack, sizeof(*recoded));
+ recoded = cu__zalloc(cu, sizeof(*recoded));
if (recoded == NULL)
return -ENOMEM;
@@ -680,19 +800,18 @@ static int tag__recode_dwarf_bitfield(struct tag *tag, struct cu *cu, uint16_t b
* the dwarf_cu as in dwarf there are no such things
* as base_types of less than 8 bits, etc.
*/
- recoded = cu__find_base_type_by_sname_and_size(cu, name, bit_size, &short_id);
+ recoded = cu__find_base_type_by_name_and_size(cu, name, bit_size, &short_id);
if (recoded != NULL)
return short_id;
- struct base_type *new_bt = obstack_zalloc(&cu->obstack,
- sizeof(*new_bt));
+ struct base_type *new_bt = cu__zalloc(cu, sizeof(*new_bt));
if (new_bt == NULL)
return -ENOMEM;
recoded = (struct tag *)new_bt;
recoded->tag = DW_TAG_base_type;
recoded->top_level = 1;
- new_bt->name = name;
+ new_bt->name = strdup(name);
new_bt->bit_size = bit_size;
break;
@@ -702,12 +821,12 @@ static int tag__recode_dwarf_bitfield(struct tag *tag, struct cu *cu, uint16_t b
* the dwarf_cu as in dwarf there are no such things
* as enumeration_types of less than 8 bits, etc.
*/
- recoded = cu__find_enumeration_by_sname_and_size(cu, name, bit_size, &short_id);
+ recoded = cu__find_enumeration_by_name_and_size(cu, name, bit_size, &short_id);
if (recoded != NULL)
return short_id;
struct type *alias = tag__type(tag);
- struct type *new_enum = obstack_zalloc(&cu->obstack, sizeof(*new_enum));
+ struct type *new_enum = cu__zalloc(cu, sizeof(*new_enum));
if (new_enum == NULL)
return -ENOMEM;
@@ -720,13 +839,13 @@ static int tag__recode_dwarf_bitfield(struct tag *tag, struct cu *cu, uint16_t b
*/
new_enum->namespace.tags.next = &alias->namespace.tags;
new_enum->namespace.shared_tags = 1;
- new_enum->namespace.name = name;
+ new_enum->namespace.name = strdup(name);
new_enum->size = bit_size;
break;
default:
fprintf(stderr, "%s: tag=%s, name=%s, bit_size=%d\n",
__func__, dwarf_tag_name(tag->tag),
- strings__ptr(strings, name), bit_size);
+ name, bit_size);
return -EINVAL;
}
@@ -734,10 +853,55 @@ static int tag__recode_dwarf_bitfield(struct tag *tag, struct cu *cu, uint16_t b
if (cu__add_tag(cu, recoded, &new_id) == 0)
return new_id;
- obstack_free(&cu->obstack, recoded);
+ free(recoded);
return -ENOMEM;
}
+static int add_llvm_annotation(Dwarf_Die *die, int component_idx, struct conf_load *conf,
+ struct list_head *head)
+{
+ struct llvm_annotation *annot;
+ const char *name;
+
+ if (conf->skip_encoding_btf_decl_tag)
+ return 0;
+
+ /* Only handle btf_decl_tag annotation for now. */
+ name = attr_string(die, DW_AT_name, conf);
+ if (strcmp(name, "btf_decl_tag") != 0)
+ return 0;
+
+ annot = zalloc(sizeof(*annot));
+ if (!annot)
+ return -ENOMEM;
+
+ annot->value = attr_string(die, DW_AT_const_value, conf);
+ annot->component_idx = component_idx;
+ list_add_tail(&annot->node, head);
+ return 0;
+}
+
+static int add_child_llvm_annotations(Dwarf_Die *die, int component_idx,
+ struct conf_load *conf, struct list_head *head)
+{
+ Dwarf_Die child;
+ int ret;
+
+ if (!dwarf_haschildren(die) || dwarf_child(die, &child) != 0)
+ return 0;
+
+ die = &child;
+ do {
+ if (dwarf_tag(die) == DW_TAG_LLVM_annotation) {
+ ret = add_llvm_annotation(die, component_idx, conf, head);
+ if (ret)
+ return ret;
+ }
+ } while (dwarf_siblingof(die, die) == 0);
+
+ return 0;
+}
+
int class_member__dwarf_recode_bitfield(struct class_member *member,
struct cu *cu)
{
@@ -757,58 +921,76 @@ int class_member__dwarf_recode_bitfield(struct class_member *member,
}
static struct class_member *class_member__new(Dwarf_Die *die, struct cu *cu,
- bool in_union)
+ bool in_union, struct conf_load *conf)
{
struct class_member *member = tag__alloc(cu, sizeof(*member));
if (member != NULL) {
tag__init(&member->tag, cu, die);
- member->name = strings__add(strings, attr_string(die, DW_AT_name));
- member->is_static = !in_union && !dwarf_hasattr(die, DW_AT_data_member_location);
- member->const_value = attr_numeric(die, DW_AT_const_value);
- member->alignment = attr_numeric(die, DW_AT_alignment);
- member->byte_offset = attr_offset(die, DW_AT_data_member_location);
- /*
- * Bit offset calculated here is valid only for byte-aligned
- * fields. For bitfields on little-endian archs we need to
- * adjust them taking into account byte size of the field,
- * which might not be yet known. So we'll re-calculate bit
- * offset later, in class_member__cache_byte_size.
- */
- member->bit_offset = member->byte_offset * 8;
+ member->name = attr_string(die, DW_AT_name, conf);
+ member->alignment = attr_alignment(die, conf);
+
+ Dwarf_Attribute attr;
+
+ member->has_bit_offset = dwarf_attr(die, DW_AT_data_bit_offset, &attr) != NULL;
+
+ if (member->has_bit_offset) {
+ member->bit_offset = __attr_offset(&attr);
+ // byte_offset and bitfield_offset will be recalculated later, when
+ // we discover the size of this bitfield base type.
+ } else {
+ if (dwarf_attr(die, DW_AT_data_member_location, &attr) != NULL) {
+ member->byte_offset = __attr_offset(&attr);
+ } else {
+ member->is_static = !in_union;
+ }
+
+ /*
+ * Bit offset calculated here is valid only for byte-aligned
+ * fields. For bitfields on little-endian archs we need to
+ * adjust them taking into account byte size of the field,
+ * which might not be yet known. So we'll re-calculate bit
+ * offset later, in class_member__cache_byte_size.
+ */
+ member->bit_offset = member->byte_offset * 8;
+ member->bitfield_offset = attr_numeric(die, DW_AT_bit_offset);
+ }
+
/*
* If DW_AT_byte_size is not present, byte size will be
* determined later in class_member__cache_byte_size using
* base integer/enum type
*/
member->byte_size = attr_numeric(die, DW_AT_byte_size);
- member->bitfield_offset = attr_numeric(die, DW_AT_bit_offset);
member->bitfield_size = attr_numeric(die, DW_AT_bit_size);
member->bit_hole = 0;
member->bitfield_end = 0;
member->visited = 0;
- member->accessibility = attr_numeric(die, DW_AT_accessibility);
- member->virtuality = attr_numeric(die, DW_AT_virtuality);
+
+ if (!cu__is_c(cu)) {
+ member->accessibility = attr_numeric(die, DW_AT_accessibility);
+ member->const_value = attr_numeric(die, DW_AT_const_value);
+ member->virtuality = attr_numeric(die, DW_AT_virtuality);
+ }
member->hole = 0;
}
return member;
}
-static struct parameter *parameter__new(Dwarf_Die *die, struct cu *cu)
+static struct parameter *parameter__new(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
struct parameter *parm = tag__alloc(cu, sizeof(*parm));
if (parm != NULL) {
tag__init(&parm->tag, cu, die);
- parm->name = strings__add(strings, attr_string(die, DW_AT_name));
+ parm->name = attr_string(die, DW_AT_name, conf);
}
return parm;
}
-static struct inline_expansion *inline_expansion__new(Dwarf_Die *die,
- struct cu *cu)
+static struct inline_expansion *inline_expansion__new(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
struct inline_expansion *exp = tag__alloc(cu, sizeof(*exp));
@@ -816,8 +998,7 @@ static struct inline_expansion *inline_expansion__new(Dwarf_Die *die,
struct dwarf_tag *dtag = exp->ip.tag.priv;
tag__init(&exp->ip.tag, cu, die);
- dtag->decl_file =
- strings__add(strings, attr_string(die, DW_AT_call_file));
+ dtag->decl_file = attr_string(die, DW_AT_call_file, conf);
dtag->decl_line = attr_numeric(die, DW_AT_call_line);
dtag->type = attr_type(die, DW_AT_abstract_origin);
exp->ip.addr = 0;
@@ -853,13 +1034,13 @@ out:
return exp;
}
-static struct label *label__new(Dwarf_Die *die, struct cu *cu)
+static struct label *label__new(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
struct label *label = tag__alloc(cu, sizeof(*label));
if (label != NULL) {
tag__init(&label->ip.tag, cu, die);
- label->name = strings__add(strings, attr_string(die, DW_AT_name));
+ label->name = attr_string(die, DW_AT_name, conf);
if (!cu->has_addr_info || dwarf_lowpc(die, &label->ip.addr))
label->ip.addr = 0;
}
@@ -867,12 +1048,12 @@ static struct label *label__new(Dwarf_Die *die, struct cu *cu)
return label;
}
-static struct class *class__new(Dwarf_Die *die, struct cu *cu)
+static struct class *class__new(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
struct class *class = tag__alloc_with_spec(cu, sizeof(*class));
if (class != NULL) {
- type__init(&class->type, die, cu);
+ type__init(&class->type, die, cu, conf);
INIT_LIST_HEAD(&class->vtable);
class->nr_vtable_entries =
class->nr_holes =
@@ -921,9 +1102,10 @@ static struct lexblock *lexblock__new(Dwarf_Die *die, struct cu *cu)
static void ftype__init(struct ftype *ftype, Dwarf_Die *die, struct cu *cu)
{
+#ifndef NDEBUG
const uint16_t tag = dwarf_tag(die);
assert(tag == DW_TAG_subprogram || tag == DW_TAG_subroutine_type);
-
+#endif
tag__init(&ftype->tag, cu, die);
INIT_LIST_HEAD(&ftype->parms);
ftype->nr_parms = 0;
@@ -940,15 +1122,15 @@ static struct ftype *ftype__new(Dwarf_Die *die, struct cu *cu)
return ftype;
}
-static struct function *function__new(Dwarf_Die *die, struct cu *cu)
+static struct function *function__new(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
struct function *func = tag__alloc_with_spec(cu, sizeof(*func));
if (func != NULL) {
ftype__init(&func->proto, die, cu);
lexblock__init(&func->lexblock, cu, die);
- func->name = strings__add(strings, attr_string(die, DW_AT_name));
- func->linkage_name = strings__add(strings, attr_string(die, DW_AT_MIPS_linkage_name));
+ func->name = attr_string(die, DW_AT_name, conf);
+ func->linkage_name = attr_string(die, DW_AT_MIPS_linkage_name, conf);
func->inlined = attr_numeric(die, DW_AT_inline);
func->declaration = dwarf_hasattr(die, DW_AT_declaration);
func->external = dwarf_hasattr(die, DW_AT_external);
@@ -958,6 +1140,7 @@ static struct function *function__new(Dwarf_Die *die, struct cu *cu)
func->accessibility = attr_numeric(die, DW_AT_accessibility);
func->virtuality = attr_numeric(die, DW_AT_virtuality);
INIT_LIST_HEAD(&func->vtable_node);
+ INIT_LIST_HEAD(&func->annots);
INIT_LIST_HEAD(&func->tool_node);
func->vtable_entry = -1;
if (dwarf_hasattr(die, DW_AT_vtable_elem_location))
@@ -1005,10 +1188,10 @@ static struct tag unsupported_tag;
#define cu__tag_not_handled(die) __cu__tag_not_handled(die, __FUNCTION__)
static struct tag *__die__process_tag(Dwarf_Die *die, struct cu *cu,
- int toplevel, const char *fn);
+ int toplevel, const char *fn, struct conf_load *conf);
-#define die__process_tag(die, cu, toplevel) \
- __die__process_tag(die, cu, toplevel, __FUNCTION__)
+#define die__process_tag(die, cu, toplevel, conf_load) \
+ __die__process_tag(die, cu, toplevel, __FUNCTION__, conf_load)
static struct tag *die__create_new_tag(Dwarf_Die *die, struct cu *cu)
{
@@ -1023,6 +1206,89 @@ static struct tag *die__create_new_tag(Dwarf_Die *die, struct cu *cu)
return tag;
}
+static struct btf_type_tag_ptr_type *die__create_new_btf_type_tag_ptr_type(Dwarf_Die *die, struct cu *cu)
+{
+ struct btf_type_tag_ptr_type *tag;
+
+ tag = tag__alloc_with_spec(cu, sizeof(struct btf_type_tag_ptr_type));
+ if (tag == NULL)
+ return NULL;
+
+ tag__init(&tag->tag, cu, die);
+ tag->tag.has_btf_type_tag = true;
+ INIT_LIST_HEAD(&tag->tags);
+ return tag;
+}
+
+static struct btf_type_tag_type *die__create_new_btf_type_tag_type(Dwarf_Die *die, struct cu *cu,
+ struct conf_load *conf)
+{
+ struct btf_type_tag_type *tag;
+
+ tag = tag__alloc_with_spec(cu, sizeof(struct btf_type_tag_type));
+ if (tag == NULL)
+ return NULL;
+
+ tag__init(&tag->tag, cu, die);
+ tag->value = attr_string(die, DW_AT_const_value, conf);
+ return tag;
+}
+
+static struct tag *die__create_new_pointer_tag(Dwarf_Die *die, struct cu *cu,
+ struct conf_load *conf)
+{
+ struct btf_type_tag_ptr_type *tag = NULL;
+ struct btf_type_tag_type *annot;
+ Dwarf_Die *cdie, child;
+ const char *name;
+ uint32_t id;
+
+ /* If no child tags or skipping btf_type_tag encoding, just create a new tag
+ * and return
+ */
+ if (!dwarf_haschildren(die) || dwarf_child(die, &child) != 0 ||
+ conf->skip_encoding_btf_type_tag)
+ return tag__new(die, cu);
+
+ /* Otherwise, check DW_TAG_LLVM_annotation child tags */
+ cdie = &child;
+ do {
+ if (dwarf_tag(cdie) != DW_TAG_LLVM_annotation)
+ continue;
+
+ /* Only check btf_type_tag annotations */
+ name = attr_string(cdie, DW_AT_name, conf);
+ if (strcmp(name, "btf_type_tag") != 0)
+ continue;
+
+ if (tag == NULL) {
+ /* Create a btf_type_tag_ptr type. */
+ tag = die__create_new_btf_type_tag_ptr_type(die, cu);
+ if (!tag)
+ return NULL;
+ }
+
+ /* Create a btf_type_tag type for this annotation. */
+ annot = die__create_new_btf_type_tag_type(cdie, cu, conf);
+ if (annot == NULL)
+ return NULL;
+
+ if (cu__table_add_tag(cu, &annot->tag, &id) < 0)
+ return NULL;
+
+ struct dwarf_tag *dtag = annot->tag.priv;
+ dtag->small_id = id;
+ cu__hash(cu, &annot->tag);
+
+ /* For a list of DW_TAG_LLVM_annotation like tag1 -> tag2 -> tag3,
+ * the tag->tags contains tag3 -> tag2 -> tag1.
+ */
+ list_add(&annot->node, &tag->tags);
+ } while (dwarf_siblingof(cdie, cdie) == 0);
+
+ return tag ? &tag->tag : tag__new(die, cu);
+}
+
static struct tag *die__create_new_ptr_to_member_type(Dwarf_Die *die,
struct cu *cu)
{
@@ -1032,18 +1298,18 @@ static struct tag *die__create_new_ptr_to_member_type(Dwarf_Die *die,
}
static int die__process_class(Dwarf_Die *die,
- struct type *class, struct cu *cu);
+ struct type *class, struct cu *cu, struct conf_load *conf);
-static struct tag *die__create_new_class(Dwarf_Die *die, struct cu *cu)
+static struct tag *die__create_new_class(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
Dwarf_Die child;
- struct class *class = class__new(die, cu);
+ struct class *class = class__new(die, cu, conf);
if (class != NULL &&
dwarf_haschildren(die) != 0 &&
dwarf_child(die, &child) == 0) {
- if (die__process_class(&child, &class->type, cu) != 0) {
- class__delete(class, cu);
+ if (die__process_class(&child, &class->type, cu, conf) != 0) {
+ class__delete(class);
class = NULL;
}
}
@@ -1052,18 +1318,18 @@ static struct tag *die__create_new_class(Dwarf_Die *die, struct cu *cu)
}
static int die__process_namespace(Dwarf_Die *die, struct namespace *namespace,
- struct cu *cu);
+ struct cu *cu, struct conf_load *conf);
-static struct tag *die__create_new_namespace(Dwarf_Die *die, struct cu *cu)
+static struct tag *die__create_new_namespace(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
Dwarf_Die child;
- struct namespace *namespace = namespace__new(die, cu);
+ struct namespace *namespace = namespace__new(die, cu, conf);
if (namespace != NULL &&
dwarf_haschildren(die) != 0 &&
dwarf_child(die, &child) == 0) {
- if (die__process_namespace(&child, namespace, cu) != 0) {
- namespace__delete(namespace, cu);
+ if (die__process_namespace(&child, namespace, cu, conf) != 0) {
+ namespace__delete(namespace);
namespace = NULL;
}
}
@@ -1071,16 +1337,16 @@ static struct tag *die__create_new_namespace(Dwarf_Die *die, struct cu *cu)
return namespace ? &namespace->tag : NULL;
}
-static struct tag *die__create_new_union(Dwarf_Die *die, struct cu *cu)
+static struct tag *die__create_new_union(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
Dwarf_Die child;
- struct type *utype = type__new(die, cu);
+ struct type *utype = type__new(die, cu, conf);
if (utype != NULL &&
dwarf_haschildren(die) != 0 &&
dwarf_child(die, &child) == 0) {
- if (die__process_class(&child, utype, cu) != 0) {
- type__delete(utype, cu);
+ if (die__process_class(&child, utype, cu, conf) != 0) {
+ type__delete(utype);
utype = NULL;
}
}
@@ -1088,9 +1354,9 @@ static struct tag *die__create_new_union(Dwarf_Die *die, struct cu *cu)
return utype ? &utype->namespace.tag : NULL;
}
-static struct tag *die__create_new_base_type(Dwarf_Die *die, struct cu *cu)
+static struct tag *die__create_new_base_type(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
- struct base_type *base = base_type__new(die, cu);
+ struct base_type *base = base_type__new(die, cu, conf);
if (base == NULL)
return NULL;
@@ -1102,18 +1368,15 @@ static struct tag *die__create_new_base_type(Dwarf_Die *die, struct cu *cu)
return &base->tag;
}
-static struct tag *die__create_new_typedef(Dwarf_Die *die, struct cu *cu)
+static struct tag *die__create_new_typedef(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
- struct type *tdef = type__new(die, cu);
+ struct type *tdef = type__new(die, cu, conf);
if (tdef == NULL)
return NULL;
- if (dwarf_haschildren(die)) {
- struct dwarf_tag *dtag = tdef->namespace.tag.priv;
- fprintf(stderr, "%s: DW_TAG_typedef %llx WITH children!\n",
- __func__, (unsigned long long)dtag->id);
- }
+ if (add_child_llvm_annotations(die, -1, conf, &tdef->namespace.annots))
+ return NULL;
return &tdef->namespace.tag;
}
@@ -1153,7 +1416,7 @@ static struct tag *die__create_new_array(Dwarf_Die *die, struct cu *cu)
return &array->tag;
out_free:
- obstack_free(&cu->obstack, array);
+ free(array);
return NULL;
}
@@ -1170,16 +1433,21 @@ static struct tag *die__create_new_string_type(Dwarf_Die *die, struct cu *cu)
static struct tag *die__create_new_parameter(Dwarf_Die *die,
struct ftype *ftype,
struct lexblock *lexblock,
- struct cu *cu)
+ struct cu *cu, struct conf_load *conf,
+ int param_idx)
{
- struct parameter *parm = parameter__new(die, cu);
+ struct parameter *parm = parameter__new(die, cu, conf);
if (parm == NULL)
return NULL;
- if (ftype != NULL)
+ if (ftype != NULL) {
ftype__add_parameter(ftype, parm);
- else {
+ if (param_idx >= 0) {
+ if (add_child_llvm_annotations(die, param_idx, conf, &(tag__function(&ftype->tag)->annots)))
+ return NULL;
+ }
+ } else {
/*
* DW_TAG_formal_parameters on a non DW_TAG_subprogram nor
* DW_TAG_subroutine_type tag happens sometimes, likely due to
@@ -1197,9 +1465,9 @@ static struct tag *die__create_new_parameter(Dwarf_Die *die,
static struct tag *die__create_new_label(Dwarf_Die *die,
struct lexblock *lexblock,
- struct cu *cu)
+ struct cu *cu, struct conf_load *conf)
{
- struct label *label = label__new(die, cu);
+ struct label *label = label__new(die, cu, conf);
if (label == NULL)
return NULL;
@@ -1208,15 +1476,18 @@ static struct tag *die__create_new_label(Dwarf_Die *die,
return &label->ip.tag;
}
-static struct tag *die__create_new_variable(Dwarf_Die *die, struct cu *cu)
+static struct tag *die__create_new_variable(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
- struct variable *var = variable__new(die, cu);
+ struct variable *var = variable__new(die, cu, conf);
+
+ if (var == NULL || add_child_llvm_annotations(die, -1, conf, &var->annots))
+ return NULL;
- return var ? &var->ip.tag : NULL;
+ return &var->ip.tag;
}
static struct tag *die__create_new_subroutine_type(Dwarf_Die *die,
- struct cu *cu)
+ struct cu *cu, struct conf_load *conf)
{
Dwarf_Die child;
struct ftype *ftype = ftype__new(die, cu);
@@ -1237,13 +1508,13 @@ static struct tag *die__create_new_subroutine_type(Dwarf_Die *die,
tag__print_not_supported(dwarf_tag(die));
continue;
case DW_TAG_formal_parameter:
- tag = die__create_new_parameter(die, ftype, NULL, cu);
+ tag = die__create_new_parameter(die, ftype, NULL, cu, conf, -1);
break;
case DW_TAG_unspecified_parameters:
ftype->unspec_parms = 1;
continue;
default:
- tag = die__process_tag(die, cu, 0);
+ tag = die__process_tag(die, cu, 0, conf);
if (tag == NULL)
goto out_delete;
@@ -1271,16 +1542,16 @@ hash:
out:
return &ftype->tag;
out_delete_tag:
- tag__delete(tag, cu);
+ tag__delete(tag);
out_delete:
- ftype__delete(ftype, cu);
+ ftype__delete(ftype);
return NULL;
}
-static struct tag *die__create_new_enumeration(Dwarf_Die *die, struct cu *cu)
+static struct tag *die__create_new_enumeration(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
Dwarf_Die child;
- struct type *enumeration = type__new(die, cu);
+ struct type *enumeration = type__new(die, cu, conf);
if (enumeration == NULL)
return NULL;
@@ -1304,7 +1575,7 @@ static struct tag *die__create_new_enumeration(Dwarf_Die *die, struct cu *cu)
cu__tag_not_handled(die);
continue;
}
- enumerator = enumerator__new(die, cu);
+ enumerator = enumerator__new(die, cu, conf);
if (enumerator == NULL)
goto out_delete;
@@ -1313,14 +1584,15 @@ static struct tag *die__create_new_enumeration(Dwarf_Die *die, struct cu *cu)
out:
return &enumeration->namespace.tag;
out_delete:
- enumeration__delete(enumeration, cu);
+ enumeration__delete(enumeration);
return NULL;
}
static int die__process_class(Dwarf_Die *die, struct type *class,
- struct cu *cu)
+ struct cu *cu, struct conf_load *conf)
{
const bool is_union = tag__is_union(&class->namespace.tag);
+ int member_idx = 0;
do {
switch (dwarf_tag(die)) {
@@ -1344,7 +1616,7 @@ static int die__process_class(Dwarf_Die *die, struct type *class,
continue;
case DW_TAG_inheritance:
case DW_TAG_member: {
- struct class_member *member = class_member__new(die, cu, is_union);
+ struct class_member *member = class_member__new(die, cu, is_union, conf);
if (member == NULL)
return -ENOMEM;
@@ -1353,7 +1625,7 @@ static int die__process_class(Dwarf_Die *die, struct type *class,
uint32_t id;
if (cu__table_add_tag(cu, &member->tag, &id) < 0) {
- class_member__delete(member, cu);
+ class_member__delete(member);
return -ENOMEM;
}
@@ -1363,10 +1635,17 @@ static int die__process_class(Dwarf_Die *die, struct type *class,
type__add_member(class, member);
cu__hash(cu, &member->tag);
+ if (add_child_llvm_annotations(die, member_idx, conf, &class->namespace.annots))
+ return -ENOMEM;
+ member_idx++;
}
continue;
+ case DW_TAG_LLVM_annotation:
+ if (add_llvm_annotation(die, -1, conf, &class->namespace.annots))
+ return -ENOMEM;
+ continue;
default: {
- struct tag *tag = die__process_tag(die, cu, 0);
+ struct tag *tag = die__process_tag(die, cu, 0, conf);
if (tag == NULL)
return -ENOMEM;
@@ -1379,7 +1658,7 @@ static int die__process_class(Dwarf_Die *die, struct type *class,
uint32_t id;
if (cu__table_add_tag(cu, tag, &id) < 0) {
- tag__delete(tag, cu);
+ tag__delete(tag);
return -ENOMEM;
}
@@ -1403,11 +1682,11 @@ static int die__process_class(Dwarf_Die *die, struct type *class,
}
static int die__process_namespace(Dwarf_Die *die, struct namespace *namespace,
- struct cu *cu)
+ struct cu *cu, struct conf_load *conf)
{
struct tag *tag;
do {
- tag = die__process_tag(die, cu, 0);
+ tag = die__process_tag(die, cu, 0, conf);
if (tag == NULL)
goto out_enomem;
@@ -1429,36 +1708,36 @@ static int die__process_namespace(Dwarf_Die *die, struct namespace *namespace,
return 0;
out_delete_tag:
- tag__delete(tag, cu);
+ tag__delete(tag);
out_enomem:
return -ENOMEM;
}
static int die__process_function(Dwarf_Die *die, struct ftype *ftype,
- struct lexblock *lexblock, struct cu *cu);
+ struct lexblock *lexblock, struct cu *cu, struct conf_load *conf);
static int die__create_new_lexblock(Dwarf_Die *die,
- struct cu *cu, struct lexblock *father)
+ struct cu *cu, struct lexblock *father, struct conf_load *conf)
{
struct lexblock *lexblock = lexblock__new(die, cu);
if (lexblock != NULL) {
- if (die__process_function(die, NULL, lexblock, cu) != 0)
+ if (die__process_function(die, NULL, lexblock, cu, conf) != 0)
goto out_delete;
}
if (father != NULL)
lexblock__add_lexblock(father, lexblock);
return 0;
out_delete:
- lexblock__delete(lexblock, cu);
+ lexblock__delete(lexblock);
return -ENOMEM;
}
static struct tag *die__create_new_inline_expansion(Dwarf_Die *die,
struct lexblock *lexblock,
- struct cu *cu);
+ struct cu *cu, struct conf_load *conf);
-static int die__process_inline_expansion(Dwarf_Die *die, struct lexblock *lexblock, struct cu *cu)
+static int die__process_inline_expansion(Dwarf_Die *die, struct lexblock *lexblock, struct cu *cu, struct conf_load *conf)
{
Dwarf_Die child;
struct tag *tag;
@@ -1471,6 +1750,8 @@ static int die__process_inline_expansion(Dwarf_Die *die, struct lexblock *lexblo
uint32_t id;
switch (dwarf_tag(die)) {
+ case DW_TAG_call_site:
+ case DW_TAG_call_site_parameter:
case DW_TAG_GNU_call_site:
case DW_TAG_GNU_call_site_parameter:
/*
@@ -1484,7 +1765,7 @@ static int die__process_inline_expansion(Dwarf_Die *die, struct lexblock *lexblo
*/
continue;
case DW_TAG_lexical_block:
- if (die__create_new_lexblock(die, cu, lexblock) != 0)
+ if (die__create_new_lexblock(die, cu, lexblock, conf) != 0)
goto out_enomem;
continue;
case DW_TAG_formal_parameter:
@@ -1501,13 +1782,15 @@ static int die__process_inline_expansion(Dwarf_Die *die, struct lexblock *lexblo
*/
continue;
case DW_TAG_inlined_subroutine:
- tag = die__create_new_inline_expansion(die, lexblock, cu);
+ tag = die__create_new_inline_expansion(die, lexblock, cu, conf);
break;
case DW_TAG_label:
- tag = die__create_new_label(die, lexblock, cu);
+ if (conf->ignore_labels)
+ continue;
+ tag = die__create_new_label(die, lexblock, cu, conf);
break;
default:
- tag = die__process_tag(die, cu, 0);
+ tag = die__process_tag(die, cu, 0, conf);
if (tag == NULL)
goto out_enomem;
@@ -1534,22 +1817,22 @@ hash:
return 0;
out_delete_tag:
- tag__delete(tag, cu);
+ tag__delete(tag);
out_enomem:
return -ENOMEM;
}
static struct tag *die__create_new_inline_expansion(Dwarf_Die *die,
struct lexblock *lexblock,
- struct cu *cu)
+ struct cu *cu, struct conf_load *conf)
{
- struct inline_expansion *exp = inline_expansion__new(die, cu);
+ struct inline_expansion *exp = inline_expansion__new(die, cu, conf);
if (exp == NULL)
return NULL;
- if (die__process_inline_expansion(die, lexblock, cu) != 0) {
- obstack_free(&cu->obstack, exp);
+ if (die__process_inline_expansion(die, lexblock, cu, conf) != 0) {
+ free(exp);
return NULL;
}
@@ -1559,8 +1842,9 @@ static struct tag *die__create_new_inline_expansion(Dwarf_Die *die,
}
static int die__process_function(Dwarf_Die *die, struct ftype *ftype,
- struct lexblock *lexblock, struct cu *cu)
+ struct lexblock *lexblock, struct cu *cu, struct conf_load *conf)
{
+ int param_idx = 0;
Dwarf_Die child;
struct tag *tag;
@@ -1572,6 +1856,8 @@ static int die__process_function(Dwarf_Die *die, struct ftype *ftype,
uint32_t id;
switch (dwarf_tag(die)) {
+ case DW_TAG_call_site:
+ case DW_TAG_call_site_parameter:
case DW_TAG_GNU_call_site:
case DW_TAG_GNU_call_site_parameter:
/*
@@ -1602,10 +1888,10 @@ static int die__process_function(Dwarf_Die *die, struct ftype *ftype,
tag__print_not_supported(dwarf_tag(die));
continue;
case DW_TAG_formal_parameter:
- tag = die__create_new_parameter(die, ftype, lexblock, cu);
+ tag = die__create_new_parameter(die, ftype, lexblock, cu, conf, param_idx++);
break;
case DW_TAG_variable:
- tag = die__create_new_variable(die, cu);
+ tag = die__create_new_variable(die, cu, conf);
if (tag == NULL)
goto out_enomem;
lexblock__add_variable(lexblock, tag__variable(tag));
@@ -1615,17 +1901,28 @@ static int die__process_function(Dwarf_Die *die, struct ftype *ftype,
ftype->unspec_parms = 1;
continue;
case DW_TAG_label:
- tag = die__create_new_label(die, lexblock, cu);
+ if (conf->ignore_labels)
+ continue;
+ tag = die__create_new_label(die, lexblock, cu, conf);
break;
case DW_TAG_inlined_subroutine:
- tag = die__create_new_inline_expansion(die, lexblock, cu);
+ if (conf->ignore_inline_expansions)
+ continue;
+ tag = die__create_new_inline_expansion(die, lexblock, cu, conf);
break;
case DW_TAG_lexical_block:
- if (die__create_new_lexblock(die, cu, lexblock) != 0)
+ // lexblocks can contain types that are then referenced from outside.
+ // Thus we can't ignore them without more surgery, i.e. by adding code
+ // to just process types inside lexblocks, leave this for later.
+ if (die__create_new_lexblock(die, cu, lexblock, conf) != 0)
+ goto out_enomem;
+ continue;
+ case DW_TAG_LLVM_annotation:
+ if (add_llvm_annotation(die, -1, conf, &(tag__function(&ftype->tag)->annots)))
goto out_enomem;
continue;
default:
- tag = die__process_tag(die, cu, 0);
+ tag = die__process_tag(die, cu, 0, conf);
if (tag == NULL)
goto out_enomem;
@@ -1654,19 +1951,18 @@ hash:
return 0;
out_delete_tag:
- tag__delete(tag, cu);
+ tag__delete(tag);
out_enomem:
return -ENOMEM;
}
-static struct tag *die__create_new_function(Dwarf_Die *die, struct cu *cu)
+static struct tag *die__create_new_function(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
- struct function *function = function__new(die, cu);
+ struct function *function = function__new(die, cu, conf);
if (function != NULL &&
- die__process_function(die, &function->proto,
- &function->lexblock, cu) != 0) {
- function__delete(function, cu);
+ die__process_function(die, &function->proto, &function->lexblock, cu, conf) != 0) {
+ function__delete(function);
function = NULL;
}
@@ -1674,7 +1970,7 @@ static struct tag *die__create_new_function(Dwarf_Die *die, struct cu *cu)
}
static struct tag *__die__process_tag(Dwarf_Die *die, struct cu *cu,
- int top_level, const char *fn)
+ int top_level, const char *fn, struct conf_load *conf)
{
struct tag *tag;
@@ -1686,37 +1982,38 @@ static struct tag *__die__process_tag(Dwarf_Die *die, struct cu *cu,
case DW_TAG_string_type: // FORTRAN stuff, looks like an array
tag = die__create_new_string_type(die, cu); break;
case DW_TAG_base_type:
- tag = die__create_new_base_type(die, cu); break;
+ tag = die__create_new_base_type(die, cu, conf); break;
case DW_TAG_const_type:
case DW_TAG_imported_declaration:
case DW_TAG_imported_module:
- case DW_TAG_pointer_type:
case DW_TAG_reference_type:
case DW_TAG_restrict_type:
case DW_TAG_unspecified_type:
case DW_TAG_volatile_type:
tag = die__create_new_tag(die, cu); break;
+ case DW_TAG_pointer_type:
+ tag = die__create_new_pointer_tag(die, cu, conf); break;
case DW_TAG_ptr_to_member_type:
tag = die__create_new_ptr_to_member_type(die, cu); break;
case DW_TAG_enumeration_type:
- tag = die__create_new_enumeration(die, cu); break;
+ tag = die__create_new_enumeration(die, cu, conf); break;
case DW_TAG_namespace:
- tag = die__create_new_namespace(die, cu); break;
+ tag = die__create_new_namespace(die, cu, conf); break;
case DW_TAG_class_type:
case DW_TAG_interface_type:
case DW_TAG_structure_type:
- tag = die__create_new_class(die, cu); break;
+ tag = die__create_new_class(die, cu, conf); break;
case DW_TAG_subprogram:
- tag = die__create_new_function(die, cu); break;
+ tag = die__create_new_function(die, cu, conf); break;
case DW_TAG_subroutine_type:
- tag = die__create_new_subroutine_type(die, cu); break;
+ tag = die__create_new_subroutine_type(die, cu, conf); break;
case DW_TAG_rvalue_reference_type:
case DW_TAG_typedef:
- tag = die__create_new_typedef(die, cu); break;
+ tag = die__create_new_typedef(die, cu, conf); break;
case DW_TAG_union_type:
- tag = die__create_new_union(die, cu); break;
+ tag = die__create_new_union(die, cu, conf); break;
case DW_TAG_variable:
- tag = die__create_new_variable(die, cu); break;
+ tag = die__create_new_variable(die, cu, conf); break;
default:
__cu__tag_not_handled(die, fn);
/* fall thru */
@@ -1734,10 +2031,10 @@ static struct tag *__die__process_tag(Dwarf_Die *die, struct cu *cu,
return tag;
}
-static int die__process_unit(Dwarf_Die *die, struct cu *cu)
+static int die__process_unit(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
do {
- struct tag *tag = die__process_tag(die, cu, 1);
+ struct tag *tag = die__process_tag(die, cu, 1, conf);
if (tag == NULL)
return -ENOMEM;
@@ -1759,17 +2056,6 @@ static int die__process_unit(Dwarf_Die *die, struct cu *cu)
return 0;
}
-static void __tag__print_type_not_found(struct tag *tag, const char *func)
-{
- struct dwarf_tag *dtag = tag->priv;
- fprintf(stderr, "%s: couldn't find %#llx type for %#llx (%s)!\n", func,
- (unsigned long long)dtag->type.off, (unsigned long long)dtag->id,
- dwarf_tag_name(tag->tag));
-}
-
-#define tag__print_type_not_found(tag) \
- __tag__print_type_not_found(tag, __func__)
-
static void ftype__recode_dwarf_types(struct tag *tag, struct cu *cu);
static int namespace__recode_dwarf_types(struct tag *tag, struct cu *cu)
@@ -1990,6 +2276,45 @@ static void lexblock__recode_dwarf_types(struct lexblock *tag, struct cu *cu)
}
}
+static void dwarf_cu__recode_btf_type_tag_ptr(struct btf_type_tag_ptr_type *tag,
+ uint32_t pointee_type)
+{
+ struct btf_type_tag_type *annot;
+ struct dwarf_tag *annot_dtag;
+ struct tag *prev_tag;
+
+ /* Given source like
+ * int tag1 tag2 tag3 *p;
+ * the tag->tags contains tag3 -> tag2 -> tag1, the final type chain looks like:
+ * pointer -> tag3 -> tag2 -> tag1 -> pointee
+ *
+ * Basically it means
+ * - '*' applies to "int tag1 tag2 tag3"
+ * - tag3 applies to "int tag1 tag2"
+ * - tag2 applies to "int tag1"
+ * - tag1 applies to "int"
+ *
+ * This also makes final source code (format c) easier as we can do
+ * emit for "tag3 -> tag2 -> tag1 -> int"
+ * emit '*'
+ *
+ * For 'tag3 -> tag2 -> tag1 -> int":
+ * emit for "tag2 -> tag1 -> int"
+ * emit tag3
+ *
+ * Eventually we can get the source code like
+ * int tag1 tag2 tag3 *p;
+ * and this matches the user/kernel code.
+ */
+ prev_tag = &tag->tag;
+ list_for_each_entry(annot, &tag->tags, node) {
+ annot_dtag = annot->tag.priv;
+ prev_tag->type = annot_dtag->small_id;
+ prev_tag = &annot->tag;
+ }
+ prev_tag->type = pointee_type;
+}
+
static int tag__recode_dwarf_type(struct tag *tag, struct cu *cu)
{
struct dwarf_tag *dtag = tag->priv;
@@ -2083,19 +2408,26 @@ static int tag__recode_dwarf_type(struct tag *tag, struct cu *cu)
goto find_type;
case DW_TAG_variable: {
struct variable *var = tag__variable(tag);
- dwarf_off_ref specification = dwarf_tag__spec(dtag);
- if (specification.off) {
- dtype = dwarf_cu__find_tag_by_ref(cu->priv, &specification);
- if (dtype)
- var->spec = tag__variable(dtype->tag);
+ if (var->has_specification) {
+ dwarf_off_ref specification = dwarf_tag__spec(dtag);
+
+ if (specification.off) {
+ dtype = dwarf_cu__find_tag_by_ref(cu->priv,
+ &specification);
+ if (dtype)
+ var->spec = tag__variable(dtype->tag);
+ }
}
}
}
if (dtag->type.off == 0) {
- tag->type = 0; /* void */
+ if (tag->tag != DW_TAG_pointer_type || !tag->has_btf_type_tag)
+ tag->type = 0; /* void */
+ else
+ dwarf_cu__recode_btf_type_tag_ptr(tag__btf_type_tag_ptr(tag), 0);
return 0;
}
@@ -2107,7 +2439,39 @@ check_type:
return 0;
}
out:
- tag->type = dtype->small_id;
+ if (tag->tag != DW_TAG_pointer_type || !tag->has_btf_type_tag)
+ tag->type = dtype->small_id;
+ else
+ dwarf_cu__recode_btf_type_tag_ptr(tag__btf_type_tag_ptr(tag), dtype->small_id);
+
+ return 0;
+}
+
+static int cu__resolve_func_ret_types(struct cu *cu)
+{
+ struct ptr_table *pt = &cu->functions_table;
+ uint32_t i;
+
+ for (i = 0; i < pt->nr_entries; ++i) {
+ struct tag *tag = pt->entries[i];
+
+ if (tag == NULL || tag->type != 0)
+ continue;
+
+ struct function *fn = tag__function(tag);
+ if (!fn->abstract_origin)
+ continue;
+
+ struct dwarf_tag *dtag = tag->priv;
+ struct dwarf_tag *dfunc;
+ dfunc = dwarf_cu__find_tag_by_ref(cu->priv, &dtag->abstract_origin);
+ if (dfunc == NULL) {
+ tag__print_abstract_origin_not_found(tag);
+ return -1;
+ }
+
+ tag->type = dfunc->tag->type;
+ }
return 0;
}
@@ -2138,8 +2502,7 @@ static const char *dwarf_tag__decl_file(const struct tag *tag,
const struct cu *cu)
{
struct dwarf_tag *dtag = tag->priv;
- return cu->extra_dbg_info ?
- strings__ptr(strings, dtag->decl_file) : NULL;
+ return cu->extra_dbg_info ? dtag->decl_file : NULL;
}
static uint32_t dwarf_tag__decl_line(const struct tag *tag,
@@ -2156,19 +2519,24 @@ static unsigned long long dwarf_tag__orig_id(const struct tag *tag,
return cu->extra_dbg_info ? dtag->id : 0;
}
-static const char *dwarf__strings_ptr(const struct cu *cu __unused,
- strings_t s)
-{
- return s ? strings__ptr(strings, s) : NULL;
-}
-
struct debug_fmt_ops dwarf__ops;
-static int die__process(Dwarf_Die *die, struct cu *cu)
+static int die__process(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
Dwarf_Die child;
const uint16_t tag = dwarf_tag(die);
+ if (tag == DW_TAG_skeleton_unit) {
+ static bool warned;
+
+ if (!warned) {
+ fprintf(stderr, "WARNING: DW_TAG_skeleton_unit used, please look for a .dwo file and use it instead.\n"
+ " A future version of pahole will support do this automagically.\n");
+ warned = true;
+ }
+ return 0; // so that other units can be processed
+ }
+
if (tag == DW_TAG_partial_unit) {
static bool warned;
@@ -2182,15 +2550,15 @@ static int die__process(Dwarf_Die *die, struct cu *cu)
}
if (tag != DW_TAG_compile_unit && tag != DW_TAG_type_unit) {
- fprintf(stderr, "%s: DW_TAG_compile_unit, DW_TAG_type_unit or DW_TAG_partial_unit expected got %s!\n",
- __FUNCTION__, dwarf_tag_name(tag));
+ fprintf(stderr, "%s: DW_TAG_compile_unit, DW_TAG_type_unit, DW_TAG_partial_unit or DW_TAG_skeleton_unit expected got %s (0x%x)!\n",
+ __FUNCTION__, dwarf_tag_name(tag), tag);
return -EINVAL;
}
cu->language = attr_numeric(die, DW_AT_language);
if (dwarf_child(die, &child) == 0) {
- int err = die__process_unit(&child, cu);
+ int err = die__process_unit(&child, cu, conf);
if (err)
return err;
}
@@ -2203,12 +2571,16 @@ static int die__process(Dwarf_Die *die, struct cu *cu)
return 0;
}
-static int die__process_and_recode(Dwarf_Die *die, struct cu *cu)
+static int die__process_and_recode(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
- int ret = die__process(die, cu);
+ int ret = die__process(die, cu, conf);
if (ret != 0)
return ret;
- return cu__recode_dwarf_types(cu);
+ ret = cu__recode_dwarf_types(cu);
+ if (ret != 0)
+ return ret;
+
+ return cu__resolve_func_ret_types(cu);
}
static int class_member__cache_byte_size(struct tag *tag, struct cu *cu,
@@ -2250,7 +2622,7 @@ static int class_member__cache_byte_size(struct tag *tag, struct cu *cu,
member->bit_size = member->byte_size * 8;
/*
- * XXX: after all the attemps to determine byte size, we might still
+ * XXX: after all the attempts to determine byte size, we might still
* be unsuccessful, because base_type__name_to_size doesn't know about
* the base_type name, so one has to add there when such base_type
* isn't found. pahole will put zero on the struct output so it should
@@ -2261,24 +2633,31 @@ static int class_member__cache_byte_size(struct tag *tag, struct cu *cu,
return 0;
}
- /*
- * For little-endian architectures, DWARF data emitted by gcc/clang
- * specifies bitfield offset as an offset from the highest-order bit
- * of an underlying integral type (e.g., int) to a highest-order bit
- * of a bitfield. E.g., for bitfield taking first 5 bits of int-backed
- * bitfield, bit offset will be 27 (sizeof(int) - 0 offset - 5 bit
- * size), which is very counter-intuitive and isn't a natural
- * extension of byte offset, which on little-endian points to
- * lowest-order byte. So here we re-adjust bitfield offset to be an
- * offset from lowest-order bit of underlying integral type to
- * a lowest-order bit of a bitfield. This makes bitfield offset
- * a natural extension of byte offset for bitfields and is uniform
- * with how big-endian bit offsets work.
- */
- if (cu->little_endian) {
- member->bitfield_offset = member->bit_size - member->bitfield_offset - member->bitfield_size;
+ if (!member->has_bit_offset) {
+ /*
+ * For little-endian architectures, DWARF data emitted by gcc/clang
+ * specifies bitfield offset as an offset from the highest-order bit
+ * of an underlying integral type (e.g., int) to a highest-order bit
+ * of a bitfield. E.g., for bitfield taking first 5 bits of int-backed
+ * bitfield, bit offset will be 27 (sizeof(int) - 0 offset - 5 bit
+ * size), which is very counter-intuitive and isn't a natural
+ * extension of byte offset, which on little-endian points to
+ * lowest-order byte. So here we re-adjust bitfield offset to be an
+ * offset from lowest-order bit of underlying integral type to
+ * a lowest-order bit of a bitfield. This makes bitfield offset
+ * a natural extension of byte offset for bitfields and is uniform
+ * with how big-endian bit offsets work.
+ */
+ if (cu->little_endian)
+ member->bitfield_offset = member->bit_size - member->bitfield_offset - member->bitfield_size;
+
+ member->bit_offset = member->byte_offset * 8 + member->bitfield_offset;
+ } else {
+ // DWARF5 has DW_AT_data_bit_offset, offset in bits from the
+ // start of the container type (struct, class, etc).
+ member->byte_offset = member->bit_offset / 8;
+ member->bitfield_offset = member->bit_offset - member->byte_offset * 8;
}
- member->bit_offset = member->byte_offset * 8 + member->bitfield_offset;
/* make sure bitfield offset is non-negative */
if (member->bitfield_offset < 0) {
@@ -2303,10 +2682,8 @@ static int class_member__cache_byte_size(struct tag *tag, struct cu *cu,
return 0;
}
-static int finalize_cu(struct cus *cus, struct cu *cu, struct dwarf_cu *dcu,
- struct conf_load *conf)
+static int cu__finalize(struct cu *cu, struct conf_load *conf)
{
- base_type_name_to_size_table__init(strings);
cu__for_all_tags(cu, class_member__cache_byte_size, conf);
if (conf && conf->steal) {
return conf->steal(cu, conf);
@@ -2314,11 +2691,9 @@ static int finalize_cu(struct cus *cus, struct cu *cu, struct dwarf_cu *dcu,
return LSK__KEEPIT;
}
-static int finalize_cu_immediately(struct cus *cus, struct cu *cu,
- struct dwarf_cu *dcu,
- struct conf_load *conf)
+static int cus__finalize(struct cus *cus, struct cu *cu, struct conf_load *conf)
{
- int lsk = finalize_cu(cus, cu, dcu, conf);
+ int lsk = cu__finalize(cu, conf);
switch (lsk) {
case LSK__DELETE:
cu__delete(cu);
@@ -2326,20 +2701,32 @@ static int finalize_cu_immediately(struct cus *cus, struct cu *cu,
case LSK__STOP_LOADING:
break;
case LSK__KEEPIT:
- if (!cu->extra_dbg_info)
- obstack_free(&dcu->obstack, NULL);
cus__add(cus, cu);
break;
}
return lsk;
}
-static int cus__load_debug_types(struct cus *cus, struct conf_load *conf,
- Dwfl_Module *mod, Dwarf *dw, Elf *elf,
- const char *filename,
- const unsigned char *build_id,
- int build_id_len,
- struct cu **cup, struct dwarf_cu *dcup)
+static int cu__set_common(struct cu *cu, struct conf_load *conf,
+ Dwfl_Module *mod, Elf *elf)
+{
+ cu->uses_global_strings = true;
+ cu->elf = elf;
+ cu->dwfl = mod;
+ cu->extra_dbg_info = conf ? conf->extra_dbg_info : 0;
+ cu->has_addr_info = conf ? conf->get_addr_info : 0;
+
+ GElf_Ehdr ehdr;
+ if (gelf_getehdr(elf, &ehdr) == NULL)
+ return DWARF_CB_ABORT;
+
+ cu->little_endian = ehdr.e_ident[EI_DATA] == ELFDATA2LSB;
+ return 0;
+}
+
+static int __cus__load_debug_types(struct conf_load *conf, Dwfl_Module *mod, Dwarf *dw, Elf *elf,
+ const char *filename, const unsigned char *build_id,
+ int build_id_len, struct cu **cup, struct dwarf_cu *dcup)
{
Dwarf_Off off = 0, noff, type_off;
size_t cuhl;
@@ -2356,24 +2743,14 @@ static int cus__load_debug_types(struct cus *cus, struct conf_load *conf,
struct cu *cu;
cu = cu__new("", pointer_size, build_id,
- build_id_len, filename);
- if (cu == NULL) {
+ build_id_len, filename, conf->use_obstack);
+ if (cu == NULL ||
+ cu__set_common(cu, conf, mod, elf) != 0) {
return DWARF_CB_ABORT;
}
- cu->uses_global_strings = true;
- cu->elf = elf;
- cu->dwfl = mod;
- cu->extra_dbg_info = conf ? conf->extra_dbg_info : 0;
- cu->has_addr_info = conf ? conf->get_addr_info : 0;
-
- GElf_Ehdr ehdr;
- if (gelf_getehdr(elf, &ehdr) == NULL) {
+ if (dwarf_cu__init(dcup, cu) != 0)
return DWARF_CB_ABORT;
- }
- cu->little_endian = ehdr.e_ident[EI_DATA] == ELFDATA2LSB;
-
- dwarf_cu__init(dcup);
dcup->cu = cu;
/* Funny hack. */
dcup->type_unit = dcup;
@@ -2387,7 +2764,7 @@ static int cus__load_debug_types(struct cus *cus, struct conf_load *conf,
Dwarf_Die *cu_die = dwarf_offdie_types(dw, off + cuhl,
&die_mem);
- if (die__process(cu_die, *cup) != 0)
+ if (die__process(cu_die, *cup, conf) != 0)
return DWARF_CB_ABORT;
off = noff;
@@ -2399,40 +2776,236 @@ static int cus__load_debug_types(struct cus *cus, struct conf_load *conf,
return 0;
}
-static int cus__load_module(struct cus *cus, struct conf_load *conf,
- Dwfl_Module *mod, Dwarf *dw, Elf *elf,
- const char *filename)
+/* Match the define in linux:include/linux/elfnote.h */
+#define LINUX_ELFNOTE_BUILD_LTO 0x101
+
+static bool cus__merging_cu(Dwarf *dw, Elf *elf)
{
+ Elf_Scn *section = NULL;
+ while ((section = elf_nextscn(elf, section)) != 0) {
+ GElf_Shdr header;
+ if (!gelf_getshdr(section, &header))
+ continue;
+
+ if (header.sh_type != SHT_NOTE)
+ continue;
+
+ Elf_Data *data = NULL;
+ while ((data = elf_getdata(section, data)) != 0) {
+ size_t name_off, desc_off, offset = 0;
+ GElf_Nhdr hdr;
+ while ((offset = gelf_getnote(data, offset, &hdr, &name_off, &desc_off)) != 0) {
+ if (hdr.n_type != LINUX_ELFNOTE_BUILD_LTO)
+ continue;
+
+ /* owner is Linux */
+ if (strcmp((char *)data->d_buf + name_off, "Linux") != 0)
+ continue;
+
+ return *(int *)(data->d_buf + desc_off) != 0;
+ }
+ }
+ }
+
Dwarf_Off off = 0, noff;
size_t cuhl;
- const unsigned char *build_id = NULL;
+
+ while (dwarf_nextcu (dw, off, &noff, &cuhl, NULL, NULL, NULL) == 0) {
+ Dwarf_Die die_mem;
+ Dwarf_Die *cu_die = dwarf_offdie(dw, off + cuhl, &die_mem);
+
+ if (cu_die == NULL)
+ break;
+
+ Dwarf_Off offset = 0;
+ while (true) {
+ size_t length;
+ Dwarf_Abbrev *abbrev = dwarf_getabbrev (cu_die, offset, &length);
+ if (abbrev == NULL || abbrev == DWARF_END_ABBREV)
+ break;
+
+ size_t attrcnt;
+ if (dwarf_getattrcnt (abbrev, &attrcnt) != 0)
+ return false;
+
+ unsigned int attr_num, attr_form;
+ Dwarf_Off aboffset;
+ size_t j;
+ for (j = 0; j < attrcnt; ++j) {
+ if (dwarf_getabbrevattr (abbrev, j, &attr_num, &attr_form,
+ &aboffset))
+ return false;
+ if (attr_form == DW_FORM_ref_addr)
+ return true;
+ }
+
+ offset += length;
+ }
+
+ off = noff;
+ }
+
+ return false;
+}
+
+struct dwarf_cus {
+ struct cus *cus;
+ struct conf_load *conf;
+ Dwfl_Module *mod;
+ Dwarf *dw;
+ Elf *elf;
+ const char *filename;
+ Dwarf_Off off;
+ const unsigned char *build_id;
+ int build_id_len;
+ int error;
+ struct dwarf_cu *type_dcu;
+};
+
+static int dwarf_cus__create_and_process_cu(struct dwarf_cus *dcus, Dwarf_Die *cu_die, uint8_t pointer_size)
+{
+ /*
+ * DW_AT_name in DW_TAG_compile_unit can be NULL, first seen in:
+ *
+ * /usr/libexec/gcc/x86_64-redhat-linux/4.3.2/ecj1.debug
+ */
+ const char *name = attr_string(cu_die, DW_AT_name, dcus->conf);
+ struct cu *cu = cu__new(name ?: "", pointer_size, dcus->build_id, dcus->build_id_len, dcus->filename, dcus->conf->use_obstack);
+ if (cu == NULL || cu__set_common(cu, dcus->conf, dcus->mod, dcus->elf) != 0)
+ return DWARF_CB_ABORT;
+
+ struct dwarf_cu *dcu = dwarf_cu__new(cu);
+
+ if (dcu == NULL)
+ return DWARF_CB_ABORT;
+
+ dcu->type_unit = dcus->type_dcu;
+ cu->priv = dcu;
+ cu->dfops = &dwarf__ops;
+
+ if (die__process_and_recode(cu_die, cu, dcus->conf) != 0 ||
+ cus__finalize(dcus->cus, cu, dcus->conf) == LSK__STOP_LOADING)
+ return DWARF_CB_ABORT;
+
+ return DWARF_CB_OK;
+}
+
+static int dwarf_cus__nextcu(struct dwarf_cus *dcus, Dwarf_Die *die_mem, Dwarf_Die **cu_die, uint8_t *pointer_size, uint8_t *offset_size)
+{
+ Dwarf_Off noff;
+ size_t cuhl;
+ int ret;
+
+ cus__lock(dcus->cus);
+
+ if (dcus->error) {
+ ret = dcus->error;
+ goto out_unlock;
+ }
+
+ ret = dwarf_nextcu(dcus->dw, dcus->off, &noff, &cuhl, NULL, pointer_size, offset_size);
+ if (ret == 0) {
+ *cu_die = dwarf_offdie(dcus->dw, dcus->off + cuhl, die_mem);
+ if (*cu_die != NULL)
+ dcus->off = noff;
+ }
+
+out_unlock:
+ cus__unlock(dcus->cus);
+
+ return ret;
+}
+
+static void *dwarf_cus__process_cu_thread(void *arg)
+{
+ struct dwarf_cus *dcus = arg;
uint8_t pointer_size, offset_size;
+ Dwarf_Die die_mem, *cu_die;
-#ifdef HAVE_DWFL_MODULE_BUILD_ID
- GElf_Addr vaddr;
- int build_id_len = dwfl_module_build_id(mod, &build_id, &vaddr);
-#else
- int build_id_len = 0;
-#endif
+ while (dwarf_cus__nextcu(dcus, &die_mem, &cu_die, &pointer_size, &offset_size) == 0) {
+ if (cu_die == NULL)
+ break;
- struct cu *type_cu;
- struct dwarf_cu type_dcu;
- int type_lsk = LSK__KEEPIT;
+ if (dwarf_cus__create_and_process_cu(dcus, cu_die, pointer_size) == DWARF_CB_ABORT)
+ goto out_abort;
+ }
- int res = cus__load_debug_types(cus, conf, mod, dw, elf, filename,
- build_id, build_id_len,
- &type_cu, &type_dcu);
- if (res != 0) {
- return res;
+ if (dcus->conf->thread_exit && dcus->conf->thread_exit() != 0)
+ goto out_abort;
+
+ return (void *)DWARF_CB_OK;
+out_abort:
+ return (void *)DWARF_CB_ABORT;
+}
+
+static int dwarf_cus__threaded_process_cus(struct dwarf_cus *dcus)
+{
+ pthread_t threads[dcus->conf->nr_jobs];
+ int i;
+
+ for (i = 0; i < dcus->conf->nr_jobs; ++i) {
+ dcus->error = pthread_create(&threads[i], NULL, dwarf_cus__process_cu_thread, dcus);
+ if (dcus->error)
+ goto out_join;
}
- if (type_cu != NULL) {
- type_lsk = finalize_cu(cus, type_cu, &type_dcu, conf);
- if (type_lsk == LSK__KEEPIT) {
- cus__add(cus, type_cu);
- }
+ dcus->error = 0;
+
+out_join:
+ while (--i >= 0) {
+ void *res;
+ int err = pthread_join(threads[i], &res);
+
+ if (err == 0 && res != NULL)
+ dcus->error = (long)res;
+ }
+
+ return dcus->error;
+}
+
+static int __dwarf_cus__process_cus(struct dwarf_cus *dcus)
+{
+ uint8_t pointer_size, offset_size;
+ Dwarf_Off noff;
+ size_t cuhl;
+
+ while (dwarf_nextcu(dcus->dw, dcus->off, &noff, &cuhl, NULL, &pointer_size, &offset_size) == 0) {
+ Dwarf_Die die_mem;
+ Dwarf_Die *cu_die = dwarf_offdie(dcus->dw, dcus->off + cuhl, &die_mem);
+
+ if (cu_die == NULL)
+ break;
+
+ if (dwarf_cus__create_and_process_cu(dcus, cu_die, pointer_size) == DWARF_CB_ABORT)
+ return DWARF_CB_ABORT;
+
+ dcus->off = noff;
}
+ return 0;
+}
+
+static int dwarf_cus__process_cus(struct dwarf_cus *dcus)
+{
+ if (dcus->conf->nr_jobs > 1)
+ return dwarf_cus__threaded_process_cus(dcus);
+
+ return __dwarf_cus__process_cus(dcus);
+}
+
+static int cus__merge_and_process_cu(struct cus *cus, struct conf_load *conf,
+ Dwfl_Module *mod, Dwarf *dw, Elf *elf,
+ const char *filename,
+ const unsigned char *build_id,
+ int build_id_len,
+ struct dwarf_cu *type_dcu)
+{
+ uint8_t pointer_size, offset_size;
+ struct dwarf_cu *dcu = NULL;
+ Dwarf_Off off = 0, noff;
+ struct cu *cu = NULL;
+ size_t cuhl;
+
while (dwarf_nextcu(dw, off, &noff, &cuhl, NULL, &pointer_size,
&offset_size) == 0) {
Dwarf_Die die_mem;
@@ -2441,46 +3014,123 @@ static int cus__load_module(struct cus *cus, struct conf_load *conf,
if (cu_die == NULL)
break;
- /*
- * DW_AT_name in DW_TAG_compile_unit can be NULL, first
- * seen in:
- * /usr/libexec/gcc/x86_64-redhat-linux/4.3.2/ecj1.debug
- */
- const char *name = attr_string(cu_die, DW_AT_name);
- struct cu *cu = cu__new(name ?: "", pointer_size,
- build_id, build_id_len, filename);
- if (cu == NULL)
- return DWARF_CB_ABORT;
- cu->uses_global_strings = true;
- cu->elf = elf;
- cu->dwfl = mod;
- cu->extra_dbg_info = conf ? conf->extra_dbg_info : 0;
- cu->has_addr_info = conf ? conf->get_addr_info : 0;
-
- GElf_Ehdr ehdr;
- if (gelf_getehdr(elf, &ehdr) == NULL) {
- return DWARF_CB_ABORT;
- }
- cu->little_endian = ehdr.e_ident[EI_DATA] == ELFDATA2LSB;
+ if (cu == NULL) {
+ cu = cu__new("", pointer_size, build_id, build_id_len,
+ filename, conf->use_obstack);
+ if (cu == NULL || cu__set_common(cu, conf, mod, elf) != 0)
+ goto out_abort;
- struct dwarf_cu dcu;
+ dcu = zalloc(sizeof(*dcu));
+ if (dcu == NULL)
+ goto out_abort;
- dwarf_cu__init(&dcu);
- dcu.cu = cu;
- dcu.type_unit = type_cu ? &type_dcu : NULL;
- cu->priv = &dcu;
- cu->dfops = &dwarf__ops;
+ /* Merged cu tends to need a lot more memory.
+ * Let us start with max_hashtags__bits and
+ * go down to find a proper hashtag bit value.
+ */
+ uint32_t default_hbits = hashtags__bits;
+ for (hashtags__bits = max_hashtags__bits;
+ hashtags__bits >= default_hbits;
+ hashtags__bits--) {
+ if (dwarf_cu__init(dcu, cu) == 0)
+ break;
+ }
+ if (hashtags__bits < default_hbits)
+ goto out_abort;
- if (die__process_and_recode(cu_die, cu) != 0)
- return DWARF_CB_ABORT;
+ dcu->cu = cu;
+ dcu->type_unit = type_dcu;
+ cu->priv = dcu;
+ cu->dfops = &dwarf__ops;
+ cu->language = attr_numeric(cu_die, DW_AT_language);
+ }
- if (finalize_cu_immediately(cus, cu, &dcu, conf)
- == LSK__STOP_LOADING)
- return DWARF_CB_ABORT;
+ Dwarf_Die child;
+ if (dwarf_child(cu_die, &child) == 0) {
+ if (die__process_unit(&child, cu, conf) != 0)
+ goto out_abort;
+ }
off = noff;
}
+ if (cu == NULL)
+ return 0;
+
+ /* process merged cu */
+ if (cu__recode_dwarf_types(cu) != LSK__KEEPIT)
+ goto out_abort;
+
+ /*
+ * for lto build, the function return type may not be
+ * resolved due to the return type of a subprogram is
+ * encoded in another subprogram through abstract_origin
+ * tag. Let us visit all subprograms again to resolve this.
+ */
+ if (cu__resolve_func_ret_types(cu) != LSK__KEEPIT)
+ goto out_abort;
+
+ if (cus__finalize(cus, cu, conf) == LSK__STOP_LOADING)
+ goto out_abort;
+
+ return 0;
+
+out_abort:
+ dwarf_cu__delete(cu);
+ cu__delete(cu);
+ return DWARF_CB_ABORT;
+}
+
+static int cus__load_module(struct cus *cus, struct conf_load *conf,
+ Dwfl_Module *mod, Dwarf *dw, Elf *elf,
+ const char *filename)
+{
+ const unsigned char *build_id = NULL;
+#ifdef HAVE_DWFL_MODULE_BUILD_ID
+ GElf_Addr vaddr;
+ int build_id_len = dwfl_module_build_id(mod, &build_id, &vaddr);
+#else
+ int build_id_len = 0;
+#endif
+ struct cu *type_cu;
+ struct dwarf_cu type_dcu;
+ int type_lsk = LSK__KEEPIT;
+
+ int res = __cus__load_debug_types(conf, mod, dw, elf, filename, build_id, build_id_len, &type_cu, &type_dcu);
+ if (res != 0) {
+ return res;
+ }
+
+ if (type_cu != NULL) {
+ type_lsk = cu__finalize(type_cu, conf);
+ if (type_lsk == LSK__KEEPIT) {
+ cus__add(cus, type_cu);
+ }
+ }
+
+ if (cus__merging_cu(dw, elf)) {
+ res = cus__merge_and_process_cu(cus, conf, mod, dw, elf, filename,
+ build_id, build_id_len,
+ type_cu ? &type_dcu : NULL);
+ } else {
+ struct dwarf_cus dcus = {
+ .off = 0,
+ .cus = cus,
+ .conf = conf,
+ .mod = mod,
+ .dw = dw,
+ .elf = elf,
+ .filename = filename,
+ .type_dcu = type_cu ? &type_dcu : NULL,
+ .build_id = build_id,
+ .build_id_len = build_id_len,
+ };
+ res = dwarf_cus__process_cus(&dcus);
+ }
+
+ if (res)
+ return res;
+
if (type_lsk == LSK__DELETE)
cu__delete(type_cu);
@@ -2495,9 +3145,9 @@ struct process_dwflmod_parms {
};
static int cus__process_dwflmod(Dwfl_Module *dwflmod,
- void **userdata __unused,
- const char *name __unused,
- Dwarf_Addr base __unused,
+ void **userdata __maybe_unused,
+ const char *name __maybe_unused,
+ Dwarf_Addr base __maybe_unused,
void *arg)
{
struct process_dwflmod_parms *parms = arg;
@@ -2535,6 +3185,16 @@ static int cus__process_dwflmod(Dwfl_Module *dwflmod,
return err;
}
+static void dwarf_loader__exit(struct cus *cus)
+{
+ Dwfl *dwfl = cus__priv(cus);
+
+ if (dwfl) {
+ dwfl_end(dwfl);
+ cus__set_priv(cus, NULL);
+ }
+}
+
static int cus__process_file(struct cus *cus, struct conf_load *conf, int fd,
const char *filename)
{
@@ -2559,6 +3219,9 @@ static int cus__process_file(struct cus *cus, struct conf_load *conf, int fd,
Dwfl *dwfl = dwfl_begin(&callbacks);
+ cus__set_priv(cus, dwfl);
+ cus__set_loader_exit(cus, dwarf_loader__exit);
+
if (dwfl_report_offline(dwfl, filename, filename, dwfl_fd) == NULL)
return -1;
@@ -2573,7 +3236,10 @@ static int cus__process_file(struct cus *cus, struct conf_load *conf, int fd,
/* Process the one or more modules gleaned from this file. */
dwfl_getmodules(dwfl, cus__process_dwflmod, &parms, 0);
- dwfl_end(dwfl);
+
+ // We can't call dwfl_end(dwfl) here, as we keep pointers to strings
+ // allocated by libdw that will be freed at dwfl_end(), so leave this for
+ // cus__delete().
return parms.nr_dwarf_sections_found ? 0 : -1;
}
@@ -2582,6 +3248,21 @@ static int dwarf__load_file(struct cus *cus, struct conf_load *conf,
{
int fd, err;
+ if (conf->max_hashtable_bits != 0) {
+ if (conf->max_hashtable_bits > 31)
+ return -E2BIG;
+
+ max_hashtags__bits = conf->max_hashtable_bits;
+ }
+
+ if (conf->hashtable_bits != 0) {
+ if (conf->hashtable_bits > max_hashtags__bits)
+ return -E2BIG;
+
+ hashtags__bits = conf->hashtable_bits;
+ } else if (hashtags__bits > max_hashtags__bits)
+ return -EINVAL;
+
elf_version(EV_CURRENT);
fd = open(filename, O_RDONLY);
@@ -2595,26 +3276,12 @@ static int dwarf__load_file(struct cus *cus, struct conf_load *conf,
return err;
}
-static int dwarf__init(void)
-{
- strings = strings__new();
- return strings != NULL ? 0 : -ENOMEM;
-}
-
-static void dwarf__exit(void)
-{
- strings__delete(strings);
- strings = NULL;
-}
-
struct debug_fmt_ops dwarf__ops = {
.name = "dwarf",
- .init = dwarf__init,
- .exit = dwarf__exit,
.load_file = dwarf__load_file,
- .strings__ptr = dwarf__strings_ptr,
.tag__decl_file = dwarf_tag__decl_file,
.tag__decl_line = dwarf_tag__decl_line,
.tag__orig_id = dwarf_tag__orig_id,
+ .cu__delete = dwarf_cu__delete,
.has_alignment_info = true,
};