From 39f34d78146a66f41638bffe88743c66ded2ac94 Mon Sep 17 00:00:00 2001 From: Nikolai Nosov Date: Wed, 22 Apr 2020 13:05:04 +0400 Subject: [PATCH] better printing of parameters. export access to parameter's children --- include/libpst-types.h | 2 +- include/libpst.h | 12 ++- src/dwarf/dwarf_function.c | 19 ++-- src/dwarf/dwarf_parameter.c | 184 ++++++++++++++++++++++-------------- src/dwarf/dwarf_parameter.h | 10 +- src/libpst.c | 9 +- 6 files changed, 145 insertions(+), 91 deletions(-) diff --git a/include/libpst-types.h b/include/libpst-types.h index 9cc065a..a47635a 100644 --- a/include/libpst-types.h +++ b/include/libpst-types.h @@ -58,7 +58,7 @@ typedef enum { typedef struct { char* name; ///< parameter's name - char* type_name; ///< name of parameter's type in case of 'PARAM_TYPE_TYPEDEF' + char* type_name; ///< name of parameter's type uint32_t line; ///< line of parameter definition unw_word_t size; ///< size of parameter in bits unw_word_t value; ///< value of parameter. use 'size' to determine number of actual bits of 'value' diff --git a/include/libpst.h b/include/libpst.h index aadb59e..0f6b499 100644 --- a/include/libpst.h +++ b/include/libpst.h @@ -65,7 +65,7 @@ const char* pst_print_simple(pst_handler* handler); * @param current pointer to current function. NULL to get first * @return pointer to next function's handle, NULL in case of end of list */ -const pst_function* pst_get_next_function(pst_handler* handler, pst_function* current); +const pst_function* pst_function_next(pst_handler* handler, pst_function* current); /** * @brief Get function's information (name, address, line) @@ -80,7 +80,15 @@ const pst_function_info* pst_get_function_info(pst_function* function); * @param current pointer to current parameter. NULL to get first * @return pointer to next parameter's handle, NULL in case of end of list */ -const pst_parameter* pst_get_next_parameter(pst_function* function, pst_parameter* current); +const pst_parameter* pst_parameter_next(pst_function* function, pst_parameter* current); + +/** + * @brief Get next parameter's children parameter (for composite types) + * @param parent parent parameter's handler obtained by pst_get_next_parameter() + * @param current pointer to current child parameter. NULL to get first + * @return pointer to next parameter's handle, NULL in case of end of list + */ +const pst_parameter* pst_parameter_next_child(pst_parameter* parent, pst_parameter* current); /** * @brief Get parameter's information (name, type, line etc) diff --git a/src/dwarf/dwarf_function.c b/src/dwarf/dwarf_function.c index 0dec7fb..8126e26 100644 --- a/src/dwarf/dwarf_function.c +++ b/src/dwarf/dwarf_function.c @@ -167,7 +167,7 @@ bool handle_lexical_block(pst_function* fn, Dwarf_Die* result) break; case DW_TAG_variable: { pst_parameter* param = add_param(fn); - if(!pst_parameter_handle_dwarf(param, &child, fn)) { + if(!parameter_handle_dwarf(param, &child, fn)) { del_param(param); } break; @@ -202,7 +202,7 @@ bool pst_function_print_dwarf(pst_function* fn) pst_parameter* param = pst_function_next_parameter(fn, NULL); if(param && (param->info.flags & PARAM_RETURN)) { // print return value type, function name and start list of parameters - pst_parameter_print_dwarf(param); + parameter_print(param); fn->ctx->print(fn->ctx, " %s(", fn->info.name); param = pst_function_next_parameter(fn, param); } else { @@ -213,7 +213,7 @@ bool pst_function_print_dwarf(pst_function* fn) for(; param; param = pst_function_next_parameter(fn, param)) { if(param->info.flags & PARAM_RETURN) { // print return value type, function name and start list of parameters - pst_parameter_print_dwarf(param); + parameter_print(param); fn->ctx->print(fn->ctx, " %s(", fn->info.name); continue; } @@ -229,7 +229,7 @@ bool pst_function_print_dwarf(pst_function* fn) } else { fn->ctx->print(fn->ctx, " "); } - pst_parameter_print_dwarf(param); + parameter_print(param); fn->ctx->print(fn->ctx, ";\n"); } else { if(first) { @@ -237,7 +237,7 @@ bool pst_function_print_dwarf(pst_function* fn) } else { fn->ctx->print(fn->ctx, ", "); } - pst_parameter_print_dwarf(param); + parameter_print(param); } } @@ -307,14 +307,13 @@ bool pst_function_handle_dwarf(pst_function * fn, Dwarf_Die* d) // Get reference to return attribute type of the function // may be to use dwfl_module_return_value_location() instead pst_parameter* ret_p = add_param(fn); ret_p->info.flags |= PARAM_RETURN; - attr = dwarf_attr(fn->die, DW_AT_type, &attr_mem); - if(attr) { - if(!pst_parameter_handle_type(ret_p, attr)) { + if(dwarf_hasattr(fn->die, DW_AT_type)) { + if(!parameter_handle_type(ret_p, fn->die)) { pst_log(SEVERITY_ERROR, "Failed to handle return parameter type for function %s(...)", fn->info.name); del_param(ret_p); } } else { - pst_parameter_add_type(ret_p, "void", PARAM_TYPE_VOID); + parameter_add_type(ret_p, "void", PARAM_TYPE_VOID); } // handle and save additionally these attributes: @@ -343,7 +342,7 @@ bool pst_function_handle_dwarf(pst_function * fn, Dwarf_Die* d) case DW_TAG_formal_parameter: case DW_TAG_variable: { pst_parameter* param = add_param(fn); - if(!pst_parameter_handle_dwarf(param, &result, fn)) { + if(!parameter_handle_dwarf(param, &result, fn)) { del_param(param); } diff --git a/src/dwarf/dwarf_parameter.c b/src/dwarf/dwarf_parameter.c index dfe956a..fa850a9 100644 --- a/src/dwarf/dwarf_parameter.c +++ b/src/dwarf/dwarf_parameter.c @@ -89,36 +89,83 @@ static pst_type* next_type(pst_parameter* param, pst_type* t) return ret; } -bool pst_parameter_print_dwarf(pst_parameter* param) +static void parameter_print_type(pst_parameter* param) { - if(param->info.flags & PARAM_RETURN) { - param->ctx->print(param->ctx, "%s", param->info.type_name ? param->info.type_name : ""); - } else { - if(param->info.flags & PARAM_TYPE_FUNCPTR) { - param->ctx->print(param->ctx, "%s (*%s)(", param->info.type_name ? param->info.type_name : "", param->info.name); - for(pst_parameter* p = pst_parameter_next_child(param, NULL); p; p = pst_parameter_next_child(param, p)) { - if(p->info.flags & PARAM_RETURN) { - // skip return value - continue; - } - param->ctx->print(param->ctx, "%s%s%s", p->info.type_name ? p->info.type_name : "", p->info.flags & PARAM_TYPE_POINTER ? "*" : "", - (pst_parameter_next_child(param, p) != NULL) ? ", " : ""); + bool is_1st = true; + for(pst_type* t = next_type(param, NULL); t; t = next_type(param, t)) { + if(is_1st) { + switch(t->type) { + case PARAM_CONST: + param->ctx->print(param->ctx, "%s", "const "); + break; + case PARAM_TYPE_STRUCT: + param->ctx->print(param->ctx, "%s", "struct "); + break; + case PARAM_TYPE_UNION: + param->ctx->print(param->ctx, "%s", "union "); + break; + case PARAM_TYPE_ENUM: + param->ctx->print(param->ctx, "%s", "enum "); + break; + case PARAM_TYPE_CLASS: + param->ctx->print(param->ctx, "%s", "class "); + break; + default: + break; } - param->ctx->print(param->ctx, ") = "); - } else { - param->ctx->print(param->ctx, "%s%s %s = ", param->info.type_name ? param->info.type_name : "", - param->info.flags & PARAM_TYPE_POINTER ? "*" : "", param->info.name); + + param->ctx->print(param->ctx, "%s", param->info.type_name ? param->info.type_name : ""); + is_1st = false; } - if(param->info.flags & PARAM_HAS_VALUE) { - param->ctx->print(param->ctx, "0x%lX", param->info.value); - } else { - param->ctx->print(param->ctx, ""); + + switch(t->type) { + case PARAM_TYPE_POINTER: + if(!(param->info.flags & PARAM_TYPE_FUNCPTR)) { + param->ctx->print(param->ctx, "%s", "*"); + } + break; + case PARAM_TYPE_REF: + param->ctx->print(param->ctx, "%s", "&"); + break; + case PARAM_TYPE_ARRAY: + param->ctx->print(param->ctx, "%s", "[]"); + break; + default: + break; } } - return true; } -pst_type* pst_parameter_add_type(pst_parameter* param, const char* name, pst_param_flags type) +void parameter_print(pst_parameter* param) +{ + parameter_print_type(param); + if(param->info.flags & PARAM_RETURN) { + return; + } + + if(param->info.flags & PARAM_TYPE_FUNCPTR) { + param->ctx->print(param->ctx, " (*%s)(", param->info.name); + for(pst_parameter* p = parameter_next_child(param, NULL); p; p = parameter_next_child(param, p)) { + if(p->info.flags & PARAM_RETURN) { + // skip return value + continue; + } + parameter_print_type(p); + param->ctx->print(param->ctx, "%s", (parameter_next_child(param, p) != NULL) ? ", " : ""); + } + param->ctx->print(param->ctx, ") = "); + } else { + param->ctx->print(param->ctx, " %s = ", param->info.name); + } + + if(param->info.flags & PARAM_HAS_VALUE) { + param->ctx->print(param->ctx, "0x%lX", param->info.value); + } else { + param->ctx->print(param->ctx, ""); + } +} + +pst_type* parameter_add_type(pst_parameter* param, const char* name, pst_param_flags type) { pst_new(pst_type, t, name, type); list_add_bottom(¶m->types, &t->node); @@ -130,7 +177,7 @@ pst_type* pst_parameter_add_type(pst_parameter* param, const char* name, pst_par return t; } -pst_parameter* pst_parameter_next_child(pst_parameter* param, pst_parameter* p) +pst_parameter* parameter_next_child(pst_parameter* param, pst_parameter* p) { struct list_node* n = (p == NULL) ? list_first(¶m->children) : list_next(&p->node); @@ -142,7 +189,7 @@ pst_parameter* pst_parameter_next_child(pst_parameter* param, pst_parameter* p) return ret; } -bool pst_parameter_handle_subroutine(pst_parameter* param, Dwarf_Die* die) +static bool handle_subroutine(pst_parameter* param, Dwarf_Die* die) { // return value pst_new(pst_parameter, p, param->ctx); @@ -156,13 +203,9 @@ bool pst_parameter_handle_subroutine(pst_parameter* param, Dwarf_Die* die) } } - // Get reference to attribute type of the parameter/variable - attr = dwarf_attr(die, DW_AT_type, &attr_mem); - if(attr) { - pst_parameter_handle_type(param, attr); - } + parameter_handle_type(param, die); - // hack since DWARF has no ability to determine 'void' it another way + // hack since DWARF has no ability to determine 'void' another way if(!p->info.type_name) { p->info.type_name = pst_strdup("void"); } @@ -191,11 +234,7 @@ bool pst_parameter_handle_subroutine(pst_parameter* param, Dwarf_Die* die) } } - // Get reference to attribute type of the parameter/variable - attr = dwarf_attr(&result, DW_AT_type, &attr_mem); - if(attr) { - pst_parameter_handle_type(p1, attr); - } + parameter_handle_type(p1, &result); // hack since DWARF has no ability to determine 'void' it another way if(!p1->info.type_name) { @@ -221,100 +260,107 @@ bool pst_parameter_handle_subroutine(pst_parameter* param, Dwarf_Die* die) return true; } -bool pst_parameter_handle_type(pst_parameter* param, Dwarf_Attribute* base) +bool parameter_handle_type(pst_parameter* param, Dwarf_Die* result) { Dwarf_Attribute attr_mem; Dwarf_Attribute* attr; - // get DIE of return type + // get DIE of type Dwarf_Die ret_die; - if(!dwarf_formref_die(base, &ret_die)) { - pst_log(SEVERITY_ERROR, "Failed to get parameter DIE"); + // Get reference to attribute type of the parameter/variable + attr = dwarf_attr(result, DW_AT_type, &attr_mem); + if(!attr) { + pst_log(SEVERITY_WARNING, "%s: Failed to determine type of parameter", __FUNCTION__); + return false; + } + + if(!dwarf_formref_die(attr, &ret_die)) { + pst_log(SEVERITY_ERROR, "Failed to get parameter type DIE"); return false; } param->info.size = 64; switch (dwarf_tag(&ret_die)) { + // base types case DW_TAG_base_type: { // get Size attribute and it's value attr = dwarf_attr(&ret_die, DW_AT_byte_size, &attr_mem); if(attr) { dwarf_formudata(attr, ¶m->info.size); } - pst_log(SEVERITY_DEBUG, "base type '%s'(%lu)", dwarf_diename(&ret_die), param->info.size); - pst_parameter_add_type(param, dwarf_diename(&ret_die), DW_TAG_base_type); + pst_log(SEVERITY_DEBUG, "%s: Base type '%s'(%lu)", __FUNCTION__, dwarf_diename(&ret_die), param->info.size); const char* type_name = dwarf_diename(&ret_die); - pst_log(SEVERITY_DEBUG, "type_name = %s", type_name); attr = dwarf_attr(&ret_die, DW_AT_encoding, &attr_mem); if(attr) { Dwarf_Word enc_type = 0; dwarf_formudata(attr, &enc_type); switch (enc_type) { case DW_ATE_boolean: - pst_parameter_add_type(param, type_name, PARAM_TYPE_BOOL); + parameter_add_type(param, type_name, PARAM_TYPE_BOOL); break; case DW_ATE_address: - pst_parameter_add_type(param, NULL, PARAM_TYPE_POINTER); + parameter_add_type(param, NULL, PARAM_TYPE_POINTER); break; case DW_ATE_signed: - pst_parameter_add_type(param, type_name, PARAM_TYPE_INT); + parameter_add_type(param, type_name, PARAM_TYPE_INT); break; case DW_ATE_unsigned: - pst_parameter_add_type(param, type_name, PARAM_TYPE_UINT); + parameter_add_type(param, type_name, PARAM_TYPE_UINT); break; case DW_ATE_signed_char: - pst_parameter_add_type(param, type_name, PARAM_TYPE_CHAR); + parameter_add_type(param, type_name, PARAM_TYPE_CHAR); break; case DW_ATE_unsigned_char: - pst_parameter_add_type(param, type_name, PARAM_TYPE_UCHAR); + parameter_add_type(param, type_name, PARAM_TYPE_UCHAR); break; case DW_ATE_float: case DW_ATE_complex_float: case DW_ATE_imaginary_float: case DW_ATE_decimal_float: - pst_parameter_add_type(param, type_name, PARAM_TYPE_FLOAT); + parameter_add_type(param, type_name, PARAM_TYPE_FLOAT); break; } } break; } + // complex types case DW_TAG_array_type: - pst_parameter_add_type(param, NULL, PARAM_TYPE_ARRAY); + parameter_add_type(param, NULL, PARAM_TYPE_ARRAY); break; case DW_TAG_structure_type: - pst_parameter_add_type(param, NULL, PARAM_TYPE_STRUCT); + parameter_add_type(param, NULL, PARAM_TYPE_STRUCT); break; case DW_TAG_union_type: - pst_parameter_add_type(param, NULL, PARAM_TYPE_UNION); + parameter_add_type(param, NULL, PARAM_TYPE_UNION); break; case DW_TAG_class_type: - pst_parameter_add_type(param, NULL, PARAM_TYPE_CLASS); + parameter_add_type(param, NULL, PARAM_TYPE_CLASS); break; case DW_TAG_pointer_type: - pst_parameter_add_type(param, NULL, PARAM_TYPE_POINTER); + parameter_add_type(param, NULL, PARAM_TYPE_POINTER); break; case DW_TAG_enumeration_type: - pst_parameter_add_type(param, NULL, PARAM_TYPE_ENUM); + parameter_add_type(param, NULL, PARAM_TYPE_ENUM); break; case DW_TAG_const_type: - pst_parameter_add_type(param, NULL, PARAM_CONST); + parameter_add_type(param, NULL, PARAM_CONST); break; case DW_TAG_subroutine_type: - pst_parameter_handle_subroutine(param, &ret_die); - pst_parameter_add_type(param, NULL, PARAM_TYPE_FUNCPTR); + handle_subroutine(param, &ret_die); + parameter_add_type(param, NULL, PARAM_TYPE_FUNCPTR); break; case DW_TAG_typedef: { - pst_parameter_add_type(param, dwarf_diename(&ret_die), PARAM_TYPE_TYPEDEF); + parameter_add_type(param, dwarf_diename(&ret_die), PARAM_TYPE_TYPEDEF); break; } case DW_TAG_unspecified_type: - pst_parameter_add_type(param, "void", PARAM_TYPE_VOID); + parameter_add_type(param, "void", PARAM_TYPE_VOID); break; case DW_TAG_reference_type: - pst_parameter_add_type(param, NULL, PARAM_TYPE_REF); + parameter_add_type(param, NULL, PARAM_TYPE_REF); break; default: @@ -322,15 +368,15 @@ bool pst_parameter_handle_type(pst_parameter* param, Dwarf_Attribute* base) break; } - attr = dwarf_attr(&ret_die, DW_AT_type, &attr_mem); - if(attr) { - return pst_parameter_handle_type(param, attr); + if(dwarf_hasattr(&ret_die, DW_AT_type)) { + // handle parameter's sub-type + return parameter_handle_type(param, &ret_die); } return true; } -bool pst_parameter_handle_dwarf(pst_parameter* param, Dwarf_Die* result, pst_function* fun) +bool parameter_handle_dwarf(pst_parameter* param, Dwarf_Die* result, pst_function* fun) { param->die = result; @@ -341,12 +387,8 @@ bool pst_parameter_handle_dwarf(pst_parameter* param, Dwarf_Die* result, pst_fun param->info.flags |= (dwarf_tag(result) == DW_TAG_variable) ? PARAM_VARIABLE : 0; dwarf_decl_line(result, (int*)¶m->info.line); - // Get reference to attribute type of the parameter/variable - attr = dwarf_attr(result, DW_AT_type, &attr_mem); pst_log(SEVERITY_DEBUG, "---> Handle '%s' %s", param->info.name, dwarf_tag(result) == DW_TAG_formal_parameter ? "parameter" : "variable"); - if(attr) { - pst_parameter_handle_type(param, attr); - } + parameter_handle_type(param, result); if(dwarf_hasattr(result, DW_AT_location)) { // determine location of parameter in stack/heap or CPU registers diff --git a/src/dwarf/dwarf_parameter.h b/src/dwarf/dwarf_parameter.h index 7722e90..246678b 100644 --- a/src/dwarf/dwarf_parameter.h +++ b/src/dwarf/dwarf_parameter.h @@ -45,10 +45,10 @@ void pst_parameter_init(pst_parameter* param, pst_context* ctx); pst_parameter* pst_parameter_new(pst_context* ctx); void pst_parameter_fini(pst_parameter* param); -bool pst_parameter_handle_dwarf(pst_parameter* param, Dwarf_Die* result, pst_function* fun); -bool pst_parameter_print_dwarf(pst_parameter* param); -bool pst_parameter_handle_type(pst_parameter* param, Dwarf_Attribute* base); -pst_type* pst_parameter_add_type(pst_parameter* param, const char* name, pst_param_flags type); -pst_parameter* pst_parameter_next_child(pst_parameter* param, pst_parameter* p); +bool parameter_handle_dwarf(pst_parameter* param, Dwarf_Die* result, pst_function* fun); +void parameter_print(pst_parameter* param); +bool parameter_handle_type(pst_parameter* param, Dwarf_Die* result); +pst_type* parameter_add_type(pst_parameter* param, const char* name, pst_param_flags type); +pst_parameter* parameter_next_child(pst_parameter* param, pst_parameter* p); #endif /* __PST_DWARF_PARAMETER_H__ */ diff --git a/src/libpst.c b/src/libpst.c index 06b38d2..0794187 100644 --- a/src/libpst.c +++ b/src/libpst.c @@ -60,12 +60,17 @@ pst_function_info* pst_get_function_info(pst_function* function) return &function->info; } -pst_function* pst_get_next_function(pst_handler* handler, pst_function* current) +pst_function* pst_function_next(pst_handler* handler, pst_function* current) { return pst_handler_next_function(handler, current); } -pst_parameter* pst_get_next_parameter(pst_function* function, pst_parameter* current) +pst_parameter* pst_parameter_next(pst_function* function, pst_parameter* current) { return pst_function_next_parameter(function, current); } + +pst_parameter* pst_parameter_next_child(pst_parameter* parent, pst_parameter* current) +{ + return parameter_next_child(parent, current); +}