4
* Created on: Feb 1, 2020
10
#include <elfutils/libdw.h>
13
#include "dwarf_utils.h"
15
#include "dwarf_parameter.h"
20
void pst_type_init(pst_type* t, const char* name, pst_param_flags type)
22
list_node_init(&t->node);
24
t->name = pst_strdup(name);
32
pst_type* pst_type_new(const char* name, pst_param_flags type)
34
pst_type* nt = pst_alloc(pst_type);
36
pst_type_init(nt, name, type);
43
void pst_type_fini(pst_type* t)
56
static void clear(pst_parameter* param)
58
// clean up parameter's types
60
struct list_node *pos, *tn;
61
list_for_each_entry_safe(t, pos, tn, ¶m->types, node) {
66
// clean up children parameters
67
pst_parameter* p = NULL;
68
list_for_each_entry_safe(p, pos, tn, ¶m->children, node) {
70
pst_parameter_fini(p);
73
if(param->info.name) {
74
pst_free(param->info.name);
77
if(param->info.type_name) {
78
pst_free(param->info.type_name);
82
static pst_type* next_type(pst_parameter* param, pst_type* t)
84
list_node* n = (t == NULL) ? list_first(¶m->types) : list_next(&t->node);
87
ret = list_entry(n, pst_type, node);
93
static void parameter_print_type(pst_parameter* param)
96
for(pst_type* t = next_type(param, NULL); t; t = next_type(param, t)) {
100
param->ctx->print(param->ctx, "%s", "const ");
103
param->ctx->print(param->ctx, "%s", "volatile ");
105
case PARAM_TYPE_STRUCT:
106
param->ctx->print(param->ctx, "%s", "struct ");
108
case PARAM_TYPE_UNION:
109
param->ctx->print(param->ctx, "%s", "union ");
111
case PARAM_TYPE_ENUM:
112
param->ctx->print(param->ctx, "%s", "enum ");
114
case PARAM_TYPE_CLASS:
115
param->ctx->print(param->ctx, "%s", "class ");
121
param->ctx->print(param->ctx, "%s", param->info.type_name ? param->info.type_name : "");
126
case PARAM_TYPE_POINTER:
127
if(!(param->info.flags & PARAM_TYPE_FUNCPTR)) {
128
param->ctx->print(param->ctx, "%s", "*");
132
param->ctx->print(param->ctx, "%s", "&");
134
case PARAM_TYPE_RREF:
135
param->ctx->print(param->ctx, "%s", "&&");
137
case PARAM_TYPE_ARRAY:
138
param->ctx->print(param->ctx, "%s", "[]");
146
void parameter_print(pst_parameter* param)
148
parameter_print_type(param);
149
if(param->info.flags & PARAM_RETURN) {
153
if(param->info.flags & PARAM_TYPE_FUNCPTR) {
154
param->ctx->print(param->ctx, " (*%s)(", param->info.name);
155
for(pst_parameter* p = parameter_next_child(param, NULL); p; p = parameter_next_child(param, p)) {
156
if(p->info.flags & PARAM_RETURN) {
160
parameter_print_type(p);
161
param->ctx->print(param->ctx, "%s", (parameter_next_child(param, p) != NULL) ? ", " : "");
163
param->ctx->print(param->ctx, ") = ");
165
param->ctx->print(param->ctx, " %s = ", param->info.name);
168
if(param->info.flags & PARAM_HAS_VALUE) {
169
param->ctx->print(param->ctx, "0x%lX", param->info.value);
171
// don't take care on NULL pointer since obviously it's invalid
172
if((param->info.flags & PARAM_INVALID) && param->info.value != 0) {
173
param->ctx->print(param->ctx, " <invalid>");
176
param->ctx->print(param->ctx, "<undefined>");
180
pst_type* parameter_add_type(pst_parameter* param, const char* name, pst_param_flags type)
182
pst_new(pst_type, t, name, type);
183
list_add_bottom(¶m->types, &t->node);
184
param->info.flags |= type;
185
if(name && !param->info.type_name) {
186
param->info.type_name = pst_strdup(name);
192
pst_parameter* parameter_next_child(pst_parameter* param, pst_parameter* p)
194
struct list_node* n = (p == NULL) ? list_first(¶m->children) : list_next(&p->node);
196
pst_parameter* ret = NULL;
198
ret = list_entry(n, pst_parameter, node);
204
static bool handle_subroutine(pst_parameter* param, Dwarf_Die* die)
207
pst_new(pst_parameter, p, param->ctx);
208
list_add_bottom(¶m->children, &p->node);
209
Dwarf_Attribute attr_mem;
210
Dwarf_Attribute* attr = dwarf_attr(die, DW_AT_name, &attr_mem);
212
const char *name = dwarf_formstring(attr);
214
p->info.name = pst_strdup(name);
218
parameter_handle_type(param, die);
220
// hack since DWARF has no ability to determine 'void' another way
221
if(!p->info.type_name) {
222
p->info.type_name = pst_strdup("void");
225
p->info.flags |= PARAM_RETURN;
228
if(dwarf_child(die, &result) != 0) {
229
// no parameters defined for subroutine
233
// went through arguments of subroutine
235
switch (dwarf_tag(&result)) {
236
case DW_TAG_formal_parameter:
238
pst_new(pst_parameter, p1, param->ctx);
239
list_add_bottom(¶m->children, &p1->node);
241
attr = dwarf_attr(&result, DW_AT_name, &attr_mem);
243
const char *name = dwarf_formstring(attr);
245
p1->info.name = pst_strdup(name);
249
parameter_handle_type(p1, &result);
251
// hack since DWARF has no ability to determine 'void' it another way
252
if(!p1->info.type_name) {
253
p1->info.type_name = pst_strdup("void");
258
case DW_TAG_unspecified_parameters:
260
pst_new(pst_parameter, p1, param->ctx);
261
list_add_bottom(¶m->children, &p1->node);
262
p1->info.flags |= PARAM_TYPE_UNSPEC;
263
p1->info.name = pst_strdup("...");
267
pst_log(SEVERITY_WARNING, "Unknown TAG of pointer to function: 0x%X", dwarf_tag(&result));
270
} while(dwarf_siblingof(&result, &result) == 0);
275
bool parameter_handle_type(pst_parameter* param, Dwarf_Die* result)
277
Dwarf_Attribute attr_mem;
278
Dwarf_Attribute* attr;
283
// Get reference to attribute type of the parameter/variable
284
attr = dwarf_attr(result, DW_AT_type, &attr_mem);
286
pst_log(SEVERITY_WARNING, "%s: Failed to determine type of parameter", __FUNCTION__);
290
if(!dwarf_formref_die(attr, &ret_die)) {
291
pst_log(SEVERITY_ERROR, "Failed to get parameter type DIE");
295
// get Size attribute and it's value
296
param->info.size = 8;
297
attr = dwarf_attr(&ret_die, DW_AT_byte_size, &attr_mem);
299
dwarf_formudata(attr, ¶m->info.size);
302
switch (dwarf_tag(&ret_die)) {
304
case DW_TAG_base_type: {
305
const char* type_name = dwarf_diename(&ret_die);
306
attr = dwarf_attr(&ret_die, DW_AT_encoding, &attr_mem);
308
Dwarf_Word enc_type = 0;
309
dwarf_formudata(attr, &enc_type);
312
parameter_add_type(param, type_name, PARAM_TYPE_BOOL);
315
parameter_add_type(param, NULL, PARAM_TYPE_POINTER);
318
parameter_add_type(param, type_name, PARAM_TYPE_INT);
320
case DW_ATE_unsigned:
321
parameter_add_type(param, type_name, PARAM_TYPE_UINT);
323
case DW_ATE_signed_char:
324
parameter_add_type(param, type_name, PARAM_TYPE_CHAR);
326
case DW_ATE_unsigned_char:
327
parameter_add_type(param, type_name, PARAM_TYPE_UCHAR);
330
case DW_ATE_complex_float:
331
case DW_ATE_imaginary_float:
332
case DW_ATE_decimal_float:
333
parameter_add_type(param, type_name, PARAM_TYPE_FLOAT);
336
pst_log(SEVERITY_WARNING, "Unknown parameter base type encodings 0x%lX", enc_type);
343
case DW_TAG_array_type:
344
parameter_add_type(param, NULL, PARAM_TYPE_ARRAY);
346
case DW_TAG_structure_type:
347
parameter_add_type(param, NULL, PARAM_TYPE_STRUCT);
349
case DW_TAG_union_type:
350
parameter_add_type(param, NULL, PARAM_TYPE_UNION);
352
case DW_TAG_class_type:
353
parameter_add_type(param, NULL, PARAM_TYPE_CLASS);
355
case DW_TAG_pointer_type:
356
parameter_add_type(param, NULL, PARAM_TYPE_POINTER);
358
case DW_TAG_enumeration_type:
359
parameter_add_type(param, NULL, PARAM_TYPE_ENUM);
361
case DW_TAG_const_type:
362
parameter_add_type(param, NULL, PARAM_CONST);
364
case DW_TAG_subroutine_type:
365
handle_subroutine(param, &ret_die);
366
parameter_add_type(param, NULL, PARAM_TYPE_FUNCPTR);
368
case DW_TAG_typedef: {
369
parameter_add_type(param, dwarf_diename(&ret_die), PARAM_TYPE_TYPEDEF);
372
case DW_TAG_unspecified_type:
373
parameter_add_type(param, "void", PARAM_TYPE_VOID);
375
case DW_TAG_reference_type:
376
parameter_add_type(param, NULL, PARAM_TYPE_REF);
378
case DW_TAG_rvalue_reference_type:
379
parameter_add_type(param, NULL, PARAM_TYPE_RREF);
381
case DW_TAG_volatile_type:
382
parameter_add_type(param, NULL, PARAM_VOLATILE);
384
case DW_TAG_string_type:
385
pst_log(SEVERITY_DEBUG, "String type, skipping");
388
pst_log(SEVERITY_WARNING, "Unknown 0x%X tag type", dwarf_tag(&ret_die));
392
pst_log(SEVERITY_DEBUG, "%s: Parameter type '%s'(%lu) flags = 0x%X", __FUNCTION__, dwarf_diename(&ret_die), param->info.size, param->info.flags);
394
if(dwarf_hasattr(&ret_die, DW_AT_type)) {
395
// handle parameter's sub-type
396
return parameter_handle_type(param, &ret_die);
402
bool parameter_handle_dwarf(pst_parameter* param, Dwarf_Die* result, pst_function* fun)
406
Dwarf_Attribute attr_mem;
407
Dwarf_Attribute* attr;
409
param->info.name = pst_strdup(dwarf_diename(result));
410
param->info.flags |= (dwarf_tag(result) == DW_TAG_variable) ? PARAM_VARIABLE : 0;
412
dwarf_decl_line(result, (int*)¶m->info.line);
413
pst_log(SEVERITY_DEBUG, "---> Handle '%s' %s", param->info.name, dwarf_tag(result) == DW_TAG_formal_parameter ? "parameter" : "variable");
414
parameter_handle_type(param, result);
416
if(dwarf_hasattr(result, DW_AT_location)) {
417
// determine location of parameter in stack/heap or CPU registers
418
attr = dwarf_attr(result, DW_AT_location, &attr_mem);
420
unw_get_reg(param->ctx->curr_frame, UNW_REG_IP, &pc);
422
if(handle_location(param->ctx, attr, ¶m->location, pc, fun)) {
423
param->info.value = param->location.value;
424
param->info.flags |= PARAM_HAS_VALUE;
426
pst_log(SEVERITY_WARNING, "Failed to calculate DW_AT_location expression: %s", param->ctx->buff);
428
} else if(dwarf_hasattr(result, DW_AT_const_value)) {
429
param->info.flags |= PARAM_CONST;
430
// no locations definitions, value is constant, known by DWARF directly
431
attr = dwarf_attr(result, DW_AT_const_value, &attr_mem);
432
param->info.flags |= PARAM_HAS_VALUE;
433
switch (dwarf_whatform(attr)) {
435
param->info.value = (unw_word_t)dwarf_formstring(attr);
441
dwarf_formudata(attr, ¶m->info.value);
444
dwarf_formsdata(attr, (int64_t*)¶m->info.value);
447
dwarf_formudata(attr, ¶m->info.value);
450
pst_log(SEVERITY_WARNING, "Unknown form '0x%X' of attribute for Constant value", dwarf_whatform(attr));
451
param->info.flags &= ~PARAM_HAS_VALUE;
455
// check pointer validity
456
if((param->info.flags & (PARAM_TYPE_POINTER | PARAM_TYPE_FUNCPTR)) && pst_pointer_valid((void*)param->info.value, sizeof((void*)param->info.size))) {
457
param->info.flags |= PARAM_INVALID;
460
// clean-up unused bits in parameter's value
461
if(!(param->info.flags & (PARAM_TYPE_POINTER | PARAM_TYPE_FUNCPTR))) {
462
param->info.value &= 0xFFFFFFFFFFFFFFFF >> (64 - ((param->info.size * 8) & 0x3F));
465
// hack since DWARF has no ability to determine 'void' it another way
466
if(!param->info.type_name) {
467
param->info.type_name = pst_strdup("void");
470
// Additionally handle these attributes:
471
// 1. DW_AT_default_value to get information about default value for DW_TAG_formal_parameter type of function
472
// A DW_AT_default_value attribute for a formal parameter entry. The value of
473
// this attribute may be a constant, or a reference to the debugging information
474
// entry for a variable, or a reference to a debugging information entry containing a DWARF procedure
476
// 2. DW_AT_variable_parameter
477
// A DW_AT_variable_parameter attribute, which is a flag, if a formal
478
// parameter entry represents a parameter whose value in the calling function
479
// may be modified by the callee. The absence of this attribute implies that the
480
// parameter’s value in the calling function cannot be modified by the callee.
482
// 3. DW_AT_abstract_origin
483
// In place of these omitted attributes, each concrete inlined instance entry has a DW_AT_abstract_origin attribute that may be used to obtain the
484
// missing information (indirectly) from the associated abstract instance entry. The value of the abstract origin attribute is a reference to the associated abstract
491
void pst_parameter_init(pst_parameter* param, pst_context* ctx)
493
list_node_init(¶m->node);
496
param->info.name = NULL;
497
param->info.type_name = NULL;
498
param->info.line = 0;
499
param->info.size = 0;
500
param->info.flags = 0;
502
list_head_init(¶m->types);
503
list_head_init(¶m->children);
505
pst_dwarf_expr_init(¶m->location);
506
param->allocated = false;
509
pst_parameter* pst_parameter_new(pst_context* ctx)
511
pst_parameter* param = pst_alloc(pst_parameter);
513
pst_parameter_init(param, ctx);
514
param->allocated = true;
519
void pst_parameter_fini(pst_parameter* param)
522
if(param->allocated) {