I now read the DWARF data in addition to the .conf files
[platform/upstream/ltrace.git] / dwarf_prototypes.c
index 9f03384..1068bbb 100644 (file)
 //#define DUMP_PROTOTYPES
 
 #if 1
-#define complain( die, format, ... )                                                   \
+#define complain(die, format, ...)                                                             \
        fprintf(stderr, "%s() die '%s' @ 0x%lx: " format "\n",          \
                        __func__, dwarf_diename(die), dwarf_dieoffset(die),     \
-                       ##__VA_ARGS__ )
+                       ##__VA_ARGS__)
 #else
-#define complain( die, format, ... )
+#define complain(die, format, ...)
 #endif
 
+#define NEXT_SIBLING(die)                                                              \
+       int res = dwarf_siblingof(die, die);                            \
+       if (res == 0) continue;     /* sibling exists    */     \
+       if (res < 0)  return false; /* error             */     \
+       break                       /* no sibling exists */
+
 // A map from DIE addresses (Dwarf_Off) to type structures (struct
 // arg_type_info*). This is created and filled in at the start of each import,
 // and deleted when the import is complete
 static struct dict type_hash;
 
 
-static bool get_type(struct arg_type_info** info, Dwarf_Die* type_die);
+static bool get_type(struct arg_type_info** info, Dwarf_Die* type_die, struct protolib* plib);
 
 
 #if 0
@@ -59,10 +65,7 @@ static bool _dump_dwarf_tree(Dwarf_Die* die, int indent)
                                return false;
         }
 
-        int res = dwarf_siblingof(die, die);
-        if (res == 0 ) continue;     // sibling exists
-        if (res < 0 )  return false; // error
-        break;                       // no sibling exists
+        SIBLING(die);
     }
 
     return true;
@@ -70,7 +73,7 @@ static bool _dump_dwarf_tree(Dwarf_Die* die, int indent)
 
 static bool dump_dwarf_tree(Dwarf_Die* die)
 {
-    return _dump_dwarf_tree( die, 0 );
+    return _dump_dwarf_tree(die, 0);
 }
 #endif
 
@@ -111,7 +114,7 @@ static bool _dump_ltrace_tree(const struct arg_type_info* info, int indent)
 
        case ARGTYPE_POINTER:
                fprintf(stderr, "%*s%p pointer to...\n", indent*4, "", (void*)info);
-               _dump_ltrace_tree( info->u.ptr_info.info, indent+1 );
+               _dump_ltrace_tree(info->u.ptr_info.info, indent+1);
                break;
 
        case ARGTYPE_STRUCT:
@@ -123,7 +126,7 @@ static bool _dump_ltrace_tree(const struct arg_type_info* info, int indent)
                }* elements = (struct struct_field*)info->u.entries.data;
                unsigned int i;
                for(i=0; i<info->u.entries.size; i++)
-                       _dump_ltrace_tree( elements[i].info, indent+1 );
+                       _dump_ltrace_tree(elements[i].info, indent+1);
                break;
 
        default:
@@ -136,7 +139,7 @@ static bool _dump_ltrace_tree(const struct arg_type_info* info, int indent)
 
 static bool dump_ltrace_tree(const struct arg_type_info* info)
 {
-       return _dump_ltrace_tree( info, 0 );
+       return _dump_ltrace_tree(info, 0);
 }
 #endif
 
@@ -192,7 +195,7 @@ static bool get_die_numeric(uint64_t* result,
 #undef PROCESS_NUMERIC
 }
 
