pstrace

Форк
0
/
dwarf_parameter.c 
525 строк · 16.8 Кб
1
/*
2
 * dwarf_parameter.cpp
3
 *
4
 *  Created on: Feb 1, 2020
5
 *      Author: nnosov
6
 */
7

8

9
#include <dwarf.h>
10
#include <elfutils/libdw.h>
11

12
#include "common.h"
13
#include "dwarf_utils.h"
14
#include "context.h"
15
#include "dwarf_parameter.h"
16

17
//
18
// pst_type
19
//
20
void pst_type_init(pst_type* t, const char* name, pst_param_flags type)
21
{
22
    list_node_init(&t->node);
23
    if(name) {
24
        t->name = pst_strdup(name);
25
    } else {
26
        t->name = NULL;
27
    }
28
    t->type = type;
29
    t->allocated = false;
30
}
31

32
pst_type* pst_type_new(const char* name, pst_param_flags type)
33
{
34
    pst_type* nt = pst_alloc(pst_type);
35
    if(nt) {
36
        pst_type_init(nt, name, type);
37
        nt->allocated = true;
38
    }
39

40
    return nt;
41
}
42

43
void pst_type_fini(pst_type* t)
44
{
45
    if(t->name) {
46
        pst_free(t->name);
47
    }
48
    if(t->allocated) {
49
        pst_free(t);
50
    }
51
}
52

53
//
54
// pst_parameter
55
//
56
static void clear(pst_parameter* param)
57
{
58
    // clean up parameter's types
59
    pst_type* t = NULL;
60
    struct list_node  *pos, *tn;
61
    list_for_each_entry_safe(t, pos, tn, &param->types, node) {
62
        list_del(&t->node);
63
        pst_type_fini(t);
64
    }
65

66
    // clean up children parameters
67
    pst_parameter* p = NULL;
68
    list_for_each_entry_safe(p, pos, tn, &param->children, node) {
69
        list_del(&p->node);
70
        pst_parameter_fini(p);
71
    }
72

73
    if(param->info.name) {
74
        pst_free(param->info.name);
75
    }
76

77
    if(param->info.type_name) {
78
        pst_free(param->info.type_name);
79
    }
80
}
81

82
static pst_type* next_type(pst_parameter* param, pst_type* t)
83
{
84
    list_node* n = (t == NULL) ? list_first(&param->types) : list_next(&t->node);
85
    pst_type* ret = NULL;
86
    if(n) {
87
        ret = list_entry(n, pst_type, node);
88
    }
89

90
    return ret;
91
}
92

93
static void parameter_print_type(pst_parameter* param)
94
{
95
    bool is_1st = true;
96
    for(pst_type* t = next_type(param, NULL); t; t = next_type(param, t)) {
97
        if(is_1st) {
98
            switch(t->type) {
99
                case PARAM_CONST:
100
                    param->ctx->print(param->ctx, "%s", "const ");
101
                    break;
102
                case PARAM_VOLATILE:
103
                    param->ctx->print(param->ctx, "%s", "volatile ");
104
                    break;
105
                case PARAM_TYPE_STRUCT:
106
                    param->ctx->print(param->ctx, "%s", "struct ");
107
                    break;
108
                case PARAM_TYPE_UNION:
109
                    param->ctx->print(param->ctx, "%s", "union ");
110
                    break;
111
                case PARAM_TYPE_ENUM:
112
                    param->ctx->print(param->ctx, "%s", "enum ");
113
                    break;
114
                case PARAM_TYPE_CLASS:
115
                    param->ctx->print(param->ctx, "%s", "class ");
116
                    break;
117
                default:
118
                    break;
119
            }
120

121
            param->ctx->print(param->ctx, "%s", param->info.type_name ? param->info.type_name : "");
122
            is_1st = false;
123
        }
124

125
        switch(t->type) {
126
            case PARAM_TYPE_POINTER:
127
                if(!(param->info.flags & PARAM_TYPE_FUNCPTR)) {
128
                    param->ctx->print(param->ctx, "%s", "*");
129
                }
130
                break;
131
            case PARAM_TYPE_REF:
132
                param->ctx->print(param->ctx, "%s", "&");
133
                break;
134
            case PARAM_TYPE_RREF:
135
                param->ctx->print(param->ctx, "%s", "&&");
136
                break;
137
            case PARAM_TYPE_ARRAY:
138
                param->ctx->print(param->ctx, "%s", "[]");
139
                break;
140
            default:
141
                break;
142
        }
143
    }
144
}
145

