add support of pointers to functions, small refactoring of pst_parameter
This commit is contained in:
@@ -44,13 +44,16 @@ typedef enum {
|
|||||||
PARAM_TYPE_CHAR = 0x00002000, ///< character
|
PARAM_TYPE_CHAR = 0x00002000, ///< character
|
||||||
PARAM_TYPE_UCHAR = 0x00004000, ///< unsigned character
|
PARAM_TYPE_UCHAR = 0x00004000, ///< unsigned character
|
||||||
PARAM_TYPE_REF = 0x00008000, ///< reference
|
PARAM_TYPE_REF = 0x00008000, ///< reference
|
||||||
|
PARAM_TYPE_STRING = 0x00010000, ///< pointer to C zero terminated string
|
||||||
|
PARAM_TYPE_UNSPEC = 0x00020000, ///< variable number of arguments (... in C/C++)
|
||||||
// complex types
|
// complex types
|
||||||
PARAM_TYPE_ARRAY = 0x00010000, ///< array
|
PARAM_TYPE_ARRAY = 0x00040000, ///< array
|
||||||
PARAM_TYPE_STRUCT = 0x00020000, ///< structure
|
PARAM_TYPE_STRUCT = 0x00080000, ///< structure
|
||||||
PARAM_TYPE_UNION = 0x00040000, ///< union
|
PARAM_TYPE_UNION = 0x00100000, ///< union
|
||||||
PARAM_TYPE_ENUM = 0x00080000, ///< enumeration
|
PARAM_TYPE_ENUM = 0x00200000, ///< enumeration
|
||||||
PARAM_TYPE_CLASS = 0x00100000, ///< class
|
PARAM_TYPE_CLASS = 0x00400000, ///< class
|
||||||
PARAM_TYPE_TYPEDEF = 0x00200000, ///< type definition
|
PARAM_TYPE_TYPEDEF = 0x00800000, ///< type definition
|
||||||
|
PARAM_TYPE_FUNCPTR = 0x01000000, ///< pointer to function
|
||||||
} pst_param_flags;
|
} pst_param_flags;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|||||||
@@ -314,7 +314,7 @@ bool pst_function_handle_dwarf(pst_function * fn, Dwarf_Die* d)
|
|||||||
del_param(ret_p);
|
del_param(ret_p);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
pst_parameter_add_type(ret_p, "void", 0);
|
pst_parameter_add_type(ret_p, "void", PARAM_TYPE_VOID);
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle and save additionally these attributes:
|
// handle and save additionally these attributes:
|
||||||
@@ -361,8 +361,14 @@ bool pst_function_handle_dwarf(pst_function * fn, Dwarf_Die* d)
|
|||||||
handle_lexical_block(fn, &result);
|
handle_lexical_block(fn, &result);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case DW_TAG_unspecified_parameters: {
|
||||||
|
pst_parameter* param = add_param(fn);
|
||||||
|
param->info.flags |= PARAM_TYPE_UNSPEC;
|
||||||
|
param->info.name = pst_strdup("...");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Also handle:
|
// Also handle:
|
||||||
// DW_TAG_unspecified_parameters (unknown number of arguments i.e. fun(arg1, ...);
|
|
||||||
// DW_AT_inline
|
// DW_AT_inline
|
||||||
default:
|
default:
|
||||||
pst_log(SEVERITY_DEBUG, "Unknown TAG of function: 0x%X", dwarf_tag(&result));
|
pst_log(SEVERITY_DEBUG, "Unknown TAG of function: 0x%X", dwarf_tag(&result));
|
||||||
|
|||||||
+136
-24
@@ -54,6 +54,7 @@ void pst_type_fini(pst_type* t)
|
|||||||
//
|
//
|
||||||
static void clear(pst_parameter* param)
|
static void clear(pst_parameter* param)
|
||||||
{
|
{
|
||||||
|
// clean up parameter's types
|
||||||
pst_type* t = NULL;
|
pst_type* t = NULL;
|
||||||
struct list_node *pos, *tn;
|
struct list_node *pos, *tn;
|
||||||
list_for_each_entry_safe(t, pos, tn, ¶m->types, node) {
|
list_for_each_entry_safe(t, pos, tn, ¶m->types, node) {
|
||||||
@@ -61,6 +62,13 @@ static void clear(pst_parameter* param)
|
|||||||
pst_type_fini(t);
|
pst_type_fini(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// clean up children parameters
|
||||||
|
pst_parameter* p = NULL;
|
||||||
|
list_for_each_entry_safe(p, pos, tn, ¶m->children, node) {
|
||||||
|
list_del(&p->node);
|
||||||
|
pst_parameter_fini(p);
|
||||||
|
}
|
||||||
|
|
||||||
if(param->info.name) {
|
if(param->info.name) {
|
||||||
pst_free(param->info.name);
|
pst_free(param->info.name);
|
||||||
}
|
}
|
||||||
@@ -84,17 +92,28 @@ static pst_type* next_type(pst_parameter* param, pst_type* t)
|
|||||||
bool pst_parameter_print_dwarf(pst_parameter* param)
|
bool pst_parameter_print_dwarf(pst_parameter* param)
|
||||||
{
|
{
|
||||||
if(param->info.flags & PARAM_RETURN) {
|
if(param->info.flags & PARAM_RETURN) {
|
||||||
param->ctx->print(param->ctx, "%s", param->info.type_name);
|
param->ctx->print(param->ctx, "%s", param->info.type_name ? param->info.type_name : "");
|
||||||
} else {
|
} else {
|
||||||
if(param->info.flags & PARAM_HAS_VALUE) {
|
if(param->info.flags & PARAM_TYPE_FUNCPTR) {
|
||||||
param->ctx->print(param->ctx, "%s%s %s = 0x%lX",
|
param->ctx->print(param->ctx, "%s (*%s)(", param->info.type_name ? param->info.type_name : "", param->info.name);
|
||||||
param->info.type_name ? param->info.type_name : "void"/*hack to represent void since DWARF has no ability to determine it another way*/,
|
for(pst_parameter* p = pst_parameter_next_child(param, NULL); p; p = pst_parameter_next_child(param, p)) {
|
||||||
param->info.flags & PARAM_TYPE_POINTER ? "*" : "", param->info.name, param->info.value);
|
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) ? ", " : "");
|
||||||
|
}
|
||||||
|
param->ctx->print(param->ctx, ") = ");
|
||||||
} else {
|
} else {
|
||||||
param->ctx->print(param->ctx, "%s%s %s = <undefined>",
|
param->ctx->print(param->ctx, "%s%s %s = ", param->info.type_name ? param->info.type_name : "",
|
||||||
param->info.type_name ? param->info.type_name : "void"/*hack to represent void since DWARF has no ability to determine it another way*/,
|
|
||||||
param->info.flags & PARAM_TYPE_POINTER ? "*" : "", param->info.name);
|
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);
|
||||||
|
} else {
|
||||||
|
param->ctx->print(param->ctx, "<undefined>");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -111,6 +130,97 @@ 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)
|
||||||
|
{
|
||||||
|
struct list_node* n = (p == NULL) ? list_first(¶m->children) : list_next(&p->node);
|
||||||
|
|
||||||
|
pst_parameter* ret = NULL;
|
||||||
|
if(n) {
|
||||||
|
ret = list_entry(n, pst_parameter, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pst_parameter_handle_subroutine(pst_parameter* param, Dwarf_Die* die)
|
||||||
|
{
|
||||||
|
// return value
|
||||||
|
pst_new(pst_parameter, p, param->ctx);
|
||||||
|
list_add_bottom(¶m->children, &p->node);
|
||||||
|
Dwarf_Attribute attr_mem;
|
||||||
|
Dwarf_Attribute* attr = dwarf_attr(die, DW_AT_name, &attr_mem);
|
||||||
|
if(attr) {
|
||||||
|
const char *name = dwarf_formstring(attr);
|
||||||
|
if(name) {
|
||||||
|
p->info.name = pst_strdup(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// hack since DWARF has no ability to determine 'void' it another way
|
||||||
|
if(!p->info.type_name) {
|
||||||
|
p->info.type_name = pst_strdup("void");
|
||||||
|
}
|
||||||
|
|
||||||
|
p->info.flags |= PARAM_RETURN;
|
||||||
|
|
||||||
|
Dwarf_Die result;
|
||||||
|
if(dwarf_child(die, &result) != 0) {
|
||||||
|
// no parameters defined for subroutine
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// went through arguments of subroutine
|
||||||
|
do {
|
||||||
|
switch (dwarf_tag(&result)) {
|
||||||
|
case DW_TAG_formal_parameter:
|
||||||
|
{
|
||||||
|
pst_new(pst_parameter, p1, param->ctx);
|
||||||
|
list_add_bottom(¶m->children, &p1->node);
|
||||||
|
|
||||||
|
attr = dwarf_attr(&result, DW_AT_name, &attr_mem);
|
||||||
|
if(attr) {
|
||||||
|
const char *name = dwarf_formstring(attr);
|
||||||
|
if(name) {
|
||||||
|
p1->info.name = pst_strdup(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// hack since DWARF has no ability to determine 'void' it another way
|
||||||
|
if(!p1->info.type_name) {
|
||||||
|
p1->info.type_name = pst_strdup("void");
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DW_TAG_unspecified_parameters:
|
||||||
|
{
|
||||||
|
pst_new(pst_parameter, p1, param->ctx);
|
||||||
|
list_add_bottom(¶m->children, &p1->node);
|
||||||
|
p1->info.flags |= PARAM_TYPE_UNSPEC;
|
||||||
|
p1->info.name = pst_strdup("...");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
pst_log(SEVERITY_WARNING, "Unknown TAG of pointer to function: 0x%X", dwarf_tag(&result));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while(dwarf_siblingof(&result, &result) == 0);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool pst_parameter_handle_type(pst_parameter* param, Dwarf_Attribute* base)
|
bool pst_parameter_handle_type(pst_parameter* param, Dwarf_Attribute* base)
|
||||||
{
|
{
|
||||||
Dwarf_Attribute attr_mem;
|
Dwarf_Attribute attr_mem;
|
||||||
@@ -134,40 +244,37 @@ bool pst_parameter_handle_type(pst_parameter* param, Dwarf_Attribute* base)
|
|||||||
}
|
}
|
||||||
pst_log(SEVERITY_DEBUG, "base type '%s'(%lu)", dwarf_diename(&ret_die), param->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_parameter_add_type(param, dwarf_diename(&ret_die), DW_TAG_base_type);
|
||||||
param->type = DW_TAG_base_type;
|
|
||||||
|
|
||||||
|
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) {
|
||||||
param->enc_type = 0;
|
Dwarf_Word enc_type = 0;
|
||||||
dwarf_formudata(attr, ¶m->enc_type);
|
dwarf_formudata(attr, &enc_type);
|
||||||
static const char* sizemod[] = {"", "char", "short", "", "int", "", "", "", "long long"};
|
switch (enc_type) {
|
||||||
char name[32]; name[0] = 0;
|
|
||||||
switch (param->enc_type) {
|
|
||||||
case DW_ATE_boolean:
|
case DW_ATE_boolean:
|
||||||
pst_parameter_add_type(param, "bool", PARAM_TYPE_BOOL);
|
pst_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);
|
pst_parameter_add_type(param, NULL, PARAM_TYPE_POINTER);
|
||||||
break;
|
break;
|
||||||
case DW_ATE_signed:
|
case DW_ATE_signed:
|
||||||
snprintf(name, sizeof(name), "signed %s", sizemod[param->info.size & 0x0F]);
|
pst_parameter_add_type(param, type_name, PARAM_TYPE_INT);
|
||||||
pst_parameter_add_type(param, name, PARAM_TYPE_INT);
|
|
||||||
break;
|
break;
|
||||||
case DW_ATE_unsigned:
|
case DW_ATE_unsigned:
|
||||||
snprintf(name, sizeof(name), "unsigned %s", sizemod[param->info.size & 0x0F]);
|
pst_parameter_add_type(param, type_name, PARAM_TYPE_UINT);
|
||||||
pst_parameter_add_type(param, name, PARAM_TYPE_UINT);
|
|
||||||
break;
|
break;
|
||||||
case DW_ATE_signed_char:
|
case DW_ATE_signed_char:
|
||||||
pst_parameter_add_type(param, "char", PARAM_TYPE_CHAR);
|
pst_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, "unsigned char", PARAM_TYPE_UCHAR);
|
pst_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, "float", PARAM_TYPE_FLOAT);
|
pst_parameter_add_type(param, type_name, PARAM_TYPE_FLOAT);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,7 +303,8 @@ bool pst_parameter_handle_type(pst_parameter* param, Dwarf_Attribute* base)
|
|||||||
pst_parameter_add_type(param, NULL, PARAM_CONST);
|
pst_parameter_add_type(param, NULL, PARAM_CONST);
|
||||||
break;
|
break;
|
||||||
case DW_TAG_subroutine_type:
|
case DW_TAG_subroutine_type:
|
||||||
pst_log(SEVERITY_DEBUG, "%s: Skipping subroutine type", __FUNCTION__);
|
pst_parameter_handle_subroutine(param, &ret_die);
|
||||||
|
pst_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);
|
pst_parameter_add_type(param, dwarf_diename(&ret_die), PARAM_TYPE_TYPEDEF);
|
||||||
@@ -285,6 +393,11 @@ bool pst_parameter_handle_dwarf(pst_parameter* param, Dwarf_Die* result, pst_fun
|
|||||||
|
|
||||||
//param->info.value &=0xFFFFFFFFFFFFFFFF >> (64 - ((param->info.size * 8) & 0x0F));
|
//param->info.value &=0xFFFFFFFFFFFFFFFF >> (64 - ((param->info.size * 8) & 0x0F));
|
||||||
|
|
||||||
|
// hack since DWARF has no ability to determine 'void' it another way
|
||||||
|
if(!param->info.type_name) {
|
||||||
|
param->info.type_name = pst_strdup("void");
|
||||||
|
}
|
||||||
|
|
||||||
// Additionally handle these attributes:
|
// Additionally handle these attributes:
|
||||||
// 1. DW_AT_default_value to get information about default value for DW_TAG_formal_parameter type of function
|
// 1. DW_AT_default_value to get information about default value for DW_TAG_formal_parameter type of function
|
||||||
// A DW_AT_default_value attribute for a formal parameter entry. The value of
|
// A DW_AT_default_value attribute for a formal parameter entry. The value of
|
||||||
@@ -317,9 +430,8 @@ void pst_parameter_init(pst_parameter* param, pst_context* ctx)
|
|||||||
param->info.size = 0;
|
param->info.size = 0;
|
||||||
param->info.flags = 0;
|
param->info.flags = 0;
|
||||||
|
|
||||||
param->type = 0;
|
|
||||||
param->enc_type = 0;
|
|
||||||
list_head_init(¶m->types);
|
list_head_init(¶m->types);
|
||||||
|
list_head_init(¶m->children);
|
||||||
param->ctx = ctx;
|
param->ctx = ctx;
|
||||||
pst_dwarf_expr_init(¶m->location);
|
pst_dwarf_expr_init(¶m->location);
|
||||||
param->allocated = false;
|
param->allocated = false;
|
||||||
|
|||||||
@@ -34,11 +34,10 @@ typedef struct pst_parameter{
|
|||||||
// fields
|
// fields
|
||||||
Dwarf_Die* die; // DWARF DIE containing parameter's definition
|
Dwarf_Die* die; // DWARF DIE containing parameter's definition
|
||||||
pst_parameter_info info;
|
pst_parameter_info info;
|
||||||
int type; // type of parameter in DW_TAG_XXX types enumeration
|
|
||||||
Dwarf_Word enc_type; // if 'type' is DW_TAG_Base_type, then 'base_type' holds DW_AT_ATE_XXX base type encoding type
|
|
||||||
list_head types; // list of parameter's definitions i.e. 'typedef', 'uint32_t'
|
list_head types; // list of parameter's definitions i.e. 'typedef', 'uint32_t'
|
||||||
pst_context* ctx;
|
pst_context* ctx;
|
||||||
pst_dwarf_expr location;
|
pst_dwarf_expr location;
|
||||||
|
list_head children; // sub parameters. used in case of complex types (array, pointer to function etc)
|
||||||
|
|
||||||
bool allocated;
|
bool allocated;
|
||||||
} pst_parameter;
|
} pst_parameter;
|
||||||
@@ -50,5 +49,6 @@ bool pst_parameter_handle_dwarf(pst_parameter* param, Dwarf_Die* result, pst_fun
|
|||||||
bool pst_parameter_print_dwarf(pst_parameter* param);
|
bool pst_parameter_print_dwarf(pst_parameter* param);
|
||||||
bool pst_parameter_handle_type(pst_parameter* param, Dwarf_Attribute* base);
|
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_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);
|
||||||
|
|
||||||
#endif /* __PST_DWARF_PARAMETER_H__ */
|
#endif /* __PST_DWARF_PARAMETER_H__ */
|
||||||
|
|||||||
Reference in New Issue
Block a user