-static bool get_integer_base_type( enum arg_type* type, int byte_size, bool is_signed )
+static bool get_integer_base_type(enum arg_type* type, int byte_size, bool is_signed)
 {
        switch (byte_size) {
        case sizeof(char):
@@ -219,13 +222,13 @@ static bool get_integer_base_type( enum arg_type* type, int byte_size, bool is_s
 static enum arg_type get_base_type(Dwarf_Die* die)
 {
        int64_t encoding;
-       if( !get_die_numeric((uint64_t*)&encoding, die, DW_AT_encoding) )
+       if(!get_die_numeric((uint64_t*)&encoding, die, DW_AT_encoding))
                return ARGTYPE_VOID;
 
-       if (encoding == DW_ATE_void )
+       if (encoding == DW_ATE_void)
                return ARGTYPE_VOID;
 
-       if (encoding == DW_ATE_signed_char || encoding == DW_ATE_unsigned_char )
+       if (encoding == DW_ATE_signed_char || encoding == DW_ATE_unsigned_char)
                return ARGTYPE_CHAR;
 
                uint64_t byte_size;
@@ -352,13 +355,13 @@ static bool get_enum(struct arg_type_info* enum_info, Dwarf_Die* parent)
                        return false;
                }
 
-               struct value* value = calloc( 1, sizeof(struct value));
+               struct value* value = calloc(1, sizeof(struct value));
                if (value == NULL) {
                        complain(&die, "Couldn't alloc enum value");
                        return false;
                }
 
-               value_init_detached(value, NULL, type_get_simple( enum_info->type ), 0);
+               value_init_detached(value, NULL, type_get_simple(enum_info->type), 0);
                uint64_t enum_value;
                if (!get_die_numeric(&enum_value, &die, DW_AT_const_value)) {
                        complain(&die, "Couldn't get enum value");
@@ -367,31 +370,28 @@ static bool get_enum(struct arg_type_info* enum_info, Dwarf_Die* parent)
 
                value_set_word(value, (long)enum_value);
 
-               if (lens_enum_add( lens, dupkey, 0, value, 0 )) {
+               if (lens_enum_add(lens, dupkey, 0, value, 0)) {
                        complain(&die, "Couldn't add enum element");
                        return false;
                }
 
-               int res = dwarf_siblingof(&die, &die);
-               if (res == 0) continue;     /* sibling exists    */
-               if (res < 0)  return false; /* error             */
-               break;                      /* no sibling exists */
+               NEXT_SIBLING(&die);
        }
 
        return true;
 }
 
-static bool get_array(struct arg_type_info* array_info, Dwarf_Die* parent)
+static bool get_array(struct arg_type_info* array_info, Dwarf_Die* parent, struct protolib* plib)
 {
        Dwarf_Die type_die;
-       if (!get_type_die( &type_die, parent )) {
-               complain( parent, "Array has unknown type" );
+       if (!get_type_die(&type_die, parent)) {
+               complain(parent, "Array has unknown type");
                return false;
        }
 
        struct arg_type_info* info;
-       if (!get_type( &info, &type_die )) {
-               complain( parent, "Couldn't figure out array's type" );
+       if (!get_type(&info, &type_die, plib)) {
+               complain(parent, "Couldn't figure out array's type");
                return false;
        }
 
@@ -412,12 +412,12 @@ static bool get_array(struct arg_type_info* array_info, Dwarf_Die* parent)
        if (dwarf_hasattr(&subrange, DW_AT_lower_bound)) {
                uint64_t lower_bound;
                if (!get_die_numeric(&lower_bound, &subrange, DW_AT_lower_bound)) {
-                       complain( parent, "Couldn't read lower bound");
+                       complain(parent, "Couldn't read lower bound");
                        return false;
                }
 
                if (lower_bound != 0) {
-                       complain( parent,
+                       complain(parent,
                                          "Array subrange has a nonzero lower bound. Don't know what to do");
                        return false;
                }
@@ -432,7 +432,7 @@ static bool get_array(struct arg_type_info* array_info, Dwarf_Die* parent)
        else
        {
                if (!get_die_numeric(&N, &subrange, DW_AT_upper_bound)) {
-                       complain( parent, "Couldn't read upper bound");
+                       complain(parent, "Couldn't read upper bound");
                        return false;
                }
                N++;
@@ -441,27 +441,27 @@ static bool get_array(struct arg_type_info* array_info, Dwarf_Die* parent)
        // I'm not checking the subrange type. It should be some sort of integer,
        // and I don't know what it would mean for it to be something else
 
-       struct value* value = calloc( 1, sizeof(struct value));
+       struct value* value = calloc(1, sizeof(struct value));
        if (value == NULL) {
                complain(&subrange, "Couldn't alloc length value");
                return false;
        }
-       value_init_detached(value, NULL, type_get_simple( ARGTYPE_INT ), 0);
-       value_set_word(value, N );
+       value_init_detached(value, NULL, type_get_simple(ARGTYPE_INT), 0);
+       value_set_word(value, N);
 
-       struct expr_node* length = calloc( 1, sizeof(struct expr_node));
+       struct expr_node* length = calloc(1, sizeof(struct expr_node));
        if (length == NULL) {
                complain(&subrange, "Couldn't alloc length expr");
                return false;
        }
        expr_init_const(length, value);
 
-       type_init_array(array_info, info, 0, length, 0 );
+       type_init_array(array_info, info, 0, length, 0);
 
        return true;
 }
 
-static bool get_structure(struct arg_type_info* struct_info, Dwarf_Die* parent)
+static bool get_structure(struct arg_type_info* struct_info, Dwarf_Die* parent, struct protolib* plib)
 {
        type_init_struct(struct_info);
 
@@ -480,22 +480,19 @@ static bool get_structure(struct arg_type_info* struct_info, Dwarf_Die* parent)
                }
 
                Dwarf_Die type_die;
-               if (!get_type_die( &type_die, &die )) {
-                       complain( &die, "Couldn't get type of element");
+               if (!get_type_die(&type_die, &die)) {
+                       complain(&die, "Couldn't get type of element");
                        return false;
                }
 
                struct arg_type_info* member_info = NULL;
-               if (!get_type( &member_info, &type_die )) {
+               if (!get_type(&member_info, &type_die, plib)) {
                        complain(&die, "Couldn't parse type from DWARF data");
                        return false;
                }
-               type_struct_add( struct_info, member_info, 0 );
+               type_struct_add(struct_info, member_info, 0);
 
-               int res = dwarf_siblingof(&die, &die);
-               if (res == 0) continue;     /* sibling exists    */
-               if (res < 0)  return false; /* error             */
-               break;                      /* no sibling exists */
+               NEXT_SIBLING(&die);
        }
 
        return true;
@@ -503,45 +500,60 @@ static bool get_structure(struct arg_type_info* struct_info, Dwarf_Die* parent)
 
 // Reads the type in the die into the given structure
 // Returns true on sucess
-static bool get_type(struct arg_type_info** info, Dwarf_Die* type_die)
+static bool get_type(struct arg_type_info** info, Dwarf_Die* type_die, struct protolib* plib)
 {
        Dwarf_Off die_offset = dwarf_dieoffset(type_die);
-       struct arg_type_info** found_type = dict_find(&type_hash, &die_offset );
+       struct arg_type_info** found_type = dict_find(&type_hash, &die_offset);
        if (found_type != NULL) {
                *info = *found_type;
                complain(type_die, "Read pre-computed type: %p", *info);
                return true;
        }
 
+       const char* type_name = dwarf_diename(type_die);
+       if (type_name != NULL) {
+
+               struct named_type* already_defined_type =
+                       protolib_lookup_type(plib, type_name, false);
+
+               if (already_defined_type != NULL) {
+                       complain(type_die,
+                                        "Type '%s' defined in a .conf file. Using that instead of DWARF",
+                                        type_name);
+                       *info = already_defined_type->info;
+                       return true;
+               }
+       }
+
        Dwarf_Die next_die;
 
        switch (dwarf_tag(type_die)) {
        case DW_TAG_base_type:
-               *info = type_get_simple( get_base_type( type_die ));
+               *info = type_get_simple(get_base_type(type_die));
                complain(type_die, "Storing base type: %p", *info);
-               dict_insert( &type_hash, &die_offset, info );
+               dict_insert(&type_hash, &die_offset, info);
                return true;
 
        case DW_TAG_subroutine_type:
        case DW_TAG_inlined_subroutine:
                // function pointers are stored as void*. If ltrace tries to dereference
                // these, it'll get a segfault
-               *info = type_get_simple( ARGTYPE_VOID );
+               *info = type_get_simple(ARGTYPE_VOID);
                complain(type_die, "Storing subroutine type: %p", *info);
-               dict_insert( &type_hash, &die_offset, info );
+               dict_insert(&type_hash, &die_offset, info);
                return true;
 
        case DW_TAG_pointer_type:
 
-               if (!get_type_die(&next_die, type_die )) {
+               if (!get_type_die(&next_die, type_die)) {
                        // the pointed-to type isn't defined, so I report a void*
-                       *info = type_get_simple( ARGTYPE_VOID );
+                       *info = type_get_simple(ARGTYPE_VOID);
                        complain(type_die, "Storing void-pointer type: %p", *info);
-                       dict_insert( &type_hash, &die_offset, info );
+                       dict_insert(&type_hash, &die_offset, info);
                        return true;
                }
 
-               *info = calloc( 1, sizeof(struct arg_type_info));
+               *info = calloc(1, sizeof(struct arg_type_info));
                if (*info == NULL) {
                        complain(type_die, "alloc error");
                        return false;
@@ -549,65 +561,66 @@ static bool get_type(struct arg_type_info** info, Dwarf_Die* type_die)
                type_init_pointer(*info, NULL, 0);
 
                complain(type_die, "Storing pointer type: %p", *info);
-               dict_insert( &type_hash, &die_offset, info );
-               return get_type( &(*info)->u.ptr_info.info, &next_die );
+               dict_insert(&type_hash, &die_offset, info);
+               return get_type(&(*info)->u.ptr_info.info, &next_die, plib);
 
        case DW_TAG_structure_type:
-               *info = calloc( 1, sizeof(struct arg_type_info));
+               *info = calloc(1, sizeof(struct arg_type_info));
                if (*info == NULL) {
                        complain(type_die, "alloc error");
                        return false;
                }
 
                complain(type_die, "Storing struct type: %p", *info);
-               dict_insert( &type_hash, &die_offset, info );
-               return get_structure( *info, type_die );
+               dict_insert(&type_hash, &die_offset, info);
+               return get_structure(*info, type_die, plib);
 
 
-       case DW_TAG_typedef: ;
-       case DW_TAG_const_type: ;
-       case DW_TAG_volatile_type: ;
+       case DW_TAG_typedef:
+       case DW_TAG_const_type:
+       case DW_TAG_volatile_type: {
                // Various tags are simply pass-through, so I just keep going
                bool res = true;
-               if (get_type_die(&next_die, type_die )) {
+               if (get_type_die(&next_die, type_die)) {
                        complain(type_die, "Storing const/typedef type: %p", *info);
-                       res = get_type( info, &next_die );
+                       res = get_type(info, &next_die, plib);
                } else {
                        // no type. Use 'void'. Normally I'd think this is bogus, but stdio
                        // typedefs something to void
-                       *info = type_get_simple( ARGTYPE_VOID );
+                       *info = type_get_simple(ARGTYPE_VOID);
                        complain(type_die, "Storing void type: %p", *info);
                }
-               if (res )
-                       dict_insert( &type_hash, &die_offset, info );
+               if (res)
+                       dict_insert(&type_hash, &die_offset, info);
                return res;
+       }
 
        case DW_TAG_enumeration_type:
                // We have an enumeration. This has type "int", but has a particular
                // lens to handle the enum
-               *info = calloc( 1, sizeof(struct arg_type_info));
+               *info = calloc(1, sizeof(struct arg_type_info));
                if (*info == NULL) {
                        complain(type_die, "alloc error");
                        return false;
                }
 
                complain(type_die, "Storing enum int: %p", *info);
-               dict_insert( &type_hash, &die_offset, info );
-               return get_enum( *info, type_die );
+               dict_insert(&type_hash, &die_offset, info);
+               return get_enum(*info, type_die);
 
        case DW_TAG_array_type:
-               *info = calloc( 1, sizeof(struct arg_type_info));
+               *info = calloc(1, sizeof(struct arg_type_info));
                if (*info == NULL) {
                        complain(type_die, "alloc error");
                        return false;
                }
 
                complain(type_die, "Storing array: %p", *info);
-               dict_insert( &type_hash, &die_offset, info );
-               return get_array( *info, type_die );
+               dict_insert(&type_hash, &die_offset, info);
+               return get_array(*info, type_die, plib);
 
        case DW_TAG_union_type:
-               *info = type_get_simple( ARGTYPE_VOID );
+               *info = type_get_simple(ARGTYPE_VOID);
                complain(type_die, "Storing union-as-void type: %p", *info);
                return true;
 
@@ -619,23 +632,23 @@ static bool get_type(struct arg_type_info** info, Dwarf_Die* type_die)
        return false;
 }
 
-static bool get_prototype(struct prototype* proto, Dwarf_Die* subroutine)
+static bool get_prototype(struct prototype* proto, Dwarf_Die* subroutine, struct protolib* plib)
 {
        // First, look at the return type. This is stored in a DW_AT_type tag in the
        // subroutine DIE. If there is no such tag, this function returns void
        Dwarf_Die return_type_die;
-       if (!get_type_die(&return_type_die, subroutine )) {
-               proto->return_info = type_get_simple( ARGTYPE_VOID );
+       if (!get_type_die(&return_type_die, subroutine)) {
+               proto->return_info = type_get_simple(ARGTYPE_VOID);
                proto->own_return_info = 0;
        } else {
-               proto->return_info = calloc( 1, sizeof( struct arg_type_info ));
+               proto->return_info = calloc(1, sizeof(struct arg_type_info));
                if (proto->return_info == NULL) {
                        complain(subroutine, "Couldn't alloc return type");
                        return false;
                }
                proto->own_return_info = 0;
 
-               if (!get_type( &proto->return_info, &return_type_die )) {
+               if (!get_type(&proto->return_info, &return_type_die, plib)) {
                        complain(subroutine, "Couldn't get return type");
                        return false;
                }
@@ -650,109 +663,106 @@ static bool get_prototype(struct prototype* proto, Dwarf_Die* subroutine)
        }
 
        while(1) {
-               if (dwarf_tag(&arg_die) != DW_TAG_formal_parameter )
-                       goto next_prototype_argument;
+               if (dwarf_tag(&arg_die) == DW_TAG_formal_parameter) {
 
-               complain(&arg_die, "arg: 0x%02x", dwarf_tag(&arg_die));
+                       complain(&arg_die, "arg: 0x%02x", dwarf_tag(&arg_die));
 
-               Dwarf_Die type_die;
-               if (!get_type_die(&type_die, &arg_die )) {
-                       complain(&arg_die, "Couldn't get the argument type die");
-                       return false;
-               }
+                       Dwarf_Die type_die;
+                       if (!get_type_die(&type_die, &arg_die)) {
+                               complain(&arg_die, "Couldn't get the argument type die");
+                               return false;
+                       }
 
-               struct arg_type_info* arg_type_info = NULL;
-               if (!get_type( &arg_type_info, &type_die )) {
-                       complain(&arg_die, "Couldn't parse arg type from DWARF data");
-                       return false;
-               }
+                       struct arg_type_info* arg_type_info = NULL;
+                       if (!get_type(&arg_type_info, &type_die, plib)) {
+                               complain(&arg_die, "Couldn't parse arg type from DWARF data");
+                               return false;
+                       }
 
-               struct param param;
-               param_init_type(&param, arg_type_info, 0);
-               if (prototype_push_param(proto, &param) <0) {
-                       complain(&arg_die, "couldn't add argument to the prototype");
-                       return false;
-               }
+                       struct param param;
+                       param_init_type(&param, arg_type_info, 0);
+                       if (prototype_push_param(proto, &param) <0) {
+                               complain(&arg_die, "couldn't add argument to the prototype");
+                               return false;
+                       }
 
 #ifdef DUMP_PROTOTYPES
-               fprintf(stderr, "Adding argument:\n");
-               dump_ltrace_tree(arg_type_info);
+                       fprintf(stderr, "Adding argument:\n");
+                       dump_ltrace_tree(arg_type_info);
 #endif
+               }
 
-       next_prototype_argument: ;
-               int res = dwarf_siblingof(&arg_die, &arg_die);
-               if (res == 0) continue;     /* sibling exists    */
-               if (res < 0)  return false; /* error             */
-               break;                      /* no sibling exists */
+               NEXT_SIBLING(&arg_die);
        }
 
        return true;
 }
 
-static bool process_die_compileunit(struct protolib* plib, struct library* lib,
-                                                                       Dwarf_Die* parent)
+static bool import_subprogram(struct protolib* plib, struct library* lib,
+                                                         Dwarf_Die* die)
 {
-       Dwarf_Die die;
-       if (dwarf_child(parent, &die) != 0) {
-               // no child nodes, so nothing to do
+       // I use the linkage function name if there is one, otherwise the
+       // plain name
+       const char* function_name = NULL;
+       Dwarf_Attribute attr;
+       if (dwarf_attr(die, DW_AT_linkage_name, &attr) != NULL)
+               function_name = dwarf_formstring(&attr);
+       if (function_name == NULL)
+               function_name = dwarf_diename(die);
+       if (function_name == NULL) {
+               complain(die, "Function has no name. Not importing");
                return true;
        }
 
-       while (1) {
-               if (dwarf_tag(&die) == DW_TAG_subprogram) {
-
-                       // I use the linkage function name if there is one, otherwise the
-                       // plain name
-                       const char* function_name = NULL;
-                       Dwarf_Attribute attr;
-                       if (dwarf_attr(&die, DW_AT_linkage_name, &attr) != NULL)
-                               function_name = dwarf_formstring(&attr);
-                       if (function_name == NULL)
-                               function_name = dwarf_diename(&die);
-                       if (function_name == NULL) {
-                               complain(&die, "Function has no name. Not importing" );
-                               goto next_prototype;
-                       }
+       if (!filter_matches_symbol(options.plt_filter,    function_name, lib) &&
+               !filter_matches_symbol(options.static_filter, function_name, lib) &&
+               !filter_matches_symbol(options.export_filter, function_name, lib)) {
+               complain(die, "Prototype not requested by any filter");
+               return true;
+       }
 
+       complain(die, "subroutine_type: 0x%02x; function '%s'",
+                        dwarf_tag(die), function_name);
 
-                       complain(&die, "subroutine_type: 0x%02x; function '%s'",
-                                        dwarf_tag(&die), function_name);
+       struct prototype* proto =
+               protolib_lookup_prototype(plib, function_name, false);
 
-                       struct prototype* proto =
-                               protolib_lookup_prototype(plib, function_name, true );
+       if (proto != NULL) {
+               complain(die, "Prototype already exists. Skipping");
+               return true;
+       }
 
-                       if (proto != NULL) {
-                               complain(&die, "Prototype already exists. Skipping");
-                               goto next_prototype;
-                       }
+       proto = malloc(sizeof(struct prototype));
+       if (proto == NULL) {
+               complain(die, "couldn't alloc prototype");
+               return false;
+       }
+       prototype_init(proto);
 
-                       if (!filter_matches_symbol(options.plt_filter,    function_name, lib) &&
-                               !filter_matches_symbol(options.static_filter, function_name, lib) &&
-                               !filter_matches_symbol(options.export_filter, function_name, lib)) {
-                               complain(&die, "Prototype not requested by any filter");
-                               goto next_prototype;
-                       }
+       if (!get_prototype(proto, die, plib)) {
+               complain(die, "couldn't get prototype");
+               return false;
+       }
 
-                       proto = malloc(sizeof(struct prototype));
-                       if (proto == NULL) {
-                               complain(&die, "couldn't alloc prototype");
-                               return false;
-                       }
-                       prototype_init( proto );
+       protolib_add_prototype(plib, function_name, 0, proto);
+       return true;
+}
 
-                       if (!get_prototype(proto, &die )) {
-                               complain(&die, "couldn't get prototype");
-                               return false;
-                       }
+static bool process_die_compileunit(struct protolib* plib, struct library* lib,
+                                                                       Dwarf_Die* parent)
+{
+       Dwarf_Die die;
+       if (dwarf_child(parent, &die) != 0) {
+               // no child nodes, so nothing to do
+               return true;
+       }
 
-                       protolib_add_prototype(plib, function_name, 0, proto);
-               }
+       while (1) {
+               if (dwarf_tag(&die) == DW_TAG_subprogram)
+                       if(!import_subprogram(plib, lib, &die))
+                               return false;
 
-               next_prototype:;
-               int res = dwarf_siblingof(&die, &die);
-               if (res == 0) continue;     /* sibling exists    */
-               if (res < 0)  return false; /* error             */
-               break;                      /* no sibling exists */
+               NEXT_SIBLING(&die);
        }
 
        return true;
@@ -761,7 +771,7 @@ static bool process_die_compileunit(struct protolib* plib, struct library* lib,
 static bool import(struct protolib* plib, struct library* lib, Dwfl* dwfl)
 {
        dict_init(&type_hash, sizeof(Dwarf_Off), sizeof(struct arg_type_info*),
-                         dwarf_die_hash, dwarf_die_eq, NULL );
+                         dwarf_die_hash, dwarf_die_eq, NULL);
 
        Dwarf_Addr bias;
     Dwarf_Die* die = NULL;
@@ -779,13 +789,15 @@ static bool import(struct protolib* plib, struct library* lib, Dwfl* dwfl)
         }
     }
 
-       dict_destroy( &type_hash, NULL, NULL, NULL );
+       dict_destroy(&type_hash, NULL, NULL, NULL);
        return true;
 }
 
-bool import_DWARF_prototypes(struct protolib* plib, struct library* lib,
-                                                        Dwfl *dwfl)
+bool import_DWARF_prototypes(struct library* lib)
 {
+       struct protolib*        plib = lib->protolib;
+       Dwfl*                           dwfl = lib->dwfl;
+
        if (plib == NULL) {
                plib = protolib_cache_default(&g_protocache, lib->soname, 0);
                if (plib == NULL) {
@@ -794,7 +806,11 @@ bool import_DWARF_prototypes(struct protolib* plib, struct library* lib,
                }
        }
 
-       return import(plib, lib, dwfl);
+       if (import(plib, lib, dwfl)) {
+               lib->protolib = plib;
+               return true;
+       }
+       return false;
 }
 
 /*
@@ -808,6 +824,5 @@ bool import_DWARF_prototypes(struct protolib* plib, struct library* lib,
 
 - all my *allocs leak
 
-- protolib_lookup_prototype should look for imports?
 
 */