146
void parameter_print(pst_parameter* param)
147
{
148
    parameter_print_type(param);
149
    if(param->info.flags & PARAM_RETURN) {
150
        return;
151
    }
152

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) {
157
                // skip return value
158
                continue;
159
            }
160
            parameter_print_type(p);
161
            param->ctx->print(param->ctx, "%s", (parameter_next_child(param, p) != NULL) ? ", " : "");
162
        }
163
        param->ctx->print(param->ctx, ") = ");
164
    } else {
165
        param->ctx->print(param->ctx, " %s = ", param->info.name);
166
    }
167

168
    if(param->info.flags & PARAM_HAS_VALUE) {
169
        param->ctx->print(param->ctx, "0x%lX", param->info.value);
170
        
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>");
174
        }
175
    } else {
176
        param->ctx->print(param->ctx, "<undefined>");
177
    }
178
}
179

180
pst_type* parameter_add_type(pst_parameter* param, const char* name, pst_param_flags type)
181
{
182
    pst_new(pst_type, t, name, type);
183
    list_add_bottom(&param->types, &t->node);
184
    param->info.flags |= type;
185
    if(name && !param->info.type_name) {
186
        param->info.type_name = pst_strdup(name);
187
    }
188

189
    return t;
190
}
191

192
pst_parameter* parameter_next_child(pst_parameter* param, pst_parameter* p)
193
{
194
    struct list_node* n = (p == NULL) ? list_first(&param->children) : list_next(&p->node);
195

196
    pst_parameter* ret = NULL;
197
    if(n) {
198
        ret = list_entry(n, pst_parameter, node);
199
    }
200

201
    return ret;
202
}
203

204
static bool handle_subroutine(pst_parameter* param, Dwarf_Die* die)
205
{
206
	// return value
207
    pst_new(pst_parameter, p, param->ctx);
208
    list_add_bottom(&param->children, &p->node);
209
    Dwarf_Attribute attr_mem;
210
    Dwarf_Attribute* attr = dwarf_attr(die, DW_AT_name, &attr_mem);
211
    if(attr) {
212
        const char *name = dwarf_formstring(attr);
213
        if(name) {
214
            p->info.name = pst_strdup(name);
215
        }
216
    }
217

218
    parameter_handle_type(param, die);
219

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");
223
    }
224

225
    p->info.flags |= PARAM_RETURN;
226

227
    Dwarf_Die result;
228
    if(dwarf_child(die, &result) != 0) {
229
        // no parameters defined for subroutine
230
        return true;
231
    }
232

233
    // went through arguments of subroutine
234
    do {
235
        switch (dwarf_tag(&result)) {
236
            case DW_TAG_formal_parameter:
237
            {
238
                pst_new(pst_parameter, p1, param->ctx);
239
                list_add_bottom(&param->children, &p1->node);
240

241
                attr = dwarf_attr(&result, DW_AT_name, &attr_mem);
242
                if(attr) {
243
                    const char *name = dwarf_formstring(attr);
244
                    if(name) {
245
                        p1->info.name = pst_strdup(name);
246
                    }
247
                }
248

249
                parameter_handle_type(p1, &result);
250

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");
254
                }
255

256
                break;
257
            }
258
            case DW_TAG_unspecified_parameters:
259
            {
260
                pst_new(pst_parameter, p1, param->ctx);
261
                list_add_bottom(&param->children, &p1->node);
262
                p1->info.flags |= PARAM_TYPE_UNSPEC;
263
                p1->info.name = pst_strdup("...");
264
                break;
265
            }
266
            default:
267
                pst_log(SEVERITY_WARNING, "Unknown TAG of pointer to function: 0x%X", dwarf_tag(&result));
268
                break;
269
        }
