diff --git a/btf_loader.c b/btf_loader.c index 4ad0c3f..e61e4d0 100644 --- a/btf_loader.c +++ b/btf_loader.c @@ -83,6 +83,25 @@ out_free_parameters: return -ENOMEM; } +static int create_new_function(struct btf_elf *btfe, struct btf_type *tp, uint64_t size, uint32_t id) +{ + strings_t name = btf_elf__get32(btfe, &tp->name_off); + unsigned int type_id = btf_elf__get32(btfe, &tp->type); + struct function *func = tag__alloc(sizeof(*func)); + + if (func == NULL) + return -ENOMEM; + + // for BTF this is not really the type of the return of the function, + // but the prototype, the return type is the one in type_id + func->btf = 1; + func->proto.tag.tag = DW_TAG_subprogram; + func->proto.tag.type = type_id; + func->name = name; + cu__add_tag_with_id(btfe->priv, &func->proto.tag, id); + + return 0; +} static struct base_type *base_type__new(strings_t name, uint32_t attrs, uint8_t float_type, size_t size) @@ -482,15 +501,8 @@ static int btf_elf__load_types(struct btf_elf *btfe) vlen = create_new_subroutine_type(btfe, ptr, vlen, type_ptr, type_index); break; case BTF_KIND_FUNC: - /* BTF_KIND_FUNC corresponding to a defined subprogram. - * This is not really a type and it won't be referred by any other types - * either. Since types cannot be skipped, let us replace it with - * a nullify_type_entry. - * - * No warning here since BTF_KIND_FUNC is a legal entry in BTF. - */ - cu__table_nullify_type_entry(btfe->priv, type_index); - vlen = 0; + // BTF_KIND_FUNC corresponding to a defined subprogram. + vlen = create_new_function(btfe, type_ptr, size, type_index); break; default: fprintf(stderr, "BTF: idx: %d, off: %zd, Unknown kind %d\n", diff --git a/dwarves.c b/dwarves.c index 76bdf61..846c65e 100644 --- a/dwarves.c +++ b/dwarves.c @@ -1120,6 +1120,13 @@ int ftype__has_parm_of_type(const struct ftype *ftype, const type_id_t target, { struct parameter *pos; + if (ftype->tag.tag == DW_TAG_subprogram) { + struct function *func = (struct function *)ftype; + + if (func->btf) + ftype = tag__ftype(cu__type(cu, ftype->tag.type)); + } + ftype__for_each_parameter(ftype, pos) { struct tag *type = cu__type(cu, pos->tag.type); diff --git a/dwarves.h b/dwarves.h index b53bdfc..cd44381 100644 --- a/dwarves.h +++ b/dwarves.h @@ -763,7 +763,7 @@ void ftype__delete(struct ftype *ftype, struct cu *cu); void ftype__add_parameter(struct ftype *ftype, struct parameter *parm); size_t ftype__fprintf(const struct ftype *ftype, const struct cu *cu, const char *name, const int inlined, - const int is_pointer, const int type_spacing, + const int is_pointer, const int type_spacing, bool is_prototype, const struct conf_fprintf *conf, FILE *fp); size_t ftype__fprintf_parms(const struct ftype *ftype, const struct cu *cu, int indent, @@ -785,6 +785,7 @@ struct function { uint8_t accessibility:2; /* DW_ACCESS_{public,protected,private} */ uint8_t virtuality:2; /* DW_VIRTUALITY_{none,virtual,pure_virtual} */ uint8_t declaration:1; + uint8_t btf:1; int32_t vtable_entry; struct list_head vtable_node; /* fields used by tools */ diff --git a/dwarves_fprintf.c b/dwarves_fprintf.c index 31ea338..62ac292 100644 --- a/dwarves_fprintf.c +++ b/dwarves_fprintf.c @@ -297,7 +297,7 @@ size_t typedef__fprintf(const struct tag *tag, const struct cu *cu, return printed + ftype__fprintf(tag__ftype(tag_type), cu, type__name(type, cu), 0, is_pointer, 0, - pconf, fp); + true, pconf, fp); case DW_TAG_class_type: case DW_TAG_structure_type: { struct type *ctype = tag__type(tag_type); @@ -510,8 +510,7 @@ static const char *__tag__name(const struct tag *tag, const struct cu *cu, FILE *bfp = fmemopen(bf, len, "w"); if (bfp != NULL) { - ftype__fprintf(tag__ftype(tag), cu, NULL, 0, 0, 0, - pconf, bfp); + ftype__fprintf(tag__ftype(tag), cu, NULL, 0, 0, 0, true, pconf, bfp); fclose(bfp); } else snprintf(bf, len, "", @@ -700,7 +699,7 @@ next_type: if (ptype->tag == DW_TAG_subroutine_type) { printed += ftype__fprintf(tag__ftype(ptype), cu, name, 0, 1, - tconf.type_spacing, + tconf.type_spacing, true, &tconf, fp); break; } @@ -724,7 +723,7 @@ print_default: break; case DW_TAG_subroutine_type: printed += ftype__fprintf(tag__ftype(type), cu, name, 0, 0, - tconf.type_spacing, &tconf, fp); + tconf.type_spacing, true, &tconf, fp); break; case DW_TAG_const_type: { size_t const_printed = fprintf(fp, "%s ", "const"); @@ -998,7 +997,7 @@ const char *function__prototype(const struct function *func, FILE *bfp = fmemopen(bf, len, "w"); if (bfp != NULL) { - ftype__fprintf(&func->proto, cu, NULL, 0, 0, 0, + ftype__fprintf(&func->proto, cu, NULL, 0, 0, 0, true, &conf_fprintf__defaults, bfp); fclose(bfp); } else @@ -1051,13 +1050,13 @@ size_t ftype__fprintf_parms(const struct ftype *ftype, printed += ftype__fprintf(tag__ftype(ptype), cu, name, 0, 1, 0, - conf, fp); + true, conf, fp); continue; } } } else if (type->tag == DW_TAG_subroutine_type) { printed += ftype__fprintf(tag__ftype(type), cu, name, - 0, 0, 0, conf, fp); + true, 0, 0, 0, conf, fp); continue; } stype = tag__name(type, cu, sbf, sizeof(sbf), conf); @@ -1190,7 +1189,7 @@ size_t lexblock__fprintf(const struct lexblock *block, const struct cu *cu, size_t ftype__fprintf(const struct ftype *ftype, const struct cu *cu, const char *name, const int inlined, - const int is_pointer, int type_spacing, + const int is_pointer, int type_spacing, bool is_prototype, const struct conf_fprintf *conf, FILE *fp) { struct tag *type = cu__type(cu, ftype->tag.type); @@ -1199,11 +1198,9 @@ size_t ftype__fprintf(const struct ftype *ftype, const struct cu *cu, size_t printed = fprintf(fp, "%s%-*s %s%s%s%s", inlined ? "inline " : "", type_spacing, stype, - ftype->tag.tag == DW_TAG_subroutine_type ? - "(" : "", + is_prototype ? "(" : "", is_pointer ? "*" : "", name ?: "", - ftype->tag.tag == DW_TAG_subroutine_type ? - ")" : ""); + is_prototype ? ")" : ""); return printed + ftype__fprintf_parms(ftype, cu, 0, conf, fp); } @@ -1212,6 +1209,7 @@ static size_t function__fprintf(const struct tag *tag, const struct cu *cu, const struct conf_fprintf *conf, FILE *fp) { struct function *func = tag__function(tag); + struct ftype *ftype = func->btf ? tag__ftype(cu__type(cu, func->proto.tag.type)) : &func->proto; size_t printed = 0; bool inlined = !conf->strip_inline && function__declared_inline(func); @@ -1219,8 +1217,8 @@ static size_t function__fprintf(const struct tag *tag, const struct cu *cu, func->virtuality == DW_VIRTUALITY_pure_virtual) printed += fprintf(fp, "virtual "); - printed += ftype__fprintf(&func->proto, cu, function__name(func, cu), - inlined, 0, 0, conf, fp); + printed += ftype__fprintf(ftype, cu, function__name(func, cu), + inlined, 0, 0, false, conf, fp); if (func->virtuality == DW_VIRTUALITY_pure_virtual) printed += fprintf(fp, " = 0"); @@ -1845,7 +1843,7 @@ size_t tag__fprintf(struct tag *tag, const struct cu *cu, printed += __class__fprintf(tag__class(tag), cu, pconf, fp); break; case DW_TAG_subroutine_type: - printed += ftype__fprintf(tag__ftype(tag), cu, NULL, false, false, 0, pconf, fp); + printed += ftype__fprintf(tag__ftype(tag), cu, NULL, false, false, 0, true, pconf, fp); break; case DW_TAG_namespace: printed += namespace__fprintf(tag, cu, pconf, fp); diff --git a/pfunct.c b/pfunct.c index 1a6c943..f4ac200 100644 --- a/pfunct.c +++ b/pfunct.c @@ -323,7 +323,8 @@ static int function__emit_type_definitions(struct function *func, struct cu *cu, FILE *fp) { struct parameter *pos; - struct tag *type = cu__type(cu, func->proto.tag.type); + struct ftype *proto = func->btf ? tag__ftype(cu__type(cu, func->proto.tag.type)) : &func->proto; + struct tag *type = cu__type(cu, proto->tag.type); retry_return_type: /* type == NULL means the return is void */ @@ -340,7 +341,7 @@ retry_return_type: type__emit(type, cu, NULL, NULL, fp); } do_parameters: - function__for_each_parameter(func, pos) { + ftype__for_each_parameter(proto, pos) { type = cu__type(cu, pos->tag.type); try_again: if (type == NULL)