better printing of parameters. export access to parameter's children

This commit is contained in:
2020-04-22 13:05:04 +04:00
parent e5531f9986
commit 39f34d7814
6 changed files with 145 additions and 91 deletions
+1 -1
View File
@@ -58,7 +58,7 @@ typedef enum {
typedef struct { typedef struct {
char* name; ///< parameter's name 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 uint32_t line; ///< line of parameter definition
unw_word_t size; ///< size of parameter in bits 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' unw_word_t value; ///< value of parameter. use 'size' to determine number of actual bits of 'value'
+10 -2
View File
@@ -65,7 +65,7 @@ const char* pst_print_simple(pst_handler* handler);
* @param current pointer to current function. NULL to get first * @param current pointer to current function. NULL to get first
* @return pointer to next function's handle, NULL in case of end of list * @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) * @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 * @param current pointer to current parameter. NULL to get first
* @return pointer to next parameter's handle, NULL in case of end of list * @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) * @brief Get parameter's information (name, type, line etc)
+9 -10
View File
@@ -167,7 +167,7 @@ bool handle_lexical_block(pst_function* fn, Dwarf_Die* result)
break; break;
case DW_TAG_variable: { case DW_TAG_variable: {
pst_parameter* param = add_param(fn); pst_parameter* param = add_param(fn);
if(!pst_parameter_handle_dwarf(param, &child, fn)) { if(!parameter_handle_dwarf(param, &child, fn)) {
del_param(param); del_param(param);
} }
break; break;
@@ -202,7 +202,7 @@ bool pst_function_print_dwarf(pst_function* fn)
pst_parameter* param = pst_function_next_parameter(fn, NULL); pst_parameter* param = pst_function_next_parameter(fn, NULL);
if(param && (param->info.flags & PARAM_RETURN)) { if(param && (param->info.flags & PARAM_RETURN)) {
// print return value type, function name and start list of parameters // 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); fn->ctx->print(fn->ctx, " %s(", fn->info.name);
param = pst_function_next_parameter(fn, param); param = pst_function_next_parameter(fn, param);
} else { } else {
@@ -213,7 +213,7 @@ bool pst_function_print_dwarf(pst_function* fn)
for(; param; param = pst_function_next_parameter(fn, param)) { for(; param; param = pst_function_next_parameter(fn, param)) {
if(param->info.flags & PARAM_RETURN) { if(param->info.flags & PARAM_RETURN) {
// print return value type, function name and start list of parameters // 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); fn->ctx->print(fn->ctx, " %s(", fn->info.name);
continue; continue;
} }
@@ -229,7 +229,7 @@ bool pst_function_print_dwarf(pst_function* fn)
} else { } else {
fn->ctx->print(fn->ctx, " "); fn->ctx->print(fn->ctx, " ");
} }
pst_parameter_print_dwarf(param); parameter_print(param);
fn->ctx->print(fn->ctx, ";\n"); fn->ctx->print(fn->ctx, ";\n");
} else { } else {
if(first) { if(first) {
@@ -237,7 +237,7 @@ bool pst_function_print_dwarf(pst_function* fn)
} else { } else {
fn->ctx->print(fn->ctx, ", "); 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 // Get reference to return attribute type of the function
// may be to use dwfl_module_return_value_location() instead // may be to use dwfl_module_return_value_location() instead
pst_parameter* ret_p = add_param(fn); ret_p->info.flags |= PARAM_RETURN; pst_parameter* ret_p = add_param(fn); ret_p->info.flags |= PARAM_RETURN;
attr = dwarf_attr(fn->die, DW_AT_type, &attr_mem); if(dwarf_hasattr(fn->die, DW_AT_type)) {
if(attr) { if(!parameter_handle_type(ret_p, fn->die)) {
if(!pst_parameter_handle_type(ret_p, attr)) {
pst_log(SEVERITY_ERROR, "Failed to handle return parameter type for function %s(...)", fn->info.name); pst_log(SEVERITY_ERROR, "Failed to handle return parameter type for function %s(...)", fn->info.name);
del_param(ret_p); del_param(ret_p);
} }
} else { } 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: // 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_formal_parameter:
case DW_TAG_variable: { case DW_TAG_variable: {
pst_parameter* param = add_param(fn); pst_parameter* param = add_param(fn);
if(!pst_parameter_handle_dwarf(param, &result, fn)) { if(!parameter_handle_dwarf(param, &result, fn)) {
del_param(param); del_param(param);
} }
+113 -71
View File
@@ -89,36 +89,83 @@ static pst_type* next_type(pst_parameter* param, pst_type* t)
return ret; return ret;
} }
bool pst_parameter_print_dwarf(pst_parameter* param) static void parameter_print_type(pst_parameter* param)
{ {
if(param->info.flags & PARAM_RETURN) { bool is_1st = true;
param->ctx->print(param->ctx, "%s", param->info.type_name ? param->info.type_name : ""); for(pst_type* t = next_type(param, NULL); t; t = next_type(param, t)) {
} else { if(is_1st) {
if(param->info.flags & PARAM_TYPE_FUNCPTR) { switch(t->type) {
param->ctx->print(param->ctx, "%s (*%s)(", param->info.type_name ? param->info.type_name : "", param->info.name); case PARAM_CONST:
for(pst_parameter* p = pst_parameter_next_child(param, NULL); p; p = pst_parameter_next_child(param, p)) { param->ctx->print(param->ctx, "%s", "const ");
if(p->info.flags & PARAM_RETURN) { break;
// skip return value case PARAM_TYPE_STRUCT:
continue; param->ctx->print(param->ctx, "%s", "struct ");
} break;
param->ctx->print(param->ctx, "%s%s%s", p->info.type_name ? p->info.type_name : "", p->info.flags & PARAM_TYPE_POINTER ? "*" : "", case PARAM_TYPE_UNION:
(pst_parameter_next_child(param, p) != NULL) ? ", " : ""); 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", param->info.type_name ? param->info.type_name : "");
param->ctx->print(param->ctx, "%s%s %s = ", param->info.type_name ? param->info.type_name : "", is_1st = false;
param->info.flags & PARAM_TYPE_POINTER ? "*" : "", param->info.name);
} }
if(param->info.flags & PARAM_HAS_VALUE) {
param->ctx->print(param->ctx, "0x%lX", param->info.value); switch(t->type) {
} else { case PARAM_TYPE_POINTER:
param->ctx->print(param->ctx, "<undefined>"); 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, "<undefined>");
}
}
pst_type* parameter_add_type(pst_parameter* param, const char* name, pst_param_flags type)
{ {
pst_new(pst_type, t, name, type); pst_new(pst_type, t, name, type);
list_add_bottom(&param->types, &t->node); list_add_bottom(&param->types, &t->node);
@@ -130,7 +177,7 @@ pst_type* pst_parameter_add_type(pst_parameter* param, const char* name, pst_par
return t; 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(&param->children) : list_next(&p->node); struct list_node* n = (p == NULL) ? list_first(&param->children) : list_next(&p->node);
@@ -142,7 +189,7 @@ pst_parameter* pst_parameter_next_child(pst_parameter* param, pst_parameter* p)
return ret; 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 // return value
pst_new(pst_parameter, p, param->ctx); 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 parameter_handle_type(param, die);
attr = dwarf_attr(die, DW_AT_type, &attr_mem);
if(attr) {
pst_parameter_handle_type(param, attr);
}
// 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) { if(!p->info.type_name) {
p->info.type_name = pst_strdup("void"); 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 parameter_handle_type(p1, &result);
attr = dwarf_attr(&result, DW_AT_type, &attr_mem);
if(attr) {
pst_parameter_handle_type(p1, attr);
}
// hack since DWARF has no ability to determine 'void' it another way // hack since DWARF has no ability to determine 'void' it another way
if(!p1->info.type_name) { if(!p1->info.type_name) {
@@ -221,100 +260,107 @@ bool pst_parameter_handle_subroutine(pst_parameter* param, Dwarf_Die* die)
return true; 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_mem;
Dwarf_Attribute* attr; Dwarf_Attribute* attr;
// get DIE of return type // get DIE of type
Dwarf_Die ret_die; Dwarf_Die ret_die;
if(!dwarf_formref_die(base, &ret_die)) { // Get reference to attribute type of the parameter/variable
pst_log(SEVERITY_ERROR, "Failed to get parameter DIE"); 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; return false;
} }
param->info.size = 64; param->info.size = 64;
switch (dwarf_tag(&ret_die)) { switch (dwarf_tag(&ret_die)) {
// base types
case DW_TAG_base_type: { case DW_TAG_base_type: {
// get Size attribute and it's value // get Size attribute and it's value
attr = dwarf_attr(&ret_die, DW_AT_byte_size, &attr_mem); attr = dwarf_attr(&ret_die, DW_AT_byte_size, &attr_mem);
if(attr) { if(attr) {
dwarf_formudata(attr, &param->info.size); dwarf_formudata(attr, &param->info.size);
} }
pst_log(SEVERITY_DEBUG, "base type '%s'(%lu)", dwarf_diename(&ret_die), param->info.size); pst_log(SEVERITY_DEBUG, "%s: Base type '%s'(%lu)", __FUNCTION__, dwarf_diename(&ret_die), param->info.size);
pst_parameter_add_type(param, dwarf_diename(&ret_die), DW_TAG_base_type);
const char* type_name = dwarf_diename(&ret_die); 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); attr = dwarf_attr(&ret_die, DW_AT_encoding, &attr_mem);
if(attr) { if(attr) {
Dwarf_Word enc_type = 0; Dwarf_Word enc_type = 0;
dwarf_formudata(attr, &enc_type); dwarf_formudata(attr, &enc_type);
switch (enc_type) { switch (enc_type) {
case DW_ATE_boolean: case DW_ATE_boolean:
pst_parameter_add_type(param, type_name, PARAM_TYPE_BOOL); parameter_add_type(param, type_name, PARAM_TYPE_BOOL);
break; break;
case DW_ATE_address: case DW_ATE_address:
pst_parameter_add_type(param, NULL, PARAM_TYPE_POINTER); parameter_add_type(param, NULL, PARAM_TYPE_POINTER);
break; break;
case DW_ATE_signed: case DW_ATE_signed:
pst_parameter_add_type(param, type_name, PARAM_TYPE_INT); parameter_add_type(param, type_name, PARAM_TYPE_INT);
break; break;
case DW_ATE_unsigned: case DW_ATE_unsigned:
pst_parameter_add_type(param, type_name, PARAM_TYPE_UINT); parameter_add_type(param, type_name, PARAM_TYPE_UINT);
break; break;
case DW_ATE_signed_char: 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; break;
case DW_ATE_unsigned_char: 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; break;
case DW_ATE_float: case DW_ATE_float:
case DW_ATE_complex_float: case DW_ATE_complex_float:
case DW_ATE_imaginary_float: case DW_ATE_imaginary_float:
case DW_ATE_decimal_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;
} }
} }
break; break;
} }
// complex types
case DW_TAG_array_type: case DW_TAG_array_type:
pst_parameter_add_type(param, NULL, PARAM_TYPE_ARRAY); parameter_add_type(param, NULL, PARAM_TYPE_ARRAY);
break; break;
case DW_TAG_structure_type: case DW_TAG_structure_type:
pst_parameter_add_type(param, NULL, PARAM_TYPE_STRUCT); parameter_add_type(param, NULL, PARAM_TYPE_STRUCT);
break; break;
case DW_TAG_union_type: case DW_TAG_union_type:
pst_parameter_add_type(param, NULL, PARAM_TYPE_UNION); parameter_add_type(param, NULL, PARAM_TYPE_UNION);
break; break;
case DW_TAG_class_type: case DW_TAG_class_type:
pst_parameter_add_type(param, NULL, PARAM_TYPE_CLASS); parameter_add_type(param, NULL, PARAM_TYPE_CLASS);
break; break;
case DW_TAG_pointer_type: case DW_TAG_pointer_type:
pst_parameter_add_type(param, NULL, PARAM_TYPE_POINTER); parameter_add_type(param, NULL, PARAM_TYPE_POINTER);
break; break;
case DW_TAG_enumeration_type: case DW_TAG_enumeration_type:
pst_parameter_add_type(param, NULL, PARAM_TYPE_ENUM); parameter_add_type(param, NULL, PARAM_TYPE_ENUM);
break; break;
case DW_TAG_const_type: case DW_TAG_const_type:
pst_parameter_add_type(param, NULL, PARAM_CONST); parameter_add_type(param, NULL, PARAM_CONST);
break; break;
case DW_TAG_subroutine_type: case DW_TAG_subroutine_type:
pst_parameter_handle_subroutine(param, &ret_die); handle_subroutine(param, &ret_die);
pst_parameter_add_type(param, NULL, PARAM_TYPE_FUNCPTR); parameter_add_type(param, NULL, PARAM_TYPE_FUNCPTR);
break; break;
case DW_TAG_typedef: { 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; break;
} }
case DW_TAG_unspecified_type: case DW_TAG_unspecified_type:
pst_parameter_add_type(param, "void", PARAM_TYPE_VOID); parameter_add_type(param, "void", PARAM_TYPE_VOID);
break; break;
case DW_TAG_reference_type: case DW_TAG_reference_type:
pst_parameter_add_type(param, NULL, PARAM_TYPE_REF); parameter_add_type(param, NULL, PARAM_TYPE_REF);
break; break;
default: default:
@@ -322,15 +368,15 @@ bool pst_parameter_handle_type(pst_parameter* param, Dwarf_Attribute* base)
break; break;
} }
attr = dwarf_attr(&ret_die, DW_AT_type, &attr_mem); if(dwarf_hasattr(&ret_die, DW_AT_type)) {
if(attr) { // handle parameter's sub-type
return pst_parameter_handle_type(param, attr); return parameter_handle_type(param, &ret_die);
} }
return true; 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; 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; param->info.flags |= (dwarf_tag(result) == DW_TAG_variable) ? PARAM_VARIABLE : 0;
dwarf_decl_line(result, (int*)&param->info.line); dwarf_decl_line(result, (int*)&param->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"); pst_log(SEVERITY_DEBUG, "---> Handle '%s' %s", param->info.name, dwarf_tag(result) == DW_TAG_formal_parameter ? "parameter" : "variable");
if(attr) { parameter_handle_type(param, result);
pst_parameter_handle_type(param, attr);
}
if(dwarf_hasattr(result, DW_AT_location)) { if(dwarf_hasattr(result, DW_AT_location)) {
// determine location of parameter in stack/heap or CPU registers // determine location of parameter in stack/heap or CPU registers
+5 -5
View File
@@ -45,10 +45,10 @@ void pst_parameter_init(pst_parameter* param, pst_context* ctx);
pst_parameter* pst_parameter_new(pst_context* ctx); pst_parameter* pst_parameter_new(pst_context* ctx);
void pst_parameter_fini(pst_parameter* param); void pst_parameter_fini(pst_parameter* param);
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);
bool pst_parameter_print_dwarf(pst_parameter* param); void parameter_print(pst_parameter* param);
bool pst_parameter_handle_type(pst_parameter* param, Dwarf_Attribute* base); bool parameter_handle_type(pst_parameter* param, Dwarf_Die* result);
pst_type* pst_parameter_add_type(pst_parameter* param, const char* name, pst_param_flags type); pst_type* 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); pst_parameter* parameter_next_child(pst_parameter* param, pst_parameter* p);
#endif /* __PST_DWARF_PARAMETER_H__ */ #endif /* __PST_DWARF_PARAMETER_H__ */
+7 -2
View File
@@ -60,12 +60,17 @@ pst_function_info* pst_get_function_info(pst_function* function)
return &function->info; 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); 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); 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);
}