270
    } while(dwarf_siblingof(&result, &result) == 0);
271

272
    return true;
273
}
274

275
bool parameter_handle_type(pst_parameter* param, Dwarf_Die* result)
276
{
277
    Dwarf_Attribute attr_mem;
278
    Dwarf_Attribute* attr;
279

280
    // get DIE of type
281
    Dwarf_Die ret_die;
282

283
    // Get reference to attribute type of the parameter/variable
284
    attr = dwarf_attr(result, DW_AT_type, &attr_mem);
285
    if(!attr) {
286
        pst_log(SEVERITY_WARNING, "%s: Failed to determine type of parameter", __FUNCTION__);
287
        return false;
288
    }
289

290
    if(!dwarf_formref_die(attr, &ret_die)) {
291
        pst_log(SEVERITY_ERROR, "Failed to get parameter type DIE");
292
        return false;
293
    }
294

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);
298
    if(attr) {
299
        dwarf_formudata(attr, &param->info.size);
300
    }
301

302
    switch (dwarf_tag(&ret_die)) {
303
        // base types
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);
307
            if(attr) {
308
                Dwarf_Word enc_type = 0;
309
                dwarf_formudata(attr, &enc_type);
310
                switch (enc_type) {
311
                    case DW_ATE_boolean:
312
                        parameter_add_type(param, type_name, PARAM_TYPE_BOOL);
313
                        break;
314
                    case DW_ATE_address:
315
                        parameter_add_type(param, NULL, PARAM_TYPE_POINTER);
316
                        break;
317
                    case DW_ATE_signed:
318
                        parameter_add_type(param, type_name, PARAM_TYPE_INT);
319
                        break;
320
                    case DW_ATE_unsigned:
321
                        parameter_add_type(param, type_name, PARAM_TYPE_UINT);
322
                        break;
323
                    case DW_ATE_signed_char:
324
                        parameter_add_type(param, type_name, PARAM_TYPE_CHAR);
325
                        break;
326
                    case DW_ATE_unsigned_char:
327
                        parameter_add_type(param, type_name, PARAM_TYPE_UCHAR);
328
                        break;
329
                    case DW_ATE_float:
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);
334
                        break;
335
                    default:
336
                        pst_log(SEVERITY_WARNING, "Unknown parameter base type encodings 0x%lX", enc_type);
337
                }
338

339
            }
340
            break;
341
        }
342
        // complex types
343
        case DW_TAG_array_type:
344
            parameter_add_type(param, NULL, PARAM_TYPE_ARRAY);
345
            break;
346
        case DW_TAG_structure_type:
347
            parameter_add_type(param, NULL, PARAM_TYPE_STRUCT);
348
            break;
349
        case DW_TAG_union_type:
350
            parameter_add_type(param, NULL, PARAM_TYPE_UNION);
351
            break;
352
        case DW_TAG_class_type:
353
            parameter_add_type(param, NULL, PARAM_TYPE_CLASS);
354
            break;
355
        case DW_TAG_pointer_type:
356
            parameter_add_type(param, NULL, PARAM_TYPE_POINTER);
357
            break;
358
        case DW_TAG_enumeration_type:
359
            parameter_add_type(param, NULL, PARAM_TYPE_ENUM);
360
            break;
361
        case DW_TAG_const_type:
362
            parameter_add_type(param, NULL, PARAM_CONST);
363
            break;
364
        case DW_TAG_subroutine_type:
365
            handle_subroutine(param, &ret_die);
366
            parameter_add_type(param, NULL, PARAM_TYPE_FUNCPTR);
367
            break;
368
        case DW_TAG_typedef: {
369
            parameter_add_type(param, dwarf_diename(&ret_die), PARAM_TYPE_TYPEDEF);
370
            break;
371
        }
372
        case DW_TAG_unspecified_type:
373
            parameter_add_type(param, "void", PARAM_TYPE_VOID);
374
            break;
375
        case DW_TAG_reference_type:
376
            parameter_add_type(param, NULL, PARAM_TYPE_REF);
377
            break;
378
        case DW_TAG_rvalue_reference_type:
379
            parameter_add_type(param, NULL, PARAM_TYPE_RREF);
380
            break;
381
        case DW_TAG_volatile_type:
382
            parameter_add_type(param, NULL, PARAM_VOLATILE);
383
            break;
384
        case DW_TAG_string_type:
385
            pst_log(SEVERITY_DEBUG, "String type, skipping");
386
            break;
387
        default:
388
            pst_log(SEVERITY_WARNING, "Unknown 0x%X tag type", dwarf_tag(&ret_die));
389
            break;
390
    }
391

392
    pst_log(SEVERITY_DEBUG, "%s: Parameter type '%s'(%lu) flags = 0x%X", __FUNCTION__, dwarf_diename(&ret_die), param->info.size, param->info.flags);
393

394
    if(dwarf_hasattr(&ret_die, DW_AT_type)) {
395
        // handle parameter's sub-type
396
        return parameter_handle_type(param, &ret_die);
397
    }
398

399
    return true;
400
}
401

402
bool parameter_handle_dwarf(pst_parameter* param, Dwarf_Die* result, pst_function* fun)
403
{
404
    param->die = result;
405

406
    Dwarf_Attribute attr_mem;
407
    Dwarf_Attribute* attr;
408

409
    param->info.name = pst_strdup(dwarf_diename(result));
410
    param->info.flags |= (dwarf_tag(result) == DW_TAG_variable) ? PARAM_VARIABLE : 0;
411

412
    dwarf_decl_line(result, (int*)&param->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);
415

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);
419
        Dwarf_Addr pc;
420
        unw_get_reg(param->ctx->curr_frame, UNW_REG_IP,  &pc);
421

422
        if(handle_location(param->ctx, attr, &param->location, pc, fun)) {
423
            param->info.value = param->location.value;
424
            param->info.flags |= PARAM_HAS_VALUE;
425
        } else {
426
            pst_log(SEVERITY_WARNING, "Failed to calculate DW_AT_location expression: %s", param->ctx->buff);
427
        }
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)) {
434
            case DW_FORM_string:
435
                param->info.value = (unw_word_t)dwarf_formstring(attr);
436
                break;
437
            case DW_FORM_data1:
438
            case DW_FORM_data2:
439
            case DW_FORM_data4:
440
            case DW_FORM_data8:
441
                dwarf_formudata(attr, &param->info.value);
442
                break;
443
            case DW_FORM_sdata:
444
                dwarf_formsdata(attr, (int64_t*)&param->info.value);
445
                break;
446
            case DW_FORM_udata:
447
                dwarf_formudata(attr, &param->info.value);
448
                break;
449
            default:
450
                pst_log(SEVERITY_WARNING, "Unknown form '0x%X' of attribute for Constant value", dwarf_whatform(attr));
451
                param->info.flags &= ~PARAM_HAS_VALUE;
452
        }
453
    }
454

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;
458
    }
459

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));
463
    }
464

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");
468
    }
469

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
475

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.
481

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
485
    //      instance entry.
486

487

488
    return true;
489
}
490

491
void pst_parameter_init(pst_parameter* param, pst_context* ctx)
492
{
493
    list_node_init(&param->node);
494
    param->die = NULL;
495
    // info field
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;
501

502
    list_head_init(&param->types);
503
    list_head_init(&param->children);
504
    param->ctx = ctx;
505
    pst_dwarf_expr_init(&param->location);
506
    param->allocated = false;
507
}
508

509
pst_parameter* pst_parameter_new(pst_context* ctx)
510
{
511
    pst_parameter* param = pst_alloc(pst_parameter);
512
    if(param) {
513
        pst_parameter_init(param, ctx);
514
        param->allocated = true;
515
    }
516

517
    return param;
518
}
519
void pst_parameter_fini(pst_parameter* param)
520
{
521
    clear(param);
522
    if(param->allocated) {
523
        pst_free(param);
524
    }
525
}
526

527

528

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.