aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorConnor O'Brien <connoro@google.com>2021-12-21 14:07:11 -0800
committerConnor O'Brien <connoro@google.com>2022-01-05 16:20:35 -0800
commite017fe3016a192e30959cd3cd6271e5a134bd8cd (patch)
tree2f2e97ca10417fcfb99df398cdde3e72bab6f07d
parent6e27fd1e21f3f01577db8b533550cf0e2d559011 (diff)
parentc2b7b8c20877d267159ace36119f6340b9d12823 (diff)
downloaddwarves-e017fe3016a192e30959cd3cd6271e5a134bd8cd.tar.gz
Merge branch 'upstream-master' into 'master'
* upstream-master: pahole: Prep 1.23 Revert "fprintf: Allow making struct/enum/union anonymous" Revert "pahole: Add --inner_anon option" pahole: Add --inner_anon option fprintf: Allow making struct/enum/union anonymous btf_encoder: Support btf_type_tag attribute man pages: Add missing --skip_encoding_btf_decl_tag entry man pages: Add missing --skip_encoding_btf_type_tag entry dwarf_loader: Support btf_type_tag attribute dutil: Move DW_TAG_LLVM_annotation definition to dutil.h libbpf: Sync with latest libbpf repo to pick support for BTF_KIND_TYPE_TAG dwarf_loader: Warn about DW_TAG_skeleton_unit and give a workaround fprintf: Add DWARF5 tags added in elfutils 0.170 dwarf_loader: Print the hexadecimal value for unexpected tags in die__process() btf_encoder: generate BTF_KIND_DECL_TAGs for typedef btf_decl_tag attributes dwarf_loader: support typedef DW_TAG_LLVM_annotation btf_loader: Use cacheline size to infer alignment btf_loader: Propagate struct conf_load dwarves_fprintf: Move cacheline_size into struct conf_fprintf btfdiff: Suppress alignment tags with BTF as well as with DWARF btf_loader: Infer alignment info core: Export tag__natural_alignment() fprintf: Fix __attribute__((__aligned__(N)) handling for struct members btf: Rename btf_tag to btf_decl_tag manpages: Minor fixes btf_loader: Refactor class__fixup_btf_bitfields pahole: Add --skip_missing option fprintf: Fix nested struct printing wrt attributes btf_encoder: Fix handling of percpu symbols on s390 dwarf_loader: Fix heap overflow when accessing variable specification dwarves: Introduce conf_load->thread_exit() callback Update libbpf to get API to combine BTF btf_encoder: Generate BTF_KIND_TAG from llvm annotations dwarf_loader: Parse DWARF tag DW_TAG_LLVM_annotation CMakeList.txt: Don't download libbpf source when system library is used libbpf: Get latest libbpf CMakeList.txt: Make python optional pahole: Prep 1.22 core: Bump the chunk size for ptr_table uses in types, tags, functions tables pahole: Introduce --ptr_table_stats core: Add CU stats printer pahole: Fix races in accessing type information in live CUs pahole: Add missing limits.h include to get ULLONG_MAX definition CMakeList.txt: Look for obstack outside libc cmake: Add a module to find if obstack is in a separate library CMakeList.txt: Look for argp outside libc cmake: Add a module to find if argp is in a separate library fprintf: Add alternative method for reading the data cacheline size core: Include missing limits.h to get PATH_MAX definition dutil: Include linux/stddef.h to build on Alpine Linux systems README.tarball: Overcome --transform problem with symlinks MANIFEST: Add lib/include/bpf spec: Remove deleted libbtf.h from the RPM file list README.tarball: Remove hardcoded version, get it from 'git tag' MANIFEST: Remove long gone strings header files MANIFEST: Add buildcmd.sh buildcmd.sh: Add single build script for use in CI pahole: Consider type members's names when comparing unions, structs pahole: Consider type members's types when comparing unions, structs core: Introduce helpers for getting the first and next members of a type pahole: Improve the type sorting routine to consider multiple types with same name core: Remove extra ; in 'print_numeric_version' extern declaration btf_loader: Mark the 'level' arg to the libbpf error callback as __maybe_unused btf_loader: Mark create_new_datasec() args as __maybe_unused dwarf_loader: cus__load_debug_types() doesn't use its 'cus' arg, remove it dwarf_loader: Rename finalize_cu_immediately() to cus__finalize() to follow convention dwarf_loader: Remove unused 'dcu' argument from finalize_cu_immediately() dwarf_loader: Remove unused 'dcus' argument from cu__finalize() dwarf_loader: Remove unused 'cus' argument from finalize_cu() dwarf_loader: Fix signed/unsigned comparision in tag__recode_dwarf_bitfield() core: cus__fprintf_load_files_err() doesn't use its 'cus' argument core: Change last_seen_bit to uint32_t in class__find_holes() core: Change aligned_start to uint32_t in class__find_holes() core: Change cur_bitfield_end to uint32_t in class__find_holes() core: Change bit_start and bit_end to uint32_t in class__find_holes() btf_encoder: Fix signed/unsigned comparision btf_encoder: has_arg_names() doesn't need the 'cu' pointer btf_encoder: btf_encoder__encode_tag() doesn't need the 'core_id' pointer btf_encoder: btf_encoder__encode_tag() doesn't need the 'cu' pointer btf_encoder: btf_encoder__add_struct_type() doesn't need the 'cu' pointer btf_encoder: btf_encoder__add_func_proto() doesn't need the 'cu' pointer btf_encoder: No need to read the ehdr in btf_encoder__write_elf(), ditch it ctracer: No need to read the ehdr, ditch it btf_encoder: No need to store the ehdr in the instance elf_symtab: Remove needless GElf_Ehdr pointer argument from the constructor dutil: elf_symtab__new() doesn't need the GElf_Ehdr *ep argument pahole: Move case fallthru comment to after the statement elfcreator: elfcreator_copy_scn() doesn't need the 'elf' arg syscse: zero_extend() doesn't need a 'cu' arg pahole: Fix signedness of ternary expression operator ctracer: Remove a bunch of unused 'cu' pointers pahole: Use the 'prototypes' parameter in prototypes__load() codiff: class__find_pair_member() doesn't need 'cu' args core: class__find_member_by_name() doesn't need a cu pointer core: Document type->node member usage core: Fix nnr_members typo on 'struct type' comment docs man-pages: Improve the --nr_methods/-m pahole man page entry pahole: Clarify that currently --nr_methods doesn't work together witn -C pahole: No need to store the class name in 'struct structure' pahole: Multithreaded DWARF loading requires elfutils >= 0.178 btf_encoder: Add methods to maintain a list of btf encoders list: Adopt list_next_entry() from the Linux kernel dwarf_loader: Make hash table size default to 12, faster than 15 pahole: Allow tweaking the size of the loader hash tables core: Allow sizing the loader hash table hash: Remove unused hash_32(), hash_ptr() dwarf_loader: Use a per-CU frontend cache for the latest lookup result core: Use obstacks: take 2 dwarf_loader: Add comment on why we can't ignore lexblocks pahole: Ignore DW_TAG_label when encoding BTF core: Allow ignoring DW_TAG_label pahole: Ignore DW_TAG_inline_expansion when encoding BTF core: Allow ignoring DW_TAG_inline_expansion pahole: Allow encoding BTF with parallel DWARF loading core: Zero out unused entries when extending ptr_table array in ptr_table__add() pahole: No need to read DW_AT_alignment when encoding BTF dwarf_loader: Allow asking not to read the DW_AT_alignment attribute dwarf_loader: Do not look for non-C DWARF attributes in C CUs core: Add cu__is_c() to check if the CU language is C dwarf_loader: Add a lock around dwarf_decl_file() and dwarf_decl_line() calls btfdiff: Use multithreaded DWARF loading btfdiff: Use --sort for pretty printing from both BTF and DWARF pahole: Introduce --sort pahole: Store the class id in 'struct structure' as well dwarf_loader: Defer freeing libdw Dwfl handler core: Provide a way to store per loader info in cus and an exit function pahole: Keep class + cu in tree of structures dwarf_loader: Parallel DWARF loading pahole: Disable parallell BTF encoding for now pahole: Add locking for the structures list and rbtree dwarf_loader: Introduce 'dwarf_cus' to group all the DWARF specific per-cus state dwarf_loader: Factor common bits for creating and processing CU fprintf: class__vtable_fprintf() doesn't need a 'cu' arg fprintf: string_type__fprintf() doesn't need a 'cu' arg core: Ditch tag__free_orig_info(), unused core: variable__name() doesn't need a 'cu' arg core: base_type__name() doesn't need a 'cu' arg core: namespace__delete() doesn't need a 'cu' arg core: {tag,function,lexblock}__delete() doesn't need a 'cu' arg core: ftype__delete() doesn't need a 'cu' arg core: enumeration__delete() doesn't need a 'cu' arg core: type__delete() doesn't need a 'cu' arg core: class__clone() doesn't need a 'cu' arg core: class__delete() doesn't need a 'cu' arg core: type__delete_class_members() doesn't need a 'cu' arg core: class_member__delete() doesn't need a 'cu' arg core: type__clone_members() doesn't need a 'cu' arg core: class_member__clone() doesn't need a 'cu' arg pahole: Introduce --prettify option pahole: Try harder to resolve the --header type when pretty printing pahole: Make prototype__stdio_fprintf_value() receive a FILE to read raw data from man-page: Move the PRETTY PRINTING header earlier pahole: Make pipe_seek() honour the 'fp' arg instead of hardcoding stdin pahole: Rename 'fp' to 'output' in prototype__stdio_fprintf_value() pahole: Use the supplied 'fp' argument in type__instance_read_once() core: Use namespace->name in class__clone() core: Remove strings.c, unused ctf_loader: Use uint32_t instead of strings_t, that is going away core: Remove base_type_name_to_size_table.sname, unused pahole: Add missing bpf/btf.h include libctf: Comment out unused CTF encoding functions btf_loader: Add missing bpf/btf.h include btf_encoder: Add missing bpf/btf.h include pahole: Use conf_load.kabi_prefix dwarf_loader: Make attr_suffix() handle kabi_prefix dwarf_loader: Pass conf_load to functions calling attr_string() ctf_loader: No need for the 'strings' extern, not used btf_loader: No need for the 'strings' extern, not used dwarf_loader: Remove unused strings variable and debug_fmt_ops->{init,exit}() core: Remove unused debug_fmt_ops->dwarf__strings_ptr() core: Remove unused cu__string() method dwarf_loader: No need to strdup() what dwarf_formstring() returns core: No need for debug_fmt_ops->variable_name() anymore pahole: function__name() doesn't need a 'struct cu *' argument core: Make variable->name a real string core: Make label->name a real string pahole: class_member_filter__new() doesn't need a 'struct cu *' argument pahole: class_member_filter__parse() doesn't need a 'struct cu *' argument pahole: tag__real_sizeof() doesn't need a 'struct cu *' argument pahole: Rename tag__fprintf_hexdump_value() to instance__fprintf_hexdump_value() pahole: enumerations__lookup_entry_from_value() doesn't need to return a CU anymore pahole: enumeration__lookup_entry_from_value() doesn't need a 'cu' argument core: Ditch unused enumeration__prefix_len() method core: Ditch unused enumeration__prefix() method pahole: enumeration__lookup_value() doesn't need a 'cu' argument pahole: enumeration__lookup_enumerator() doesn't need a 'cu' argument core: enumeration__emit_definitions() doesn't need a 'cu' argument core: enumeration__fprintf() doesn't need a 'cu' argument core: Make enumeration__max_entry_name_len() static core: enumeration__max_entry_name_len() doesn't need a 'cu' argument core: Make enumeration__calc_prefix() static core: enumeration__calc_prefix doesn't need a 'cu' argument btf_encoder: btf_encoder__add_enum_type() doesn't need a 'cu' argument, ditch it core: enumerator__name() doesn't need a 'cu' argument, ditch it core: Ditch dwarves__active_loader, unused core: Make enumerator->name a real string emit: type__emit_fwd_decl() isn't used outside emit.c, make it static emit: type__emit_fwd_decl() doesn't need a cu arg emit: type_emissions__find_definition() doesn't need a cu arg core: class__name() doesn't need a cu arg core: type__name() doesn't need a cu arg core: Make namespace->name a real string core: Make class_member->name a real string core: Make parameter->name a real string core: Make base_type->name a real string pahole: Disable incomplete CTF encoder core: Ditch unused cu__find_struct_by_sname() core: Convert cu__find_base_type_by_sname_and_size to search for a string core: Convert cu__find_enumeration_by_sname_and_size to search for a string dwarf_loader: Rename strings_t 'name' to 'sname' to clarify usage core: Make function->name a real string core: Make function->linkage_name a real string dwarf_loader: Make dwarf_tag->decl_file a real string pahole: Allow specifying the number of threads to use while loading files pahole: Make '-j' available for use as number of jobs (threads) core: Protect cus->cus with a mutex core: Make 'struct cus' opaque, only visible in dwarves.c core: Introduce helper to return number of cu entries in a 'struct cus' core: Move cus__find_pair() from codiff to the core core: Introduce helper to return if there is no cu entries in a 'struct cus' core: Prepare cus__find_cu_by_name() for locking core: Prepare cus__find_function_at_addr() for locking core: Prepare __cus__find_struct_by_name() for locking core: Prepare cus__find_type_by_name() for locking core: Initialize cu->priv in cu__new() CMakeList.txt: Bump version to the upcoming 1.22 release, not out of the door yet Revert "btf_encoder: Reduce the size of encode_cu() by moving function encoding to separate method" dwarf_loader: Separate non-LTO per CU processing + BTF encoding part btf_encoder: Reduce the size of encode_cu() by moving function encoding to separate method btf_encoder: Reduce the size of encode_cu() by moving var encoding to separate method btf_encoder: No need to set the endianness twice when encoding into an ELF file btf_encoder: Pass detached_filename to the constructor btf_encoder: Adopt writing to raw file method btf_encoder: Rename btf__encode_in_elf to btf_encoder__write_elf, shortening function signature btf_encoder: Combine btf__write_elf() with btf__encode_in_elf() btf_encoder: Move duplicate code to btf_encoder__encode() btf_encoder: Pass the 'skip_encoding_vars' to the constructor btf_encoder: No need to export the 'struct btf_definition', make it opaque libbpf: bump dependency to >= 0.4.0 libbpf: If LIBBPF_EMBEDDED=OFF and libbpf-dev/pkgconfig is not available, fail the build headers: Rebame __unused to __maybe_unused to avoid clashes with system headers libbpf: Fixup patch to allow to use packaged version README: Add documentation for -DBUILD_SHARED_LIBS CMakeLists.txt: Enable SHARED and STATIC lib creation libbpf: Allow to use packaged version btf_encoder: Move libbtf.c to btf_encoder.c, the only user of its functions btf_encoder: Move PERCPU_SECTION define to the only source file using it btf_encoder: Move library global variable btf_gen_floats to btf_encoder class btf_encoder: Ditch unused 'btf_encoder__verbose' global variable btf_encoder: Use encoder->verbose instead of btf_encoder__verbose btf_encoder: Adopt btf__log_func_param() and use encoder->verbose btf_encoder: Adopt btf__log_member() and use encoder->verbose btf_encoder: Adopt btf__log_type() and use encoder->verbose btf_encoder: No need to pass encoder->percpu_secinfo to btf_encoder__add_datasec() btf_encoder: Make btf_encoder__add_var_secinfo() receive a btf_encoder pointer btf_encoder: Adopt btf__encode_var_secinfo() as btf_encoder__add_var_secinfo() btf_encoder: Adopt btf__encode_datasec_type() as btf_encoder__add_datasec() btf_encoder: Adopt btf__encode_var_type() as btf_encoder__add_var() btf_encoder: Adopt btf__encode_enum_val() as btf_encoder__add_enum_val() btf_encoder: Adopt btf__encode_enum() as btf_encoder__add_enum() btf_encoder: Adopt btf__encode_enumeration_type() as btf_encoder__add_enum_type() btf_encoder: Adopt btf__encode_func_proto_param() as btf_encoder__add_func_param() btf_encoder: Adopt btf__encode_func_proto() as btf_encoder__add_func_proto() btf_encoder: Adopt btf__encode_array() as btf_encoder__add_array() btf_encoder: Adopt btf__encode_struct() as btf_encoder__add_struct() btf_encoder: Adopt btf__encode_member() as btf_encoder__add_field() btf_encoder: Adopt btf__encode_struct_type() as btf_encoder__add_struct_type() btf_encoder: Adopt btf__encode_ref_type() as btf_encoder__add_ref_type() btf_encoder: Adopt btf__encode_float_type() as btf_encoder__add_float() btf_encoder: Adopt btf__encode_base_type() as btf_encoder__add_base_type() libbtf: Ditch unused btf_elf__verbose_log() macro libbtf: Ditch btf_elf class, unused btf_encoder: Use 'struct btf' directly, stop using btf_elf libbtf: Remove unused ELF fields and calls from btf_elf btf_encoder: Phagocytize percpu_secinfo from btf_elf pahole: Rename 'encoder' to 'btf_encoder' as we support multiple formats btf_encoder: Move the global btf_encoder to its users, like pahole btf_encoder: Adopt the cu__encode_btf() method, as btf_encoder__encode_cu() btf_encoder: Set btf_encoder__verbose in just one place, its users btf_encoder: Move btf_elf__verbose var to btf_encoder class btf_encoder: Adopt btf_elf__force, its only used in btf_encoder methods pahole: Adopt btf_encoder object instantiation from btf_encoder btf_encoder: Move the function encode() to be a btf_encoder method btf_encoder: Temporarily expose the 'encoder' variable btf_encoder: Move 'filename' member from btf_elf to btf_encoder btfdiff: Support diffing DWARF vs detached BTF btf_encoder: No need for calling btf_encoder__encode() from cu__encode_btf() btf_encoder: Move btf_elf based encode_in_elf and write_elf methods to btf_encoder btf_encoder: Move collect_symbols() call to btf_encoder constructor btf_encoder: Remove needless hash.h include, not used anymore btf_encoder: Move global elf_functions table to the btf_encoder class btf_encoder: Move ELF's ehdr from btf_elf to btf_encoder btf_encoder: Move 'symtab' from btf_elf to btf_encoder btf_encoder: Move percpu members from btf_elf to btf_encoder btf_encoder: Add a 'verbose' member for encoder specific logging requests btf_encoder: Move 'array_index_id' global variable to 'struct btf_encoder' btf_encoder: Move percpu vars global variables to btf_encoder class btf_encoder: Adopt collect_function() as a btf_encoder method btf_encoder: Adopt collect_per_cpu_var() as a btf_encoder method btf_encoder: Adopt collect_symbol() as a btf_encoder method btf_encoder: Move 'need_index_type' global variable to 'struct btf_encoder' btf_encoder: Make tag__encode_btf() its encode_tag() method btf_encoder: Move 'has_index_type' global variable to 'struct btf_encoder' btf_encoder: Introduce 'struct btf_encoder' to have all the current globals btf_encoder: Replace btfe with btf in tag__encode_btf() btf_encoder: Move encode_enumeration_type() from btf_elf to btf btf_encoder: Move encode_struct_type() from btf_elf to btf btf_encoder: Move add_datasec_type() from btf_elf to btf encode_datasec_type() btf_encoder: Move add_var_secinfo() from btf_elf to btf encode_var_secinfo() btf_encoder: Move add_var_type() from btf_elf to btf encode_var_type() btf_encoder: Move add_func_proto() from btf_elf to btf encode_func_proto() btf_encoder: Move add_enum() from btf_elf to btf encode_enum() btf_encoder: Move add_struct() from btf_elf to btf encode_struct() btf_encoder: Move add_array() from btf_elf to btf encode_array() btf_encoder: Move add_ref_type() from btf_elf to btf encode_ref_type() btf_encoder: Move add_member() from btf_elf to btf encode_member() btf_encoder: Move add_base_type() from btf_elf to btf encode_base_type() btf_encoder: Move add_float_type() from btf_elf to btf encode_float_type() btf_encoder: bpf__log_func_param() doesn't need the btfe arg btf_encoder: Move log_member() from btf_elf to btf btf_encoder: Move log_type() from btf_elf to btf btf_encoder: Move log_err() from btf_elf to btf btf_encoder: Remove 'elf' from btf_elf__int_encoding_str() name btf_elf: Remove base_btf member, used only in the constructor btf_elf: No point in falling back to raw BTF in btf_new() btf_elf: No point in looking at the filename for /sys/kernel/btf in btf_elf__new() libbtf: Ditch unused btf_elf__string() method libbtf: Remove unused btf_elf__load() btf_encoder: Move printable_name() from btfe to btf btf_loader: Stop using libbtf.h and the btf_elf class btf_loader: cu__fixup_btf_bitfields doesn'n need btfe parameter, ditch it btf_loader: class__fixup_btf_bitfields doesn'n need btfe parameter, ditch it btf_elf: Remove unused btfe->priv member btf_loader: Add a local 'btf' var to prep next patches btf_loader: Move load_sections() from btf_elf to btf btf_loader: Move load_types() from btf_elf to btf btf_loader: Move create_new_tag() from btfe to cu btf_loader: Move create_new_datasec() from btfe to cu btf_loader: Move create_new_variable() from btfe to cu btf_loader: Move create_new_typedef() from btfe to cu btf_loader: Move create_new_forward_decl() from btfe to cu btf_loader: Move create_new_subroutine_type() from btfe to cu btf_loader: Move create_new_enumeration() from btfe to cu btf_loader: Move create_new_union() from btfe to cu btf_loader: Move create_new_class() from btfe to cu btf_loader: The create_members() function doesn't need the btfe arg btf_loader: Move create_new_array() from btfe to cu btf_loader: Move create_new_float_type() from btfe to cu btf_loader: Move create_new_int_type() from btfe to cu btf_loader: Move create_new_function() from btfe to cu btf_loader: Move load_ftype() from btfe to cu btf_loader: Pass cu to the load_sections/types routines libbtf: Remove the 'base_btf' global var, now unused pahole: Use conf_load->base_btf to call cu__encode_btf() btf_loader: Use conf_load->base_btf instead of the global btf_base var pahole: Set conf_load.btf_base when applicable core: Allow passing the base_btf object via 'struct conf_load' btf_encoder: Pass the base BTF object to the BTF encoder btf_elf: Remove unused 'wordsize' member btf_loader: Use btf__pointer_size() to set cu->addr_size btf_elf: Remove unused is_big_endian member btf_loader: Use btf__endianness() instead of to be removed btfe member libbtf: Remove unused btf_elf->raw_btf member pahole: Allow encoding BTF into a detached file btf_loader: Use btf__parse_split() dwarf_loader: Add define for DW_OP_addrx libbtf: Fix typo pahole: Add --kabi_prefix flag btf_encoder: fix and complete filtering out zero-sized per-CPU variables dwarves: Make handling of NULL by destructos consistent dutil: Make handling of NULL by destructos consistent pahole: Make handling of NULL by destructos consistent elf_symtab: Use zfree() where applicable codiff: Use zfree() where applicable dutil: Adopt the zalloc()/zfree() from perf libctf: Use zfree() where applicable pahole: Use zfree() where applicable dwarf_loader: Use zfree() instead of ad-hoc implementation gobuffer: Use zfree() and make delete accept NULL, like free() dwarves: Use zfree() libbtf: Use zfree() dutil: Adopt zfree(), to use it more pervasively dwarves: Plug leaks in cu__new() found by covscan dwarf_loader: Call dwarf_cu__delete() when aborting the load dwarf_loader: Delete the allocated CU when aborting dwarf_loader: Make all ABORT returns go thru a single exit label dwarf_loader: Use zalloc() to allocate dwarf_cu dwarf_loader: Make dwarf_cu__delete() accept NULL, just like free() dwarves: Accept NULL in cu__delete(), just like free() accepts dwarf_loader: Check if we have a CU after the loop in cus__merge_and_process_cu() dwarf_loader: Check tag__recode_dwarf_bitfield() return, may be NULL ctracer: Initialize the 'parm_list' variable, detected by covscan codiff: Fix usage of negative errno values with strerror(), reported by covscan btf_loader: Fix some memory leaks found by covscan loaders: Plug enumeration__delete() leak detected by covscan dwarves: Stop using obstacks CMakeLists.txt: Specify the file extension of srcs README: Mention how to specify another prefix btf: Remove ftrace filter pahole: Fix error message when --header couldn't be read pahole: Introduce --with_flexible_array option to show just types ending in a flexible array pahole: Prep 1.21 spec: Fix dates in RPM spec dwarf_loader: Handle DWARF5 DW_OP_addrx properly dwarf_loader: Handle subprogram ret type with abstract_origin properly dwarf_loader: Check .notes section for LTO build info dwarf_loader: Check .debug_abbrev for cross-CU references dwarf_loader: Permit merging all DWARF CU's for clang LTO built binary dwarf_loader: Factor out common code to initialize a cu dwarf_loader: Permit a flexible HASHTAGS__BITS btf: Add --btf_gen_all flag btf: Add support for the floating-point types fprintf: Honour conf_fprintf.hex when printing enumerations Avoid warning when building with NDEBUG btf_encoder: Match ftrace addresses within ELF functions dwarf_loader: Use a better hashing function, from libbpf btf_encoder: Funnel ELF error reporting through a macro btf_encoder: Sanitize non-regular int base type pahole: Prep 1.20 Revert "libbpf: allow to use packaged version" dwarf_loader: Support DWARF_TAG_call_site{_parameter} also in die__process_inline_expansion dwarf_loader: Add conditional DW_FORM_implicit_const definition for older systems dtagnames: Stop using the deprecated mallinfo() function cmake: Bump minimum required version to 2.8.12 as per upstream support warning dwarves: Make enum prefix search more robust dwarf_loader: Handle DWARF5 DW_TAG_call_site like DW_TAG_GNU_call_site dwarf_loader: Support DW_FORM_implicit_const in __attr_offset() dwarf_loader: Support DW_AT_data_bit_offset dwarf_loader: Optimize a bit the reading of DW_AT_data_member_location dwarf_loader: Fix typo dwarf_loader: Introduce __attr_offset() to reuse call to dwarf_attr() dwarf_loader: Support DW_FORM_implicit_const in attr_numeric() btf_encoder: Improve ELF error reporting bpf_encoder: Translate SHN_XINDEX in symbol's st_shndx values elf_symtab: Handle SHN_XINDEX index in elf_section_by_name() btf_encoder: Add extra checks for symbol names libbpf: allow to use packaged version btf_encoder: Improve error-handling around objcopy btf_encoder: Fix handling of restrict qualifier Bug: 203823368 Test: pahole builds after follow-up Android.bp change Signed-off-by: Connor O'Brien <connoro@google.com> Change-Id: I598528959a21e5f070edd1de23061401f28ba31d
-rw-r--r--CMakeLists.txt85
-rw-r--r--MANIFEST12
-rw-r--r--METADATA4
-rw-r--r--NEWS459
-rw-r--r--README13
-rw-r--r--README.tarball2
-rw-r--r--btf_encoder.c1556
-rw-r--r--btf_encoder.h19
-rw-r--r--btf_loader.c317
-rwxr-xr-xbtfdiff18
-rwxr-xr-xbuildcmd.sh7
-rw-r--r--changes-v1.2066
-rw-r--r--changes-v1.2170
-rw-r--r--changes-v1.2295
-rw-r--r--changes-v1.2356
-rw-r--r--cmake/modules/Findargp.cmake41
-rw-r--r--cmake/modules/Findobstack.cmake41
-rw-r--r--codiff.c87
-rw-r--r--ctf_loader.c87
-rw-r--r--ctracer.c98
-rw-r--r--dtagnames.c20
-rw-r--r--dutil.c29
-rw-r--r--dutil.h16
-rw-r--r--dwarf_loader.c1405
-rw-r--r--dwarves.c589
-rw-r--r--dwarves.h282
-rw-r--r--dwarves_emit.c56
-rw-r--r--dwarves_emit.h3
-rw-r--r--dwarves_fprintf.c267
-rw-r--r--dwarves_reorganize.c32
-rw-r--r--elf_symtab.c47
-rw-r--r--elf_symtab.h31
-rw-r--r--elfcreator.c2
-rw-r--r--elfcreator.h2
-rw-r--r--gobuffer.c5
-rw-r--r--hash.h48
l---------lib/include/bpf1
-rw-r--r--libbtf.c826
-rw-r--r--libbtf.h72
-rw-r--r--libctf.c14
-rw-r--r--list.h8
-rw-r--r--man-pages/pahole.1107
-rw-r--r--pahole.c790
-rw-r--r--pahole_strings.h31
-rw-r--r--pdwtags.c11
-rw-r--r--pfunct.c51
-rw-r--r--pglobal.c18
-rw-r--r--prefcnt.c10
-rw-r--r--rpm/SPECS/dwarves.spec83
-rw-r--r--scncopy.c2
-rw-r--r--strings.c88
-rw-r--r--syscse.c21
52 files changed, 5079 insertions, 3021 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 857487a..c0363b8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,10 +1,25 @@
project(pahole C)
-cmake_minimum_required(VERSION 2.8.8)
+cmake_minimum_required(VERSION 2.8.12)
cmake_policy(SET CMP0005 NEW)
+option(LIBBPF_EMBEDDED "Use the embedded version of libbpf instead of searching it via pkg-config" ON)
+if (NOT LIBBPF_EMBEDDED)
+ find_package(PkgConfig REQUIRED)
+ if(PKGCONFIG_FOUND)
+ pkg_check_modules(LIBBPF REQUIRED libbpf>=0.4.0)
+ endif()
+endif()
+
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}
- ${CMAKE_CURRENT_SOURCE_DIR}
- ${CMAKE_CURRENT_SOURCE_DIR}/lib/bpf/include/uapi)
+ ${CMAKE_CURRENT_SOURCE_DIR})
+if(NOT LIBBPF_FOUND)
+ # Allows to use 'system' style #include with both embedded and system libbpf
+ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/lib/include)
+ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/lib/bpf/include/uapi)
+else()
+ INCLUDE_DIRECTORIES(${LIBBPF_INCLUDE_DIRS})
+ LINK_DIRECTORIES(${LIBBPF_LIBRARY_DIRS})
+endif()
# Try to parse this later, Helio just showed me a KDE4 example to support
# x86-64 builds.
@@ -31,17 +46,26 @@ endif (NOT CMAKE_BUILD_TYPE)
set(CMAKE_C_FLAGS_DEBUG "-Wall -Werror -ggdb -O0")
set(CMAKE_C_FLAGS_RELEASE "-Wall -O2")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread")
+
+if (NOT DEFINED BUILD_SHARED_LIBS)
+ set (BUILD_SHARED_LIBS ON)
+ message(STATUS "Setting BUILD_SHARED_LIBS = ${BUILD_SHARED_LIBS}")
+endif (NOT DEFINED BUILD_SHARED_LIBS)
# Just for grepping, DWARVES_VERSION isn't used anywhere anymore
-# add_definitions(-D_GNU_SOURCE -DDWARVES_VERSION="v1.19")
+# add_definitions(-D_GNU_SOURCE -DDWARVES_VERSION="v1.23")
add_definitions(-D_GNU_SOURCE -DDWARVES_MAJOR_VERSION=1)
-add_definitions(-D_GNU_SOURCE -DDWARVES_MINOR_VERSION=19)
+add_definitions(-D_GNU_SOURCE -DDWARVES_MINOR_VERSION=23)
find_package(DWARF REQUIRED)
find_package(ZLIB REQUIRED)
+find_package(argp REQUIRED)
+find_package(obstack REQUIRED)
+find_package(Python3 QUIET)
# make sure git submodule(s) are checked out
find_package(Git QUIET)
-if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
+if(LIBBPF_EMBEDDED AND GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
# Update submodules as needed
option(GIT_SUBMODULE "Check submodules during build" ON)
if(GIT_SUBMODULE)
@@ -56,7 +80,7 @@ if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
endif()
endif()
endif()
-if(NOT EXISTS "${PROJECT_SOURCE_DIR}/lib/bpf/src/btf.h")
+if(NOT LIBBPF_FOUND AND NOT EXISTS "${PROJECT_SOURCE_DIR}/lib/bpf/src/btf.h")
message(FATAL_ERROR "The submodules were not downloaded! GIT_SUBMODULE was turned off or failed. Please update submodules and try again.")
endif()
@@ -81,30 +105,33 @@ endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64")
-file(GLOB libbpf_sources "lib/bpf/src/*.c")
-add_library(bpf OBJECT ${libbpf_sources})
-set_property(TARGET bpf PROPERTY POSITION_INDEPENDENT_CODE 1)
-target_include_directories(bpf PRIVATE
- ${CMAKE_CURRENT_SOURCE_DIR}/lib/bpf/include
- ${CMAKE_CURRENT_SOURCE_DIR}/lib/bpf/include/uapi)
+if (NOT LIBBPF_FOUND)
+ file(GLOB libbpf_sources "lib/bpf/src/*.c")
+ add_library(bpf OBJECT ${libbpf_sources})
+ set_property(TARGET bpf PROPERTY POSITION_INDEPENDENT_CODE 1)
+ target_include_directories(bpf PRIVATE
+ ${CMAKE_CURRENT_SOURCE_DIR}/lib/bpf/include
+ ${CMAKE_CURRENT_SOURCE_DIR}/lib/bpf/include/uapi)
+endif()
-set(dwarves_LIB_SRCS dwarves.c dwarves_fprintf.c gobuffer strings
- ctf_encoder.c ctf_loader.c libctf.c btf_encoder.c btf_loader.c libbtf.c
+set(dwarves_LIB_SRCS dwarves.c dwarves_fprintf.c gobuffer.c
+ ctf_loader.c libctf.c btf_encoder.c btf_loader.c
dwarf_loader.c dutil.c elf_symtab.c rbtree.c)
-add_library(dwarves SHARED ${dwarves_LIB_SRCS} $<TARGET_OBJECTS:bpf>)
+if (NOT LIBBPF_FOUND)
+ list(APPEND dwarves_LIB_SRCS $<TARGET_OBJECTS:bpf>)
+endif()
+add_library(dwarves ${dwarves_LIB_SRCS})
set_target_properties(dwarves PROPERTIES VERSION 1.0.0 SOVERSION 1)
set_target_properties(dwarves PROPERTIES INTERFACE_LINK_LIBRARIES "")
-target_include_directories(dwarves PRIVATE
- ${CMAKE_CURRENT_SOURCE_DIR}/lib/bpf/include/uapi)
-target_link_libraries(dwarves ${DWARF_LIBRARIES} ${ZLIB_LIBRARIES})
+target_link_libraries(dwarves ${DWARF_LIBRARIES} ${ZLIB_LIBRARIES} ${LIBBPF_LIBRARIES} ${ARGP_LIBRARY} ${OBSTACK_LIBRARY})
set(dwarves_emit_LIB_SRCS dwarves_emit.c)
-add_library(dwarves_emit SHARED ${dwarves_emit_LIB_SRCS})
+add_library(dwarves_emit ${dwarves_emit_LIB_SRCS})
set_target_properties(dwarves_emit PROPERTIES VERSION 1.0.0 SOVERSION 1)
target_link_libraries(dwarves_emit dwarves)
set(dwarves_reorganize_LIB_SRCS dwarves_reorganize.c)
-add_library(dwarves_reorganize SHARED ${dwarves_reorganize_LIB_SRCS})
+add_library(dwarves_reorganize ${dwarves_reorganize_LIB_SRCS})
set_target_properties(dwarves_reorganize PROPERTIES VERSION 1.0.0 SOVERSION 1)
target_link_libraries(dwarves_reorganize dwarves)
@@ -151,16 +178,18 @@ target_link_libraries(syscse dwarves)
install(TARGETS codiff ctracer dtagnames pahole pdwtags
pfunct pglobal prefcnt scncopy syscse RUNTIME DESTINATION
${CMAKE_INSTALL_PREFIX}/bin)
-install(TARGETS dwarves LIBRARY DESTINATION ${LIB_INSTALL_DIR})
-install(TARGETS dwarves dwarves_emit dwarves_reorganize LIBRARY DESTINATION ${LIB_INSTALL_DIR})
+install(TARGETS dwarves LIBRARY DESTINATION ${LIB_INSTALL_DIR} ARCHIVE DESTINATION ${LIB_INSTALL_DIR})
+install(TARGETS dwarves dwarves_emit dwarves_reorganize LIBRARY DESTINATION ${LIB_INSTALL_DIR} ARCHIVE DESTINATION ${LIB_INSTALL_DIR})
install(FILES dwarves.h dwarves_emit.h dwarves_reorganize.h
- dutil.h gobuffer.h list.h rbtree.h pahole_strings.h
- btf_encoder.h config.h ctf_encoder.h ctf.h
- elfcreator.h elf_symtab.h hash.h libbtf.h libctf.h
+ dutil.h gobuffer.h list.h rbtree.h
+ btf_encoder.h config.h ctf.h
+ elfcreator.h elf_symtab.h hash.h libctf.h
DESTINATION ${CMAKE_INSTALL_PREFIX}/include/dwarves/)
install(FILES man-pages/pahole.1 DESTINATION ${CMAKE_INSTALL_PREFIX}/share/man/man1/)
-install(PROGRAMS ostra/ostra-cg DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
+if(Python3_FOUND)
+ install(PROGRAMS ostra/ostra-cg DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
+ install(FILES ostra/python/ostra.py DESTINATION ${CMAKE_INSTALL_PREFIX}/share/dwarves/runtime/python)
+endif()
install(PROGRAMS btfdiff fullcircle DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
-install(FILES ostra/python/ostra.py DESTINATION ${CMAKE_INSTALL_PREFIX}/share/dwarves/runtime/python)
install(FILES lib/Makefile lib/ctracer_relay.c lib/ctracer_relay.h lib/linux.blacklist.cu
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/dwarves/runtime)
diff --git a/MANIFEST b/MANIFEST
index 57a721a..0e1eefa 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -15,6 +15,8 @@ dwarves_fprintf.c
dwarves_reorganize.c
dwarves_reorganize.h
cmake/modules/FindDWARF.cmake
+cmake/modules/Findargp.cmake
+cmake/modules/Findobstack.cmake
CMakeLists.txt
codiff.c
ctracer.c
@@ -27,8 +29,6 @@ fullcircle
gobuffer.c
gobuffer.h
hash.h
-libbtf.c
-libbtf.h
list.h
MANIFEST
man-pages/pahole.1
@@ -41,8 +41,6 @@ rbtree.c
rbtree.h
scncopy.c
syscse.c
-strings.c
-pahole_strings.h
dutil.c
dutil.h
changes-v1.13
@@ -50,6 +48,11 @@ changes-v1.16
changes-v1.17
changes-v1.18
changes-v1.19
+changes-v1.20
+changes-v1.21
+changes-v1.22
+changes-v1.23
+buildcmd.sh
COPYING
NEWS
README
@@ -69,3 +72,4 @@ libctf.c
libctf.h
regtest
lib/bpf/
+lib/include/bpf
diff --git a/METADATA b/METADATA
index 3b75dd1..f25f524 100644
--- a/METADATA
+++ b/METADATA
@@ -11,7 +11,7 @@ third_party {
type: GIT
value: "https://git.kernel.org/pub/scm/devel/pahole/pahole"
}
- version: "b688e35970600c15d18d5eb7c19139253437a2aa"
- last_upgrade_date { year: 2021 month: 1 day: 18 }
+ version: "c2b7b8c20877d267159ace36119f6340b9d12823"
+ last_upgrade_date { year: 2022 month: 1 day: 5 }
license_type: RESTRICTED
}
diff --git a/NEWS b/NEWS
index 9de30d8..efd0745 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,462 @@
+v1.23
+
+Wed Dec 8 2021
+
+54ae2f7f5e4f6328 Revert "fprintf: Allow making struct/enum/union anonymous"
+69fb1861de35120c Revert "pahole: Add --inner_anon option"
+005236c3e40eeb64 pahole: Add --inner_anon option
+7c5e35b63bd26f1d fprintf: Allow making struct/enum/union anonymous
+d99d551930cf4b4b btf_encoder: Support btf_type_tag attribute
+3da248c3284ef905 man pages: Add missing --skip_encoding_btf_decl_tag entry
+a58ecca0a89b142b man pages: Add missing --skip_encoding_btf_type_tag entry
+b488c8d328845bd8 dwarf_loader: Support btf_type_tag attribute
+a0cc68687f1281cd dutil: Move DW_TAG_LLVM_annotation definition to dutil.h
+76401e9e46f07753 libbpf: Sync with latest libbpf repo to pick support for BTF_KIND_TYPE_TAG
+0135ccd632796ab3 dwarf_loader: Warn about DW_TAG_skeleton_unit and give a workaround
+433dc780ca48944b fprintf: Add DWARF5 tags added in elfutils 0.170
+7af9ed4aed182869 dwarf_loader: Print the hexadecimal value for unexpected tags in die__process()
+ec62499774c4bcac btf_encoder: generate BTF_KIND_DECL_TAGs for typedef btf_decl_tag attributes
+468b4196f65458e8 dwarf_loader: support typedef DW_TAG_LLVM_annotation
+696c62180455fd29 btf_loader: Use cacheline size to infer alignment
+48f4086b766d2214 btf_loader: Propagate struct conf_load
+772725a77d3323c6 dwarves_fprintf: Move cacheline_size into struct conf_fprintf
+cdd088c05cfed082 btfdiff: Suppress alignment tags with BTF as well as with DWARF
+836c139fdf6f2b13 btf_loader: Infer alignment info
+4db65fe0cd02b3cc core: Export tag__natural_alignment()
+43e8216c25ee767f fprintf: Fix __attribute__((__aligned__(N)) handling for struct members
+c52f6421f21146ad btf: Rename btf_tag to btf_decl_tag
+3433c67bbd158e1d manpages: Minor fixes
+e975d0fba833d02d btf_loader: Refactor class__fixup_btf_bitfields
+5282feee6d4d3a88 pahole: Add --skip_missing option
+6931e393f8f6d81f fprintf: Fix nested struct printing wrt attributes
+16a7acaba4466121 btf_encoder: Fix handling of percpu symbols on s390
+3cde0135ca51de73 dwarf_loader: Fix heap overflow when accessing variable specification
+a9c99e98815f06bd dwarves: Introduce conf_load->thread_exit() callback
+cc6c7d473d518324 Update libbpf to get API to combine BTF
+e38e89e8539b144a btf_encoder: Generate BTF_KIND_TAG from llvm annotations
+aa8c494e65a77fa5 dwarf_loader: Parse DWARF tag DW_TAG_LLVM_annotation
+3d20210d84f61ee2 CMakeList.txt: Don't download libbpf source when system library is used
+38fad22d669ab044 libbpf: Get latest libbpf
+88431099950ab3e8 CMakeList.txt: Make python optional
+
+v1.22:
+
+Mon Aug 23 2021
+
+40a40df961e74aac core: Bump the chunk size for ptr_table uses in types, tags, functions tables
+9f0809e6a8e790a1 pahole: Introduce --ptr_table_stats
+f035871495435e58 core: Add CU stats printer
+c59e996c97eb5569 pahole: Fix races in accessing type information in live CUs
+c34b6c6cc96b9669 pahole: Add missing limits.h include to get ULLONG_MAX definition
+5e8ad60d1f33bed6 CMakeList.txt: Look for obstack outside libc
+739bc50b90694ffe cmake: Add a module to find if obstack is in a separate library
+5244b47a883bee96 CMakeList.txt: Look for argp outside libc
+3f70d31571d47c64 cmake: Add a module to find if argp is in a separate library
+9f9588dc2bd8c955 fprintf: Add alternative method for reading the data cacheline size
+71867afd666f2945 core: Include missing limits.h to get PATH_MAX definition
+0d8d457fa325fb07 dutil: Include linux/stddef.h to build on Alpine Linux systems
+bb02fec203463b9f README.tarball: Overcome --transform problem with symlinks
+9fed416b380a7a17 MANIFEST: Add lib/include/bpf
+cb1cf166769a169e spec: Remove deleted libbtf.h from the RPM file list
+d0c3dd18c7d81cff README.tarball: Remove hardcoded version, get it from 'git tag'
+b5140d5e6c8cade8 MANIFEST: Remove long gone strings header files
+02fd228f6af7b04e MANIFEST: Add buildcmd.sh
+06e41eccc2d19263 buildcmd.sh: Add single build script for use in CI
+eba3e874add53187 pahole: Consider type members's names when comparing unions, structs
+f61d458c9126467e pahole: Consider type members's types when comparing unions, structs
+589a298829760a14 core: Introduce helpers for getting the first and next members of a type
+815041d6dc4d62bf pahole: Improve the type sorting routine to consider multiple types with same name
+93e26698693aca95 core: Remove extra ; in 'print_numeric_version' extern declaration
+19798784d7a715d0 btf_loader: Mark the 'level' arg to the libbpf error callback as __maybe_unused
+22763a8fc7ee5f79 btf_loader: Mark create_new_datasec() args as __maybe_unused
+38df86db2b65dd43 dwarf_loader: cus__load_debug_types() doesn't use its 'cus' arg, remove it
+16d646c07e98d66c dwarf_loader: Rename finalize_cu_immediately() to cus__finalize() to follow convention
+90599e6177f20696 dwarf_loader: Remove unused 'dcu' argument from finalize_cu_immediately()
+6fd4377a0db1e8d3 dwarf_loader: Remove unused 'dcus' argument from cu__finalize()
+2bb04ecf79880a97 dwarf_loader: Remove unused 'cus' argument from finalize_cu()
+9ada372a21d0abc2 dwarf_loader: Fix signed/unsigned comparision in tag__recode_dwarf_bitfield()
+e4e9267c3a177ffa core: cus__fprintf_load_files_err() doesn't use its 'cus' argument
+df92cb6b8e0f1577 core: Change last_seen_bit to uint32_t in class__find_holes()
+789d8b3e1a7210d1 core: Change aligned_start to uint32_t in class__find_holes()
+182cdcaed9055c76 core: Change cur_bitfield_end to uint32_t in class__find_holes()
+5900f43f10844971 core: Change bit_start and bit_end to uint32_t in class__find_holes()
+8634d8535f3fb25d btf_encoder: Fix signed/unsigned comparision
+8d2efa2b6c147c37 btf_encoder: has_arg_names() doesn't need the 'cu' pointer
+05f737076f81eab9 btf_encoder: btf_encoder__encode_tag() doesn't need the 'core_id' pointer
+dc30e82b26dc98ef btf_encoder: btf_encoder__encode_tag() doesn't need the 'cu' pointer
+4360359e434b41db btf_encoder: btf_encoder__add_struct_type() doesn't need the 'cu' pointer
+6e1e4881a584ca54 btf_encoder: btf_encoder__add_func_proto() doesn't need the 'cu' pointer
+9fbfcee7d9708876 btf_encoder: No need to read the ehdr in btf_encoder__write_elf(), ditch it
+898cc490279c794b ctracer: No need to read the ehdr, ditch it
+dee83e27dd69cb98 btf_encoder: No need to store the ehdr in the instance
+24404190b80aa6bf elf_symtab: Remove needless GElf_Ehdr pointer argument from the constructor
+74c2078e04755b6a dutil: elf_symtab__new() doesn't need the GElf_Ehdr *ep argument
+23ea62817c3c9d1d pahole: Move case fallthru comment to after the statement
+7a8e75cd9a99f618 elfcreator: elfcreator_copy_scn() doesn't need the 'elf' arg
+3925a5bd53d68edc syscse: zero_extend() doesn't need a 'cu' arg
+21b2933f018a954d pahole: Fix signedness of ternary expression operator
+4e11c13895556982 ctracer: Remove a bunch of unused 'cu' pointers
+54c1e93b8eada3db pahole: Use the 'prototypes' parameter in prototypes__load()
+8b495918e6b52c4c codiff: class__find_pair_member() doesn't need 'cu' args
+057be3d9936f78d9 core: class__find_member_by_name() doesn't need a cu pointer
+ce9de90364d0fe98 core: Document type->node member usage
+cead526d6b96e1d7 core: Fix nnr_members typo on 'struct type' comment docs
+7cfc9be1f27876f4 man-pages: Improve the --nr_methods/-m pahole man page entry
+3895127ce674cfb6 pahole: Clarify that currently --nr_methods doesn't work together witn -C
+2ea46285aca0c639 pahole: No need to store the class name in 'struct structure'
+4d8551396df5ce5a pahole: Multithreaded DWARF loading requires elfutils >= 0.178
+e57e23c72a7c0446 btf_encoder: Add methods to maintain a list of btf encoders
+e9b83dba79a87935 list: Adopt list_next_entry() from the Linux kernel
+6edae3e768e6bc0d dwarf_loader: Make hash table size default to 12, faster than 15
+d2d83be1e2124785 pahole: Allow tweaking the size of the loader hash tables
+ff7bd7083f36db80 core: Allow sizing the loader hash table
+3068ff36b7ff943d hash: Remove unused hash_32(), hash_ptr()
+8eebf70d05d881cf dwarf_loader: Use a per-CU frontend cache for the latest lookup result
+a2f1e698487b783c core: Use obstacks: take 2
+dca86fb8c2220f9a dwarf_loader: Add comment on why we can't ignore lexblocks
+9d0a7ee0c38ebac5 pahole: Ignore DW_TAG_label when encoding BTF
+d40c5f1e20795938 core: Allow ignoring DW_TAG_label
+51ba83192979916e pahole: Ignore DW_TAG_inline_expansion when encoding BTF
+903863889131a7fa core: Allow ignoring DW_TAG_inline_expansion
+20757745f04ace54 pahole: Allow encoding BTF with parallel DWARF loading
+5a85d9a450819500 core: Zero out unused entries when extending ptr_table array in ptr_table__add()
+d133569bd0f0b422 pahole: No need to read DW_AT_alignment when encoding BTF
+21a41e5386938db1 dwarf_loader: Allow asking not to read the DW_AT_alignment attribute
+1ef1639039b56005 dwarf_loader: Do not look for non-C DWARF attributes in C CUs
+88265eab35666f34 core: Add cu__is_c() to check if the CU language is C
+1caed1c443d4a0dc dwarf_loader: Add a lock around dwarf_decl_file() and dwarf_decl_line() calls
+dd13708f2fd7557b btfdiff: Use multithreaded DWARF loading
+f95f7838499f94c3 btfdiff: Use --sort for pretty printing from both BTF and DWARF
+3e1c7a20770ec432 pahole: Introduce --sort
+967290bc7176e3c2 pahole: Store the class id in 'struct structure' as well
+2b45e1b6d04b147c dwarf_loader: Defer freeing libdw Dwfl handler
+35845e7e41872158 core: Provide a way to store per loader info in cus and an exit function
+5365c45177643f35 pahole: Keep class + cu in tree of structures
+fb99cad539e58638 dwarf_loader: Parallel DWARF loading
+75d4748861ad98cf pahole: Disable parallell BTF encoding for now
+1c60f71daacbe4d0 pahole: Add locking for the structures list and rbtree
+46ad8c01585df768 dwarf_loader: Introduce 'dwarf_cus' to group all the DWARF specific per-cus state
+d963af9fd8148ba0 dwarf_loader: Factor common bits for creating and processing CU
+0c5bf70cc1259162 fprintf: class__vtable_fprintf() doesn't need a 'cu' arg
+38ff86b149e1aa9a fprintf: string_type__fprintf() doesn't need a 'cu' arg
+a75c342ac2fc6c54 core: Ditch tag__free_orig_info(), unused
+80fe32fd294ac15e core: variable__name() doesn't need a 'cu' arg
+caa219dffcb41422 core: base_type__name() doesn't need a 'cu' arg
+7569e46d3515f93e core: namespace__delete() doesn't need a 'cu' arg
+de4e8b7f178257d5 core: {tag,function,lexblock}__delete() doesn't need a 'cu' arg
+789ed4e3a2c34b54 core: ftype__delete() doesn't need a 'cu' arg
+6340cb462767aa95 core: enumeration__delete() doesn't need a 'cu' arg
+33e44f5295702d95 core: type__delete() doesn't need a 'cu' arg
+0f54ca9c827e9ef7 core: class__clone() doesn't need a 'cu' arg
+2b2014187b811243 core: class__delete() doesn't need a 'cu' arg
+f40900eba656db3b core: type__delete_class_members() doesn't need a 'cu' arg
+50916756d59ad7f9 core: class_member__delete() doesn't need a 'cu' arg
+2e50463c3aa149d3 core: type__clone_members() doesn't need a 'cu' arg
+a66208355ea8108c core: class_member__clone() doesn't need a 'cu' arg
+33e0d5f874dc22c4 pahole: Introduce --prettify option
+bc36e94f32e662aa pahole: Try harder to resolve the --header type when pretty printing
+fcfa2141c375849b pahole: Make prototype__stdio_fprintf_value() receive a FILE to read raw data from
+1a65d232b040fae6 man-page: Move the PRETTY PRINTING header earlier
+2d35630fa55de2bc pahole: Make pipe_seek() honour the 'fp' arg instead of hardcoding stdin
+9aa01472d9655e1b pahole: Rename 'fp' to 'output' in prototype__stdio_fprintf_value()
+472b94018055873d pahole: Use the supplied 'fp' argument in type__instance_read_once()
+63992cb02a69485b core: Use namespace->name in class__clone()
+ced4c34c37acd185 core: Remove strings.c, unused
+adbb66c2957d9eef ctf_loader: Use uint32_t instead of strings_t, that is going away
+ad707445b3fcaf11 core: Remove base_type_name_to_size_table.sname, unused
+f8d571934b96ea35 pahole: Add missing bpf/btf.h include
+deb6a4a4921b33ec libctf: Comment out unused CTF encoding functions
+82155bc92f726c43 btf_loader: Add missing bpf/btf.h include
+05f1f9dece4ed54d btf_encoder: Add missing bpf/btf.h include
+f4a77d03909c1cf8 pahole: Use conf_load.kabi_prefix
+2b9bd83e63bacb59 dwarf_loader: Make attr_suffix() handle kabi_prefix
+daaafeb35f168fd1 dwarf_loader: Pass conf_load to functions calling attr_string()
+def39099c1920346 ctf_loader: No need for the 'strings' extern, not used
+2499920ac8d88b82 btf_loader: No need for the 'strings' extern, not used
+a388aaf489f945d4 dwarf_loader: Remove unused strings variable and debug_fmt_ops->{init,exit}()
+3d3b7b3287617b8f core: Remove unused debug_fmt_ops->dwarf__strings_ptr()
+05687c547e9f22e8 core: Remove unused cu__string() method
+a201149e181be613 dwarf_loader: No need to strdup() what dwarf_formstring() returns
+6b7f1b72f9a958e4 core: No need for debug_fmt_ops->variable_name() anymore
+9d0e3ab9a29c2e81 pahole: function__name() doesn't need a 'struct cu *' argument
+a7d789a4f841b0ea core: Make variable->name a real string
+b5694280ec5b1f1f core: Make label->name a real string
+e974d1b2404154ea pahole: class_member_filter__new() doesn't need a 'struct cu *' argument
+0275e8d24975c531 pahole: class_member_filter__parse() doesn't need a 'struct cu *' argument
+90183e8e4da43785 pahole: tag__real_sizeof() doesn't need a 'struct cu *' argument
+5cb91927385d7b75 pahole: Rename tag__fprintf_hexdump_value() to instance__fprintf_hexdump_value()
+75c769a900185faf pahole: enumerations__lookup_entry_from_value() doesn't need to return a CU anymore
+1edca2655284d968 pahole: enumeration__lookup_entry_from_value() doesn't need a 'cu' argument
+f8d98eff756bf406 core: Ditch unused enumeration__prefix_len() method
+5cc365164a4cba46 core: Ditch unused enumeration__prefix() method
+e18c60d793935ab6 pahole: enumeration__lookup_value() doesn't need a 'cu' argument
+4b877c8e6762c42f pahole: enumeration__lookup_enumerator() doesn't need a 'cu' argument
+3ff11828fee01a91 core: enumeration__emit_definitions() doesn't need a 'cu' argument
+0947d6e7954d752d core: enumeration__fprintf() doesn't need a 'cu' argument
+bb22f5bb0a137342 core: Make enumeration__max_entry_name_len() static
+dc83336171d1157c core: enumeration__max_entry_name_len() doesn't need a 'cu' argument
+ec1667c76db61e2f core: Make enumeration__calc_prefix() static
+45ec63ed20a56557 core: enumeration__calc_prefix doesn't need a 'cu' argument
+2fae84e2f79726fb btf_encoder: btf_encoder__add_enum_type() doesn't need a 'cu' argument, ditch it
+96243fdd79c5c45d core: enumerator__name() doesn't need a 'cu' argument, ditch it
+ee5c12893b2e8aa8 core: Ditch dwarves__active_loader, unused
+713239bc008910ff core: Make enumerator->name a real string
+7721cc17aca7020d emit: type__emit_fwd_decl() isn't used outside emit.c, make it static
+9aa5db7acd420d55 emit: type__emit_fwd_decl() doesn't need a cu arg
+c46f91ef6f9cd0a1 emit: type_emissions__find_definition() doesn't need a cu arg
+c127d25daf88c1a2 core: class__name() doesn't need a cu arg
+00e8c5fe216755d6 core: type__name() doesn't need a cu arg
+b99c4008acca8794 core: Make namespace->name a real string
+379a73c6eb4633d4 core: Make class_member->name a real string
+3280cb41768a7130 core: Make parameter->name a real string
+f009162fd133d155 core: Make base_type->name a real string
+e2ee753fa74ca570 pahole: Disable incomplete CTF encoder
+0d13bc50ee8dbdf8 core: Ditch unused cu__find_struct_by_sname()
+46f3f372416d7f9f core: Convert cu__find_base_type_by_sname_and_size to search for a string
+f84e8777eada296a core: Convert cu__find_enumeration_by_sname_and_size to search for a string
+a16c82f7110467b7 dwarf_loader: Rename strings_t 'name' to 'sname' to clarify usage
+82e5b5101a6adf73 core: Make function->name a real string
+4f73cac85321bd5b core: Make function->linkage_name a real string
+a93160df5335ed2e dwarf_loader: Make dwarf_tag->decl_file a real string
+a3fcbcacf79787d6 pahole: Allow specifying the number of threads to use while loading files
+d70b2562ee5d90f2 pahole: Make '-j' available for use as number of jobs (threads)
+41a283c65d300945 core: Protect cus->cus with a mutex
+972065482a7f714d core: Make 'struct cus' opaque, only visible in dwarves.c
+3895b29060fdc21e core: Introduce helper to return number of cu entries in a 'struct cus'
+874e750fb8bddcad core: Move cus__find_pair() from codiff to the core
+bf74fc1fcf1ab78e core: Introduce helper to return if there is no cu entries in a 'struct cus'
+7020f9214328ac8d core: Prepare cus__find_cu_by_name() for locking
+4bf7285b37108222 core: Prepare cus__find_function_at_addr() for locking
+73a2fd1e5a70c7f2 core: Prepare __cus__find_struct_by_name() for locking
+5020bf721b204673 core: Prepare cus__find_type_by_name() for locking
+d124926baf2366a2 core: Initialize cu->priv in cu__new()
+3ec54ee72ff7c5b1 CMakeList.txt: Bump version to the upcoming 1.22 release, not out of the door yet
+1ef87b26fd268b52 Revert "btf_encoder: Reduce the size of encode_cu() by moving function encoding to separate method"
+7869cc113b0b5a3d dwarf_loader: Separate non-LTO per CU processing + BTF encoding part
+de3a7f912559433c btf_encoder: Reduce the size of encode_cu() by moving function encoding to separate method
+d348b37ed16249e0 btf_encoder: Reduce the size of encode_cu() by moving var encoding to separate method
+f62196d3be5a8765 btf_encoder: No need to set the endianness twice when encoding into an ELF file
+819f83bd9736b9c8 btf_encoder: Pass detached_filename to the constructor
+7ed4ddc46826538e btf_encoder: Adopt writing to raw file method
+1498094d335f697a btf_encoder: Rename btf__encode_in_elf to btf_encoder__write_elf, shortening function signature
+cd2b8978c43ea00a btf_encoder: Combine btf__write_elf() with btf__encode_in_elf()
+18a3e9711ccc6887 btf_encoder: Move duplicate code to btf_encoder__encode()
+9eb3d7a29de32bf4 btf_encoder: Pass the 'skip_encoding_vars' to the constructor
+707101ec38d76958 btf_encoder: No need to export the 'struct btf_definition', make it opaque
+f1feaa94c7a92e5c libbpf: bump dependency to >= 0.4.0
+1b50808c2958dde3 libbpf: If LIBBPF_EMBEDDED=OFF and libbpf-dev/pkgconfig is not available, fail the build
+790dfbda79444d11 headers: Rebame __unused to __maybe_unused to avoid clashes with system headers
+82756ea3eaf1f6e7 libbpf: Fixup patch to allow to use packaged version
+ba953a53be25765e README: Add documentation for -DBUILD_SHARED_LIBS
+aa2027708659f172 CMakeLists.txt: Enable SHARED and STATIC lib creation
+ae2581647e849488 libbpf: Allow to use packaged version
+743f2536d8b876a4 btf_encoder: Move libbtf.c to btf_encoder.c, the only user of its functions
+6f72dddbed0e1bf8 btf_encoder: Move PERCPU_SECTION define to the only source file using it
+f0f5b4f2bc34b029 btf_encoder: Move library global variable btf_gen_floats to btf_encoder class
+09970b03bd309d83 btf_encoder: Ditch unused 'btf_encoder__verbose' global variable
+1bf2e3511a1386c4 btf_encoder: Use encoder->verbose instead of btf_encoder__verbose
+4ffa484b6a04530b btf_encoder: Adopt btf__log_func_param() and use encoder->verbose
+729da7613b399f9c btf_encoder: Adopt btf__log_member() and use encoder->verbose
+be75b76b6b9e479f btf_encoder: Adopt btf__log_type() and use encoder->verbose
+9f19e96001f72c49 btf_encoder: No need to pass encoder->percpu_secinfo to btf_encoder__add_datasec()
+869c177f8e13ce12 btf_encoder: Make btf_encoder__add_var_secinfo() receive a btf_encoder pointer
+f0e8cd68f5dcb20b btf_encoder: Adopt btf__encode_var_secinfo() as btf_encoder__add_var_secinfo()
+cc646d93d18270e9 btf_encoder: Adopt btf__encode_datasec_type() as btf_encoder__add_datasec()
+b0f71fabdeee329b btf_encoder: Adopt btf__encode_var_type() as btf_encoder__add_var()
+1aece1e7e6d593db btf_encoder: Adopt btf__encode_enum_val() as btf_encoder__add_enum_val()
+4371b3cd5b9b18e6 btf_encoder: Adopt btf__encode_enum() as btf_encoder__add_enum()
+b536947512efcb7e btf_encoder: Adopt btf__encode_enumeration_type() as btf_encoder__add_enum_type()
+1bc29591ec010fa8 btf_encoder: Adopt btf__encode_func_proto_param() as btf_encoder__add_func_param()
+393febe592e94f4a btf_encoder: Adopt btf__encode_func_proto() as btf_encoder__add_func_proto()
+4eb4c03578b29791 btf_encoder: Adopt btf__encode_array() as btf_encoder__add_array()
+06cd9f00c69d11bd btf_encoder: Adopt btf__encode_struct() as btf_encoder__add_struct()
+0b29d5a65ccef5f6 btf_encoder: Adopt btf__encode_member() as btf_encoder__add_field()
+3e2a1f7ddc930d3c btf_encoder: Adopt btf__encode_struct_type() as btf_encoder__add_struct_type()
+2c7a2f270ef7bcea btf_encoder: Adopt btf__encode_ref_type() as btf_encoder__add_ref_type()
+07d4ec9cef0c1619 btf_encoder: Adopt btf__encode_float_type() as btf_encoder__add_float()
+68ed8af85908e432 btf_encoder: Adopt btf__encode_base_type() as btf_encoder__add_base_type()
+14ab2e036147b6bc libbtf: Ditch unused btf_elf__verbose_log() macro
+539c94fee9315254 libbtf: Ditch btf_elf class, unused
+282a8a2187bde9bd btf_encoder: Use 'struct btf' directly, stop using btf_elf
+dd0b01f56837794e libbtf: Remove unused ELF fields and calls from btf_elf
+a0c5f49b0c405b1b btf_encoder: Phagocytize percpu_secinfo from btf_elf
+c288e29d06c380b5 pahole: Rename 'encoder' to 'btf_encoder' as we support multiple formats
+46a3e3a87a8963ca btf_encoder: Move the global btf_encoder to its users, like pahole
+fa849010b4565015 btf_encoder: Adopt the cu__encode_btf() method, as btf_encoder__encode_cu()
+3be437c5e7d2777e btf_encoder: Set btf_encoder__verbose in just one place, its users
+e1e787af4496b51f btf_encoder: Move btf_elf__verbose var to btf_encoder class
+66f4054252ab996e btf_encoder: Adopt btf_elf__force, its only used in btf_encoder methods
+5e1207754eb67249 pahole: Adopt btf_encoder object instantiation from btf_encoder
+0208952e8ffcfdc3 btf_encoder: Move the function encode() to be a btf_encoder method
+bcc5f95364da96bb btf_encoder: Temporarily expose the 'encoder' variable
+e27be59f10c7c6e3 btf_encoder: Move 'filename' member from btf_elf to btf_encoder
+da9d70a16ff01492 btfdiff: Support diffing DWARF vs detached BTF
+6bc135c8f49696a9 btf_encoder: No need for calling btf_encoder__encode() from cu__encode_btf()
+48a0fa2ef7b546a3 btf_encoder: Move btf_elf based encode_in_elf and write_elf methods to btf_encoder
+cc8eae604dc07b5e btf_encoder: Move collect_symbols() call to btf_encoder constructor
+96e59c55686bccaf btf_encoder: Remove needless hash.h include, not used anymore
+92f8852d8d178966 btf_encoder: Move global elf_functions table to the btf_encoder class
+aa48ed55a790c2d5 btf_encoder: Move ELF's ehdr from btf_elf to btf_encoder
+b3701a8346a6ea71 btf_encoder: Move 'symtab' from btf_elf to btf_encoder
+be8dac48691f6578 btf_encoder: Move percpu members from btf_elf to btf_encoder
+7f70877b198200ac btf_encoder: Add a 'verbose' member for encoder specific logging requests
+ef8a48b3bc7cda1f btf_encoder: Move 'array_index_id' global variable to 'struct btf_encoder'
+f3e6edffd7210265 btf_encoder: Move percpu vars global variables to btf_encoder class
+14053c490bf68a49 btf_encoder: Adopt collect_function() as a btf_encoder method
+049675f4a5401ac2 btf_encoder: Adopt collect_per_cpu_var() as a btf_encoder method
+21b5e9b368228502 btf_encoder: Adopt collect_symbol() as a btf_encoder method
+e40bc12ddf42b4a8 btf_encoder: Move 'need_index_type' global variable to 'struct btf_encoder'
+cccfeec3c7d68f89 btf_encoder: Make tag__encode_btf() its encode_tag() method
+65b3c598ab24a14a btf_encoder: Move 'has_index_type' global variable to 'struct btf_encoder'
+a5c732e712564798 btf_encoder: Introduce 'struct btf_encoder' to have all the current globals
+bd4e585d81a35862 btf_encoder: Replace btfe with btf in tag__encode_btf()
+de2676159d8472b7 btf_encoder: Move encode_enumeration_type() from btf_elf to btf
+80dec71c934fc96a btf_encoder: Move encode_struct_type() from btf_elf to btf
+6d7790a5d4fc68a4 btf_encoder: Move add_datasec_type() from btf_elf to btf encode_datasec_type()
+12d340c321e31564 btf_encoder: Move add_var_secinfo() from btf_elf to btf encode_var_secinfo()
+d90b38c1f3ca9171 btf_encoder: Move add_var_type() from btf_elf to btf encode_var_type()
+bce82c1a00a9beee btf_encoder: Move add_func_proto() from btf_elf to btf encode_func_proto()
+188f25b74130d131 btf_encoder: Move add_enum() from btf_elf to btf encode_enum()
+f82bd80a5c175425 btf_encoder: Move add_struct() from btf_elf to btf encode_struct()
+1216aebd27ecd4e6 btf_encoder: Move add_array() from btf_elf to btf encode_array()
+a96c91261e731602 btf_encoder: Move add_ref_type() from btf_elf to btf encode_ref_type()
+a97ed8080a354487 btf_encoder: Move add_member() from btf_elf to btf encode_member()
+56e0c2d4ccc7a9bd btf_encoder: Move add_base_type() from btf_elf to btf encode_base_type()
+adeeb9ebcf7ef8bd btf_encoder: Move add_float_type() from btf_elf to btf encode_float_type()
+37d3b8a1cedac677 btf_encoder: bpf__log_func_param() doesn't need the btfe arg
+64d216f57e7a229f btf_encoder: Move log_member() from btf_elf to btf
+20bb260428c0a1ad btf_encoder: Move log_type() from btf_elf to btf
+16d026ce5db765c9 btf_encoder: Move log_err() from btf_elf to btf
+c5f594eaa9b5ab8c btf_encoder: Remove 'elf' from btf_elf__int_encoding_str() name
+c81d11b8bb80bed1 btf_elf: Remove base_btf member, used only in the constructor
+69f5fff50e442cad btf_elf: No point in falling back to raw BTF in btf_new()
+3fcf804a7e69aa4f btf_elf: No point in looking at the filename for /sys/kernel/btf in btf_elf__new()
+c9eb447502b771c5 libbtf: Ditch unused btf_elf__string() method
+a355a245fb48b05f libbtf: Remove unused btf_elf__load()
+3de65d433ab18301 btf_encoder: Move printable_name() from btfe to btf
+7fb31d787d3deec1 btf_loader: Stop using libbtf.h and the btf_elf class
+e431c18b80650545 btf_loader: cu__fixup_btf_bitfields doesn'n need btfe parameter, ditch it
+8c1919c10df8a79f btf_loader: class__fixup_btf_bitfields doesn'n need btfe parameter, ditch it
+4d2ae0d9049e47c5 btf_elf: Remove unused btfe->priv member
+b54b74edfcd0dc8c btf_loader: Add a local 'btf' var to prep next patches
+52bedef0fddaa227 btf_loader: Move load_sections() from btf_elf to btf
+ac3f2952a854fccc btf_loader: Move load_types() from btf_elf to btf
+1a33deae144dbd22 btf_loader: Move create_new_tag() from btfe to cu
+8323cb33bc73817a btf_loader: Move create_new_datasec() from btfe to cu
+6fb41bbf8e31f3cf btf_loader: Move create_new_variable() from btfe to cu
+9122424dda37ccff btf_loader: Move create_new_typedef() from btfe to cu
+dd3e9ab4a00f8cf9 btf_loader: Move create_new_forward_decl() from btfe to cu
+cca6b51d292df6f1 btf_loader: Move create_new_subroutine_type() from btfe to cu
+ba1b77d01dda3ac0 btf_loader: Move create_new_enumeration() from btfe to cu
+a58bc8300f13c93f btf_loader: Move create_new_union() from btfe to cu
+367f5fe74cbb35ec btf_loader: Move create_new_class() from btfe to cu
+2460bead8a8fc02f btf_loader: The create_members() function doesn't need the btfe arg
+1136795fec7ff6bf btf_loader: Move create_new_array() from btfe to cu
+ab2f5028916c7822 btf_loader: Move create_new_float_type() from btfe to cu
+6b452a1cc5f2f22b btf_loader: Move create_new_int_type() from btfe to cu
+073a5f69ef19700a btf_loader: Move create_new_function() from btfe to cu
+29ad464f73286067 btf_loader: Move load_ftype() from btfe to cu
+407693e2cabfa7a3 btf_loader: Pass cu to the load_sections/types routines
+89b9c4f8851ebc8f libbtf: Remove the 'base_btf' global var, now unused
+6f70d0accaf17f74 pahole: Use conf_load->base_btf to call cu__encode_btf()
+0e77be409969631b btf_loader: Use conf_load->base_btf instead of the global btf_base var
+6ee61b161dbcc42c pahole: Set conf_load.btf_base when applicable
+b8255beb12c02d76 core: Allow passing the base_btf object via 'struct conf_load'
+f93e05d8bd45d4b3 btf_encoder: Pass the base BTF object to the BTF encoder
+81797a00fbdd1017 btf_elf: Remove unused 'wordsize' member
+ecc888b855c249a6 btf_loader: Use btf__pointer_size() to set cu->addr_size
+e6b69ffc74dcb3f0 btf_elf: Remove unused is_big_endian member
+81fe7d688de85fa2 btf_loader: Use btf__endianness() instead of to be removed btfe member
+9f8ce7e1137f22c1 libbtf: Remove unused btf_elf->raw_btf member
+89be5646a03435bf pahole: Allow encoding BTF into a detached file
+22a76fbc8b33a3cd btf_loader: Use btf__parse_split()
+c9d4c106ab95cd8c dwarf_loader: Add define for DW_OP_addrx
+76f7844c817eeac5 libbtf: Fix typo
+3d510406ff363056 pahole: Add --kabi_prefix flag
+0d17503db0580a66 btf_encoder: fix and complete filtering out zero-sized per-CPU variables
+fb418f9d8384d3a9 dwarves: Make handling of NULL by destructos consistent
+f049fe9ebf7aa9c2 dutil: Make handling of NULL by destructos consistent
+1512ab8ab6fe76a9 pahole: Make handling of NULL by destructos consistent
+1105b7dad2d0978b elf_symtab: Use zfree() where applicable
+131275fa20437dec codiff: Use zfree() where applicable
+6784b03fd447f507 dutil: Adopt the zalloc()/zfree() from perf
+d7f5824a9e1895d1 libctf: Use zfree() where applicable
+45d9eb8602b42a6b pahole: Use zfree() where applicable
+f48cc78e8e6e56df dwarf_loader: Use zfree() instead of ad-hoc implementation
+d0f6a4a1da524873 gobuffer: Use zfree() and make delete accept NULL, like free()
+db37185d16d4a56d dwarves: Use zfree()
+e7e86c75e149c161 libbtf: Use zfree()
+972001e58e9f5ed9 dutil: Adopt zfree(), to use it more pervasively
+5847901abf13e8bd dwarves: Plug leaks in cu__new() found by covscan
+32114e611a93b046 dwarf_loader: Call dwarf_cu__delete() when aborting the load
+26bd4c41646a64b9 dwarf_loader: Delete the allocated CU when aborting
+d8940df90b4a952b dwarf_loader: Make all ABORT returns go thru a single exit label
+3ba54ee43a301419 dwarf_loader: Use zalloc() to allocate dwarf_cu
+f3957627bb3e3431 dwarf_loader: Make dwarf_cu__delete() accept NULL, just like free()
+8772c9d827813d4d dwarves: Accept NULL in cu__delete(), just like free() accepts
+25cc0c77545cefbc dwarf_loader: Check if we have a CU after the loop in cus__merge_and_process_cu()
+2f30062b546de1ef dwarf_loader: Check tag__recode_dwarf_bitfield() return, may be NULL
+d68fd2bbc59291f3 ctracer: Initialize the 'parm_list' variable, detected by covscan
+5b0fb9745e1e9597 codiff: Fix usage of negative errno values with strerror(), reported by covscan
+cba940fb86a46fa9 btf_loader: Fix some memory leaks found by covscan
+674063b1ea4156d2 loaders: Plug enumeration__delete() leak detected by covscan
+505a1f5615c5064a dwarves: Stop using obstacks
+872658b88021b487 CMakeLists.txt: Specify the file extension of srcs
+aa8519378a37c9a5 README: Mention how to specify another prefix
+58a98f76ac95b1bb btf: Remove ftrace filter
+7c60b0443cb01795 pahole: Fix error message when --header couldn't be read
+7eea706c14997b4f pahole: Introduce --with_flexible_array option to show just types ending in a flexible array
+
+v1.21:
+
+Fri Apr 9 2021
+
+ae0b7dde1fd50b12 dwarf_loader: Handle DWARF5 DW_OP_addrx properly
+9adb014930f31c66 dwarf_loader: Handle subprogram ret type with abstract_origin properly
+5752d1951d081a80 dwarf_loader: Check .notes section for LTO build info
+209e45424ff4a22d dwarf_loader: Check .debug_abbrev for cross-CU references
+39227909db3cc2c2 dwarf_loader: Permit merging all DWARF CU's for clang LTO built binary
+763475ca1101ccfe dwarf_loader: Factor out common code to initialize a cu
+d0d3fbd4744953e8 dwarf_loader: Permit a flexible HASHTAGS__BITS
+ffe0ef4d73906c18 btf: Add --btf_gen_all flag
+de708b33114d42c2 btf: Add support for the floating-point types
+4b7f8c04d009942b fprintf: Honour conf_fprintf.hex when printing enumerations
+f2889ff163726336 Avoid warning when building with NDEBUG
+8e1f8c904e303d5d btf_encoder: Match ftrace addresses within ELF functions
+9fecc77ed82d429f dwarf_loader: Use a better hashing function, from libbpf
+0125de3a4c055cdf btf_encoder: Funnel ELF error reporting through a macro
+7d8e829f636f47ab btf_encoder: Sanitize non-regular int base type
+
+v1.20:
+
+Tue Feb 2 2021
+
+8d6f06f053a06829 (HEAD -> master, seventh/master, quaco/master, origin/master, origin/HEAD) dwarf_loader: Add conditional DW_FORM_implicit_const definition for older systems
+66d12e4790b7c5e5 dtagnames: Stop using the deprecated mallinfo() function
+1279e439b622aeb5 cmake: Bump minimum required version to 2.8.12 as per upstream support warning
+b1eaf0da6d1f72b2 dwarves: Make enum prefix search more robust
+d783117162c0212d dwarf_loader: Handle DWARF5 DW_TAG_call_site like DW_TAG_GNU_call_site
+3ff98a6396e91d0a dwarf_loader: Support DW_FORM_implicit_const in __attr_offset()
+b91b19840b0062b8 dwarf_loader: Support DW_AT_data_bit_offset
+c692e8ac5ccbab99 dwarf_loader: Optimize a bit the reading of DW_AT_data_member_location
+65917b24942ce620 dwarf_loader: Fix typo
+77205a119c85e396 dwarf_loader: Introduce __attr_offset() to reuse call to dwarf_attr()
+8ec231f6b0c8aaef dwarf_loader: Support DW_FORM_implicit_const in attr_numeric()
+7453895e01edb535 btf_encoder: Improve ELF error reporting
+1bb49897dd2b65b0 bpf_encoder: Translate SHN_XINDEX in symbol's st_shndx values
+3f8aad340bf1a188 elf_symtab: Handle SHN_XINDEX index in elf_section_by_name()
+e32b9800e650a6eb btf_encoder: Add extra checks for symbol names
+82749180b23d3c9c libbpf: allow to use packaged version
+452dbcf35f1a7bf9 btf_encoder: Improve error-handling around objcopy
+cf381f9a3822d68b btf_encoder: Fix handling of restrict qualifier
+b688e35970600c15 btf_encoder: fix skipping per-CPU variables at offset 0
+8c009d6ce762dfc9 btf_encoder: fix BTF variable generation for kernel modules
+b94e97e015a94e6b dwarves: Fix compilation on 32-bit architectures
+17df51c700248f02 btf_encoder: Detect kernel module ftrace addresses
+06ca639505fc56c6 btf_encoder: Use address size based on ELF's class
+aff60970d16b909e btf_encoder: Factor filter_functions function
+1e6a3fed6e52d365 rpm: Fix changelog date
+
v1.19:
Fri Nov 20 2020
diff --git a/README b/README
index e711ba4..c9f1737 100644
--- a/README
+++ b/README
@@ -6,8 +6,17 @@ Build instructions:
4. cmake -D__LIB=lib ..
5. make install
-Default is to be installed on /usr/local, see rpm spec file for
-installing on other places.
+cmake Options:
+ -DBUILD_SHARED_LIBS
+ By default SHARED libraries are created and applications are linked to it.
+ Use -DBUILD_SHARED_LIBS=OFF while invoking cmake to create STATIC libraries
+ and link applications to it.
+
+ Ex. cmake -D__LIB=lib -DBUILD_SHARED_LIBS=OFF ..
+
+ -DCMAKE_INSTALL_PREFIX
+ Default is to install to /usr/local, use -DCMAKE_INSTALL_PREFIX=
+ when invoking cmake to specify another install location.
Known to work scenarios:
diff --git a/README.tarball b/README.tarball
index a3db289..bade4a8 100644
--- a/README.tarball
+++ b/README.tarball
@@ -1 +1 @@
-tar cvfJ ~/rpmbuild/SOURCES/dwarves-1.17.tar.xz --transform 's,^,dwarves-1.17/,' `cat MANIFEST`
+v=1.$(($(git tag | sort -V | tail -1 | cut -d. -f2) + 1)) ; tar cvfJ ~/rpmbuild/SOURCES/dwarves-${v}.tar.xz --transform "s,^pahole/,dwarves-${v}/," `sed s%^%../pahole/%g MANIFEST`
diff --git a/btf_encoder.c b/btf_encoder.c
index 3339730..9d015f3 100644
--- a/btf_encoder.c
+++ b/btf_encoder.c
@@ -10,307 +10,719 @@
*/
#include "dwarves.h"
-#include "libbtf.h"
-#include "lib/bpf/include/uapi/linux/btf.h"
-#include "lib/bpf/src/libbpf.h"
-#include "hash.h"
#include "elf_symtab.h"
#include "btf_encoder.h"
+#include "gobuffer.h"
+#include <linux/btf.h>
+#include <bpf/btf.h>
+#include <bpf/libbpf.h>
#include <ctype.h> /* for isalpha() and isalnum() */
#include <stdlib.h> /* for qsort() and bsearch() */
#include <inttypes.h>
+#include <limits.h>
-/*
- * This corresponds to the same macro defined in
- * include/linux/kallsyms.h
- */
-#define KSYM_NAME_LEN 128
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
-struct funcs_layout {
- unsigned long mcount_start;
- unsigned long mcount_stop;
- unsigned long mcount_sec_idx;
-};
+#include <unistd.h>
+
+#include <errno.h>
+#include <stdint.h>
struct elf_function {
const char *name;
- unsigned long addr;
- unsigned long sh_addr;
bool generated;
};
-static struct elf_function *functions;
-static int functions_alloc;
-static int functions_cnt;
+#define MAX_PERCPU_VAR_CNT 4096
-static int functions_cmp(const void *_a, const void *_b)
+struct var_info {
+ uint64_t addr;
+ const char *name;
+ uint32_t sz;
+};
+
+struct btf_encoder {
+ struct list_head node;
+ struct btf *btf;
+ struct gobuffer percpu_secinfo;
+ const char *filename;
+ struct elf_symtab *symtab;
+ bool has_index_type,
+ need_index_type,
+ skip_encoding_vars,
+ raw_output,
+ verbose,
+ force,
+ gen_floats,
+ is_rel;
+ uint32_t array_index_id;
+ struct {
+ struct var_info vars[MAX_PERCPU_VAR_CNT];
+ int var_cnt;
+ uint32_t shndx;
+ uint64_t base_addr;
+ uint64_t sec_sz;
+ } percpu;
+ struct {
+ struct elf_function *entries;
+ int allocated;
+ int cnt;
+ } functions;
+};
+
+void btf_encoders__add(struct list_head *encoders, struct btf_encoder *encoder)
{
- const struct elf_function *a = _a;
- const struct elf_function *b = _b;
+ list_add_tail(&encoder->node, encoders);
+}
- return strcmp(a->name, b->name);
+struct btf_encoder *btf_encoders__first(struct list_head *encoders)
+{
+ return list_first_entry(encoders, struct btf_encoder, node);
}
-static void delete_functions(void)
+struct btf_encoder *btf_encoders__next(struct btf_encoder *encoder)
{
- free(functions);
- functions_alloc = functions_cnt = 0;
- functions = NULL;
+ return list_next_entry(encoder, node);
}
-#ifndef max
-#define max(x, y) ((x) < (y) ? (y) : (x))
-#endif
+#define PERCPU_SECTION ".data..percpu"
-static int collect_function(struct btf_elf *btfe, GElf_Sym *sym)
+/*
+ * This depends on the GNU extension to eliminate the stray comma in the zero
+ * arguments case.
+ *
+ * The difference between elf_errmsg(-1) and elf_errmsg(elf_errno()) is that the
+ * latter clears the current error.
+ */
+#define elf_error(fmt, ...) \
+ fprintf(stderr, "%s: " fmt ": %s.\n", __func__, ##__VA_ARGS__, elf_errmsg(-1))
+
+/*
+ * This depends on the GNU extension to eliminate the stray comma in the zero
+ * arguments case.
+ *
+ * The difference between elf_errmsg(-1) and elf_errmsg(elf_errno()) is that the
+ * latter clears the current error.
+ */
+#define elf_error(fmt, ...) \
+ fprintf(stderr, "%s: " fmt ": %s.\n", __func__, ##__VA_ARGS__, elf_errmsg(-1))
+
+static int btf_var_secinfo_cmp(const void *a, const void *b)
{
- struct elf_function *new;
- static GElf_Shdr sh;
- static int last_idx;
- int idx;
+ const struct btf_var_secinfo *av = a;
+ const struct btf_var_secinfo *bv = b;
- if (elf_sym__type(sym) != STT_FUNC)
- return 0;
+ return av->offset - bv->offset;
+}
- if (functions_cnt == functions_alloc) {
- functions_alloc = max(1000, functions_alloc * 3 / 2);
- new = realloc(functions, functions_alloc * sizeof(*functions));
- if (!new) {
- /*
- * The cleanup - delete_functions is called
- * in cu__encode_btf error path.
- */
- return -1;
- }
- functions = new;
+#define BITS_PER_BYTE 8
+#define BITS_PER_BYTE_MASK (BITS_PER_BYTE - 1)
+#define BITS_PER_BYTE_MASKED(bits) ((bits) & BITS_PER_BYTE_MASK)
+#define BITS_ROUNDDOWN_BYTES(bits) ((bits) >> 3)
+#define BITS_ROUNDUP_BYTES(bits) (BITS_ROUNDDOWN_BYTES(bits) + !!BITS_PER_BYTE_MASKED(bits))
+
+static const char * const btf_kind_str[NR_BTF_KINDS] = {
+ [BTF_KIND_UNKN] = "UNKNOWN",
+ [BTF_KIND_INT] = "INT",
+ [BTF_KIND_PTR] = "PTR",
+ [BTF_KIND_ARRAY] = "ARRAY",
+ [BTF_KIND_STRUCT] = "STRUCT",
+ [BTF_KIND_UNION] = "UNION",
+ [BTF_KIND_ENUM] = "ENUM",
+ [BTF_KIND_FWD] = "FWD",
+ [BTF_KIND_TYPEDEF] = "TYPEDEF",
+ [BTF_KIND_VOLATILE] = "VOLATILE",
+ [BTF_KIND_CONST] = "CONST",
+ [BTF_KIND_RESTRICT] = "RESTRICT",
+ [BTF_KIND_FUNC] = "FUNC",
+ [BTF_KIND_FUNC_PROTO] = "FUNC_PROTO",
+ [BTF_KIND_VAR] = "VAR",
+ [BTF_KIND_DATASEC] = "DATASEC",
+ [BTF_KIND_FLOAT] = "FLOAT",
+ [BTF_KIND_DECL_TAG] = "DECL_TAG",
+ [BTF_KIND_TYPE_TAG] = "TYPE_TAG",
+};
+
+static const char *btf__printable_name(const struct btf *btf, uint32_t offset)
+{
+ if (!offset)
+ return "(anon)";
+ else
+ return btf__str_by_offset(btf, offset);
+}
+
+static const char * btf__int_encoding_str(uint8_t encoding)
+{
+ if (encoding == 0)
+ return "(none)";
+ else if (encoding == BTF_INT_SIGNED)
+ return "SIGNED";
+ else if (encoding == BTF_INT_CHAR)
+ return "CHAR";
+ else if (encoding == BTF_INT_BOOL)
+ return "BOOL";
+ else
+ return "UNKN";
+}
+
+__attribute ((format (printf, 5, 6)))
+static void btf__log_err(const struct btf *btf, int kind, const char *name,
+ bool output_cr, const char *fmt, ...)
+{
+ fprintf(stderr, "[%u] %s %s", btf__get_nr_types(btf) + 1,
+ btf_kind_str[kind], name ?: "(anon)");
+
+ if (fmt && *fmt) {
+ va_list ap;
+
+ fprintf(stderr, " ");
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
}
- idx = elf_sym__section(sym);
+ if (output_cr)
+ fprintf(stderr, "\n");
+}
- if (idx != last_idx) {
- if (!elf_section_by_idx(btfe->elf, &sh, idx))
- return 0;
- last_idx = idx;
+__attribute ((format (printf, 5, 6)))
+static void btf_encoder__log_type(const struct btf_encoder *encoder, const struct btf_type *t,
+ bool err, bool output_cr, const char *fmt, ...)
+{
+ const struct btf *btf = encoder->btf;
+ uint8_t kind;
+ FILE *out;
+
+ if (!encoder->verbose && !err)
+ return;
+
+ kind = BTF_INFO_KIND(t->info);
+ out = err ? stderr : stdout;
+
+ fprintf(out, "[%u] %s %s",
+ btf__get_nr_types(btf), btf_kind_str[kind],
+ btf__printable_name(btf, t->name_off));
+
+ if (fmt && *fmt) {
+ va_list ap;
+
+ fprintf(out, " ");
+ va_start(ap, fmt);
+ vfprintf(out, fmt, ap);
+ va_end(ap);
}
- functions[functions_cnt].name = elf_sym__name(sym, btfe->symtab);
- functions[functions_cnt].addr = elf_sym__value(sym);
- functions[functions_cnt].sh_addr = sh.sh_addr;
- functions[functions_cnt].generated = false;
- functions_cnt++;
- return 0;
+ if (output_cr)
+ fprintf(out, "\n");
}
-static int addrs_cmp(const void *_a, const void *_b)
+__attribute ((format (printf, 5, 6)))
+static void btf_encoder__log_member(const struct btf_encoder *encoder, const struct btf_type *t,
+ const struct btf_member *member, bool err, const char *fmt, ...)
{
- const __u64 *a = _a;
- const __u64 *b = _b;
+ const struct btf *btf = encoder->btf;
+ FILE *out;
- if (*a == *b)
- return 0;
- return *a < *b ? -1 : 1;
+ if (!encoder->verbose && !err)
+ return;
+
+ out = err ? stderr : stdout;
+
+ if (btf_kflag(t))
+ fprintf(out, "\t%s type_id=%u bitfield_size=%u bits_offset=%u",
+ btf__printable_name(btf, member->name_off),
+ member->type,
+ BTF_MEMBER_BITFIELD_SIZE(member->offset),
+ BTF_MEMBER_BIT_OFFSET(member->offset));
+ else
+ fprintf(out, "\t%s type_id=%u bits_offset=%u",
+ btf__printable_name(btf, member->name_off),
+ member->type,
+ member->offset);
+
+ if (fmt && *fmt) {
+ va_list ap;
+
+ fprintf(out, " ");
+ va_start(ap, fmt);
+ vfprintf(out, fmt, ap);
+ va_end(ap);
+ }
+
+ fprintf(out, "\n");
}
-static int get_vmlinux_addrs(struct btf_elf *btfe, struct funcs_layout *fl,
- __u64 **paddrs, __u64 *pcount)
+__attribute ((format (printf, 6, 7)))
+static void btf_encoder__log_func_param(struct btf_encoder *encoder, const char *name, uint32_t type,
+ bool err, bool is_last_param, const char *fmt, ...)
{
- __u64 *addrs, count, offset;
- unsigned int addr_size, i;
- Elf_Data *data;
- GElf_Shdr shdr;
- Elf_Scn *sec;
+ FILE *out;
- /* Initialize for the sake of all error paths below. */
- *paddrs = NULL;
- *pcount = 0;
+ if (!encoder->verbose && !err)
+ return;
- if (!fl->mcount_start || !fl->mcount_stop)
- return 0;
+ out = err ? stderr : stdout;
- /*
- * Find mcount addressed marked by __start_mcount_loc
- * and __stop_mcount_loc symbols and load them into
- * sorted array.
- */
- sec = elf_getscn(btfe->elf, fl->mcount_sec_idx);
- if (!sec || !gelf_getshdr(sec, &shdr)) {
- fprintf(stderr, "Failed to get section(%lu) header.\n",
- fl->mcount_sec_idx);
- return -1;
+ if (is_last_param && !type)
+ fprintf(out, "vararg)\n");
+ else
+ fprintf(out, "%u %s%s", type, name, is_last_param ? ")\n" : ", ");
+
+ if (fmt && *fmt) {
+ va_list ap;
+
+ fprintf(out, " ");
+ va_start(ap, fmt);
+ vfprintf(out, fmt, ap);
+ va_end(ap);
}
+}
- /* Get address size from processed file's ELF class. */
- addr_size = gelf_getclass(btfe->elf) == ELFCLASS32 ? 4 : 8;
+static int32_t btf_encoder__add_float(struct btf_encoder *encoder, const struct base_type *bt, const char *name)
+{
+ int32_t id = btf__add_float(encoder->btf, name, BITS_ROUNDUP_BYTES(bt->bit_size));
- offset = fl->mcount_start - shdr.sh_addr;
- count = (fl->mcount_stop - fl->mcount_start) / addr_size;
+ if (id < 0) {
+ btf__log_err(encoder->btf, BTF_KIND_FLOAT, name, true, "Error emitting BTF type");
+ } else {
+ const struct btf_type *t;
- data = elf_getdata(sec, 0);
- if (!data) {
- fprintf(stderr, "Failed to get section(%lu) data.\n",
- fl->mcount_sec_idx);
- return -1;
+ t = btf__type_by_id(encoder->btf, id);
+ btf_encoder__log_type(encoder, t, false, true, "size=%u nr_bits=%u", t->size, bt->bit_size);
}
- addrs = malloc(count * sizeof(addrs[0]));
- if (!addrs) {
- fprintf(stderr, "Failed to allocate memory for ftrace addresses.\n");
+ return id;
+}
+
+static int32_t btf_encoder__add_base_type(struct btf_encoder *encoder, const struct base_type *bt, const char *name)
+{
+ const struct btf_type *t;
+ uint8_t encoding = 0;
+ uint16_t byte_sz;
+ int32_t id;
+
+ if (bt->is_signed) {
+ encoding = BTF_INT_SIGNED;
+ } else if (bt->is_bool) {
+ encoding = BTF_INT_BOOL;
+ } else if (bt->float_type && encoder->gen_floats) {
+ /*
+ * Encode floats as BTF_KIND_FLOAT if allowed, otherwise (in
+ * compatibility mode) encode them as BTF_KIND_INT - that's not
+ * fully correct, but that's what it used to be.
+ */
+ if (bt->float_type == BT_FP_SINGLE ||
+ bt->float_type == BT_FP_DOUBLE ||
+ bt->float_type == BT_FP_LDBL)
+ return btf_encoder__add_float(encoder, bt, name);
+ fprintf(stderr, "Complex, interval and imaginary float types are not supported\n");
return -1;
}
- if (addr_size == sizeof(__u64)) {
- memcpy(addrs, data->d_buf + offset, count * addr_size);
+ /* dwarf5 may emit DW_ATE_[un]signed_{num} base types where
+ * {num} is not power of 2 and may exceed 128. Such attributes
+ * are mostly used to record operation for an actual parameter
+ * or variable.
+ * For example,
+ * DW_AT_location (indexed (0x3c) loclist = 0x00008fb0:
+ * [0xffffffff82808812, 0xffffffff82808817):
+ * DW_OP_breg0 RAX+0,
+ * DW_OP_convert (0x000e97d5) "DW_ATE_unsigned_64",
+ * DW_OP_convert (0x000e97df) "DW_ATE_unsigned_8",
+ * DW_OP_stack_value,
+ * DW_OP_piece 0x1,
+ * DW_OP_breg0 RAX+0,
+ * DW_OP_convert (0x000e97d5) "DW_ATE_unsigned_64",
+ * DW_OP_convert (0x000e97da) "DW_ATE_unsigned_32",
+ * DW_OP_lit8,
+ * DW_OP_shr,
+ * DW_OP_convert (0x000e97da) "DW_ATE_unsigned_32",
+ * DW_OP_convert (0x000e97e4) "DW_ATE_unsigned_24",
+ * DW_OP_stack_value, DW_OP_piece 0x3
+ * DW_AT_name ("ebx")
+ * DW_AT_decl_file ("/linux/arch/x86/events/intel/core.c")
+ *
+ * In the above example, at some point, one unsigned_32 value
+ * is right shifted by 8 and the result is converted to unsigned_32
+ * and then unsigned_24.
+ *
+ * BTF does not need such DW_OP_* information so let us sanitize
+ * these non-regular int types to avoid libbpf/kernel complaints.
+ */
+ byte_sz = BITS_ROUNDUP_BYTES(bt->bit_size);
+ if (!byte_sz || (byte_sz & (byte_sz - 1))) {
+ name = "__SANITIZED_FAKE_INT__";
+ byte_sz = 4;
+ }
+
+ id = btf__add_int(encoder->btf, name, byte_sz, encoding);
+ if (id < 0) {
+ btf__log_err(encoder->btf, BTF_KIND_INT, name, true, "Error emitting BTF type");
} else {
- for (i = 0; i < count; i++)
- addrs[i] = (__u64) *((__u32 *) (data->d_buf + offset + i * addr_size));
+ t = btf__type_by_id(encoder->btf, id);
+ btf_encoder__log_type(encoder, t, false, true, "size=%u nr_bits=%u encoding=%s%s",
+ t->size, bt->bit_size, btf__int_encoding_str(encoding),
+ id < 0 ? " Error in emitting BTF" : "" );
}
- *paddrs = addrs;
- *pcount = count;
- return 0;
+ return id;
}
-static int
-get_kmod_addrs(struct btf_elf *btfe, __u64 **paddrs, __u64 *pcount)
+static int32_t btf_encoder__add_ref_type(struct btf_encoder *encoder, uint16_t kind, uint32_t type,
+ const char *name, bool kind_flag)
{
- __u64 *addrs, count;
- unsigned int addr_size, i;
- GElf_Shdr shdr_mcount;
- Elf_Data *data;
- Elf_Scn *sec;
+ struct btf *btf = encoder->btf;
+ const struct btf_type *t;
+ int32_t id;
+
+ switch (kind) {
+ case BTF_KIND_PTR:
+ id = btf__add_ptr(btf, type);
+ break;
+ case BTF_KIND_VOLATILE:
+ id = btf__add_volatile(btf, type);
+ break;
+ case BTF_KIND_CONST:
+ id = btf__add_const(btf, type);
+ break;
+ case BTF_KIND_RESTRICT:
+ id = btf__add_restrict(btf, type);
+ break;
+ case BTF_KIND_TYPEDEF:
+ id = btf__add_typedef(btf, name, type);
+ break;
+ case BTF_KIND_TYPE_TAG:
+ id = btf__add_type_tag(btf, name, type);
+ break;
+ case BTF_KIND_FWD:
+ id = btf__add_fwd(btf, name, kind_flag);
+ break;
+ case BTF_KIND_FUNC:
+ id = btf__add_func(btf, name, BTF_FUNC_STATIC, type);
+ break;
+ default:
+ btf__log_err(btf, kind, name, true, "Unexpected kind for reference");
+ return -1;
+ }
- /* Initialize for the sake of all error paths below. */
- *paddrs = NULL;
- *pcount = 0;
+ if (id > 0) {
+ t = btf__type_by_id(btf, id);
+ if (kind == BTF_KIND_FWD)
+ btf_encoder__log_type(encoder, t, false, true, "%s", kind_flag ? "union" : "struct");
+ else
+ btf_encoder__log_type(encoder, t, false, true, "type_id=%u", t->type);
+ } else {
+ btf__log_err(btf, kind, name, true, "Error emitting BTF type");
+ }
+ return id;
+}
- /* get __mcount_loc */
- sec = elf_section_by_name(btfe->elf, &btfe->ehdr, &shdr_mcount,
- "__mcount_loc", NULL);
- if (!sec) {
- if (btf_elf__verbose) {
- printf("%s: '%s' doesn't have __mcount_loc section\n", __func__,
- btfe->filename);
- }
- return 0;
+static int32_t btf_encoder__add_array(struct btf_encoder *encoder, uint32_t type, uint32_t index_type, uint32_t nelems)
+{
+ struct btf *btf = encoder->btf;
+ const struct btf_type *t;
+ const struct btf_array *array;
+ int32_t id;
+
+ id = btf__add_array(btf, index_type, type, nelems);
+ if (id > 0) {
+ t = btf__type_by_id(btf, id);
+ array = btf_array(t);
+ btf_encoder__log_type(encoder, t, false, true, "type_id=%u index_type_id=%u nr_elems=%u",
+ array->type, array->index_type, array->nelems);
+ } else {
+ btf__log_err(btf, BTF_KIND_ARRAY, NULL, true,
+ "type_id=%u index_type_id=%u nr_elems=%u Error emitting BTF type",
+ type, index_type, nelems);
}
+ return id;
+}
+
+static int btf_encoder__add_field(struct btf_encoder *encoder, const char *name, uint32_t type, uint32_t bitfield_size, uint32_t offset)
+{
+ struct btf *btf = encoder->btf;
+ const struct btf_type *t;
+ const struct btf_member *m;
+ int err;
- data = elf_getdata(sec, NULL);
- if (!data) {
- fprintf(stderr, "Failed to data for __mcount_loc section.\n");
+ err = btf__add_field(btf, name, type, offset, bitfield_size);
+ t = btf__type_by_id(btf, btf__get_nr_types(btf));
+ if (err) {
+ fprintf(stderr, "[%u] %s %s's field '%s' offset=%u bit_size=%u type=%u Error emitting field\n",
+ btf__get_nr_types(btf), btf_kind_str[btf_kind(t)],
+ btf__printable_name(btf, t->name_off),
+ name, offset, bitfield_size, type);
+ } else {
+ m = &btf_members(t)[btf_vlen(t) - 1];
+ btf_encoder__log_member(encoder, t, m, false, NULL);
+ }
+ return err;
+}
+
+static int32_t btf_encoder__add_struct(struct btf_encoder *encoder, uint8_t kind, const char *name, uint32_t size)
+{
+ struct btf *btf = encoder->btf;
+ const struct btf_type *t;
+ int32_t id;
+
+ switch (kind) {
+ case BTF_KIND_STRUCT:
+ id = btf__add_struct(btf, name, size);
+ break;
+ case BTF_KIND_UNION:
+ id = btf__add_union(btf, name, size);
+ break;
+ default:
+ btf__log_err(btf, kind, name, true, "Unexpected kind of struct");
return -1;
}
- /* Get address size from processed file's ELF class. */
- addr_size = gelf_getclass(btfe->elf) == ELFCLASS32 ? 4 : 8;
+ if (id < 0) {
+ btf__log_err(btf, kind, name, true, "Error emitting BTF type");
+ } else {
+ t = btf__type_by_id(btf, id);
+ btf_encoder__log_type(encoder, t, false, true, "size=%u", t->size);
+ }
+
+ return id;
+}
+
+static int32_t btf_encoder__add_enum(struct btf_encoder *encoder, const char *name, uint32_t bit_size)
+{
+ struct btf *btf = encoder->btf;
+ const struct btf_type *t;
+ int32_t id, size;
+
+ size = BITS_ROUNDUP_BYTES(bit_size);
+ id = btf__add_enum(btf, name, size);
+ if (id > 0) {
+ t = btf__type_by_id(btf, id);
+ btf_encoder__log_type(encoder, t, false, true, "size=%u", t->size);
+ } else {
+ btf__log_err(btf, BTF_KIND_ENUM, name, true,
+ "size=%u Error emitting BTF type", size);
+ }
+ return id;
+}
+
+static int btf_encoder__add_enum_val(struct btf_encoder *encoder, const char *name, int32_t value)
+{
+ int err = btf__add_enum_value(encoder->btf, name, value);
- count = data->d_size / addr_size;
+ if (!err) {
+ if (encoder->verbose)
+ printf("\t%s val=%d\n", name, value);
+ } else {
+ fprintf(stderr, "\t%s val=%d Error emitting BTF enum value\n",
+ name, value);
+ }
+ return err;
+}
+
+static int32_t btf_encoder__add_func_param(struct btf_encoder *encoder, const char *name, uint32_t type, bool is_last_param)
+{
+ int err = btf__add_func_param(encoder->btf, name, type);
- addrs = malloc(count * sizeof(addrs[0]));
- if (!addrs) {
- fprintf(stderr, "Failed to allocate memory for ftrace addresses.\n");
+ if (!err) {
+ btf_encoder__log_func_param(encoder, name, type, false, is_last_param, NULL);
+ return 0;
+ } else {
+ btf_encoder__log_func_param(encoder, name, type, true, is_last_param, "Error adding func param");
return -1;
}
+}
+
+static int32_t btf_encoder__add_func_proto(struct btf_encoder *encoder, struct ftype *ftype, uint32_t type_id_off)
+{
+ struct btf *btf = encoder->btf;
+ const struct btf_type *t;
+ struct parameter *param;
+ uint16_t nr_params, param_idx;
+ int32_t id, type_id;
- if (addr_size == sizeof(__u64)) {
- memcpy(addrs, data->d_buf, count * addr_size);
+ /* add btf_type for func_proto */
+ nr_params = ftype->nr_parms + (ftype->unspec_parms ? 1 : 0);
+ type_id = ftype->tag.type == 0 ? 0 : type_id_off + ftype->tag.type;
+
+ id = btf__add_func_proto(btf, type_id);
+ if (id > 0) {
+ t = btf__type_by_id(btf, id);
+ btf_encoder__log_type(encoder, t, false, false, "return=%u args=(%s", t->type, !nr_params ? "void)\n" : "");
} else {
- for (i = 0; i < count; i++)
- addrs[i] = (__u64) *((__u32 *) (data->d_buf + i * addr_size));
+ btf__log_err(btf, BTF_KIND_FUNC_PROTO, NULL, true,
+ "return=%u vlen=%u Error emitting BTF type",
+ type_id, nr_params);
+ return id;
}
- /*
- * We get Elf object from dwfl_module_getelf function,
- * which performs all possible relocations, including
- * __mcount_loc section.
- *
- * So addrs array now contains relocated values, which
- * we need take into account when we compare them to
- * functions values, see comment in setup_functions
- * function.
- */
- *paddrs = addrs;
- *pcount = count;
- return 0;
+ /* add parameters */
+ param_idx = 0;
+ ftype__for_each_parameter(ftype, param) {
+ const char *name = parameter__name(param);
+
+ type_id = param->tag.type == 0 ? 0 : type_id_off + param->tag.type;
+ ++param_idx;
+ if (btf_encoder__add_func_param(encoder, name, type_id, param_idx == nr_params))
+ return -1;
+ }
+
+ ++param_idx;
+ if (ftype->unspec_parms)
+ if (btf_encoder__add_func_param(encoder, NULL, 0, param_idx == nr_params))
+ return -1;
+
+ return id;
}
-static int setup_functions(struct btf_elf *btfe, struct funcs_layout *fl)
+static int32_t btf_encoder__add_var(struct btf_encoder *encoder, uint32_t type, const char *name, uint32_t linkage)
{
- __u64 *addrs, count, i;
- int functions_valid = 0;
- bool kmod = false;
+ struct btf *btf = encoder->btf;
+ const struct btf_type *t;
+ int32_t id;
+
+ id = btf__add_var(btf, name, linkage, type);
+ if (id > 0) {
+ t = btf__type_by_id(btf, id);
+ btf_encoder__log_type(encoder, t, false, true, "type=%u linkage=%u", t->type, btf_var(t)->linkage);
+ } else {
+ btf__log_err(btf, BTF_KIND_VAR, name, true,
+ "type=%u linkage=%u Error emitting BTF type",
+ type, linkage);
+ }
+ return id;
+}
- /*
- * Check if we are processing vmlinux image and
- * get mcount data if it's detected.
- */
- if (get_vmlinux_addrs(btfe, fl, &addrs, &count))
- return -1;
+static int32_t btf_encoder__add_var_secinfo(struct btf_encoder *encoder, uint32_t type,
+ uint32_t offset, uint32_t size)
+{
+ struct btf_var_secinfo si = {
+ .type = type,
+ .offset = offset,
+ .size = size,
+ };
+ return gobuffer__add(&encoder->percpu_secinfo, &si, sizeof(si));
+}
- /*
- * Check if we are processing kernel module and
- * get mcount data if it's detected.
- */
- if (!addrs) {
- if (get_kmod_addrs(btfe, &addrs, &count))
+static int32_t btf_encoder__add_datasec(struct btf_encoder *encoder, const char *section_name)
+{
+ struct gobuffer *var_secinfo_buf = &encoder->percpu_secinfo;
+ struct btf *btf = encoder->btf;
+ size_t sz = gobuffer__size(var_secinfo_buf);
+ uint16_t nr_var_secinfo = sz / sizeof(struct btf_var_secinfo);
+ struct btf_var_secinfo *last_vsi, *vsi;
+ const struct btf_type *t;
+ uint32_t datasec_sz;
+ int32_t err, id, i;
+
+ qsort(var_secinfo_buf->entries, nr_var_secinfo,
+ sizeof(struct btf_var_secinfo), btf_var_secinfo_cmp);
+
+ last_vsi = (struct btf_var_secinfo *)var_secinfo_buf->entries + nr_var_secinfo - 1;
+ datasec_sz = last_vsi->offset + last_vsi->size;
+
+ id = btf__add_datasec(btf, section_name, datasec_sz);
+ if (id < 0) {
+ btf__log_err(btf, BTF_KIND_DATASEC, section_name, true,
+ "size=%u vlen=%u Error emitting BTF type",
+ datasec_sz, nr_var_secinfo);
+ } else {
+ t = btf__type_by_id(btf, id);
+ btf_encoder__log_type(encoder, t, false, true, "size=%u vlen=%u", t->size, nr_var_secinfo);
+ }
+
+ for (i = 0; i < nr_var_secinfo; i++) {
+ vsi = (struct btf_var_secinfo *)var_secinfo_buf->entries + i;
+ err = btf__add_datasec_var_info(btf, vsi->type, vsi->offset, vsi->size);
+ if (!err) {
+ if (encoder->verbose)
+ printf("\ttype=%u offset=%u size=%u\n",
+ vsi->type, vsi->offset, vsi->size);
+ } else {
+ fprintf(stderr, "\ttype=%u offset=%u size=%u Error emitting BTF datasec var info\n",
+ vsi->type, vsi->offset, vsi->size);
return -1;
- kmod = true;
+ }
}
- if (!addrs) {
- if (btf_elf__verbose)
- printf("ftrace symbols not detected, falling back to DWARF data\n");
- delete_functions();
- return 0;
+ return id;
+}
+
+static int32_t btf_encoder__add_decl_tag(struct btf_encoder *encoder, const char *value, uint32_t type,
+ int component_idx)
+{
+ struct btf *btf = encoder->btf;
+ const struct btf_type *t;
+ int32_t id;
+
+ id = btf__add_decl_tag(btf, value, type, component_idx);
+ if (id > 0) {
+ t = btf__type_by_id(btf, id);
+ btf_encoder__log_type(encoder, t, false, true, "type_id=%u component_idx=%d",
+ t->type, component_idx);
+ } else {
+ btf__log_err(btf, BTF_KIND_DECL_TAG, value, true, "component_idx=%d Error emitting BTF type",
+ component_idx);
}
- qsort(addrs, count, sizeof(addrs[0]), addrs_cmp);
- qsort(functions, functions_cnt, sizeof(functions[0]), functions_cmp);
+ return id;
+}
- /*
- * Let's got through all collected functions and filter
- * out those that are not in ftrace.
- */
- for (i = 0; i < functions_cnt; i++) {
- struct elf_function *func = &functions[i];
- /*
- * For vmlinux image both addrs[x] and functions[x]::addr
- * values are final address and are comparable.
- *
- * For kernel module addrs[x] is final address, but
- * functions[x]::addr is relative address within section
- * and needs to be relocated by adding sh_addr.
- */
- __u64 addr = kmod ? func->addr + func->sh_addr : func->addr;
+/*
+ * This corresponds to the same macro defined in
+ * include/linux/kallsyms.h
+ */
+#define KSYM_NAME_LEN 128
+
+static int functions_cmp(const void *_a, const void *_b)
+{
+ const struct elf_function *a = _a;
+ const struct elf_function *b = _b;
- /* Make sure function is within ftrace addresses. */
- if (bsearch(&addr, addrs, count, sizeof(addrs[0]), addrs_cmp)) {
+ return strcmp(a->name, b->name);
+}
+
+#ifndef max
+#define max(x, y) ((x) < (y) ? (y) : (x))
+#endif
+
+static int btf_encoder__collect_function(struct btf_encoder *encoder, GElf_Sym *sym)
+{
+ struct elf_function *new;
+ const char *name;
+
+ if (elf_sym__type(sym) != STT_FUNC)
+ return 0;
+ name = elf_sym__name(sym, encoder->symtab);
+ if (!name)
+ return 0;
+
+ if (encoder->functions.cnt == encoder->functions.allocated) {
+ encoder->functions.allocated = max(1000, encoder->functions.allocated * 3 / 2);
+ new = realloc(encoder->functions.entries, encoder->functions.allocated * sizeof(*encoder->functions.entries));
+ if (!new) {
/*
- * We iterate over sorted array, so we can easily skip
- * not valid item and move following valid field into
- * its place, and still keep the 'new' array sorted.
+ * The cleanup - delete_functions is called
+ * in btf_encoder__encode_cu error path.
*/
- if (i != functions_valid)
- functions[functions_valid] = functions[i];
- functions_valid++;
+ return -1;
}
+ encoder->functions.entries = new;
}
- functions_cnt = functions_valid;
- free(addrs);
-
- if (btf_elf__verbose)
- printf("Found %d functions!\n", functions_cnt);
+ encoder->functions.entries[encoder->functions.cnt].name = name;
+ encoder->functions.entries[encoder->functions.cnt].generated = false;
+ encoder->functions.cnt++;
return 0;
}
-static struct elf_function *find_function(const struct btf_elf *btfe,
- const char *name)
+static struct elf_function *btf_encoder__find_function(const struct btf_encoder *encoder, const char *name)
{
struct elf_function key = { .name = name };
- return bsearch(&key, functions, functions_cnt, sizeof(functions[0]),
- functions_cmp);
+ return bsearch(&key, encoder->functions.entries, encoder->functions.cnt, sizeof(key), functions_cmp);
}
static bool btf_name_char_ok(char c, bool first)
@@ -355,8 +767,6 @@ static void dump_invalid_symbol(const char *msg, const char *sym,
fprintf(stderr, "PAHOLE: Error: Use '--btf_encode_force' to ignore such symbols and force emit the btf.\n");
}
-extern struct debug_fmt_ops *dwarves__active_loader;
-
static int tag__check_id_drift(const struct tag *tag,
uint32_t core_id, uint32_t btf_type_id,
uint32_t type_id_off)
@@ -372,19 +782,18 @@ static int tag__check_id_drift(const struct tag *tag,
return 0;
}
-static int32_t structure_type__encode(struct btf_elf *btfe, struct cu *cu, struct tag *tag, uint32_t type_id_off)
+static int32_t btf_encoder__add_struct_type(struct btf_encoder *encoder, struct tag *tag, uint32_t type_id_off)
{
struct type *type = tag__type(tag);
struct class_member *pos;
- const char *name;
+ const char *name = type__name(type);
int32_t type_id;
uint8_t kind;
kind = (tag->tag == DW_TAG_union_type) ?
BTF_KIND_UNION : BTF_KIND_STRUCT;
- name = dwarves__active_loader->strings__ptr(cu, type->namespace.name);
- type_id = btf_elf__add_struct(btfe, kind, name, type->size);
+ type_id = btf_encoder__add_struct(encoder, kind, name, type->size);
if (type_id < 0)
return type_id;
@@ -394,8 +803,8 @@ static int32_t structure_type__encode(struct btf_elf *btfe, struct cu *cu, struc
* scheme, which conforms to BTF requirement, so no conversion
* is required.
*/
- name = dwarves__active_loader->strings__ptr(cu, pos->name);
- if (btf_elf__add_member(btfe, name, type_id_off + pos->tag.type, pos->bitfield_size, pos->bit_offset))
+ name = class_member__name(pos);
+ if (btf_encoder__add_field(encoder, name, type_id_off + pos->tag.type, pos->bitfield_size, pos->bit_offset))
return -1;
}
@@ -414,67 +823,68 @@ static uint32_t array_type__nelems(struct tag *tag)
return nelem;
}
-static int32_t enumeration_type__encode(struct btf_elf *btfe, struct cu *cu, struct tag *tag)
+static int32_t btf_encoder__add_enum_type(struct btf_encoder *encoder, struct tag *tag)
{
struct type *etype = tag__type(tag);
struct enumerator *pos;
- const char *name;
+ const char *name = type__name(etype);
int32_t type_id;
- name = dwarves__active_loader->strings__ptr(cu, etype->namespace.name);
- type_id = btf_elf__add_enum(btfe, name, etype->size);
+ type_id = btf_encoder__add_enum(encoder, name, etype->size);
if (type_id < 0)
return type_id;
type__for_each_enumerator(etype, pos) {
- name = dwarves__active_loader->strings__ptr(cu, pos->name);
- if (btf_elf__add_enum_val(btfe, name, pos->value))
+ name = enumerator__name(pos);
+ if (btf_encoder__add_enum_val(encoder, name, pos->value))
return -1;
}
return type_id;
}
-static bool need_index_type;
-
-static int tag__encode_btf(struct cu *cu, struct tag *tag, uint32_t core_id, struct btf_elf *btfe,
- uint32_t array_index_id, uint32_t type_id_off)
+static int btf_encoder__encode_tag(struct btf_encoder *encoder, struct tag *tag, uint32_t type_id_off)
{
/* single out type 0 as it represents special type "void" */
uint32_t ref_type_id = tag->type == 0 ? 0 : type_id_off + tag->type;
+ struct base_type *bt;
const char *name;
switch (tag->tag) {
case DW_TAG_base_type:
- name = dwarves__active_loader->strings__ptr(cu, tag__base_type(tag)->name);
- return btf_elf__add_base_type(btfe, tag__base_type(tag), name);
+ bt = tag__base_type(tag);
+ name = __base_type__name(bt);
+ return btf_encoder__add_base_type(encoder, bt, name);
case DW_TAG_const_type:
- return btf_elf__add_ref_type(btfe, BTF_KIND_CONST, ref_type_id, NULL, false);
+ return btf_encoder__add_ref_type(encoder, BTF_KIND_CONST, ref_type_id, NULL, false);
case DW_TAG_pointer_type:
- return btf_elf__add_ref_type(btfe, BTF_KIND_PTR, ref_type_id, NULL, false);
+ return btf_encoder__add_ref_type(encoder, BTF_KIND_PTR, ref_type_id, NULL, false);
case DW_TAG_restrict_type:
- return btf_elf__add_ref_type(btfe, BTF_KIND_RESTRICT, ref_type_id, NULL, false);
+ return btf_encoder__add_ref_type(encoder, BTF_KIND_RESTRICT, ref_type_id, NULL, false);
case DW_TAG_volatile_type:
- return btf_elf__add_ref_type(btfe, BTF_KIND_VOLATILE, ref_type_id, NULL, false);
+ return btf_encoder__add_ref_type(encoder, BTF_KIND_VOLATILE, ref_type_id, NULL, false);
case DW_TAG_typedef:
- name = dwarves__active_loader->strings__ptr(cu, tag__namespace(tag)->name);
- return btf_elf__add_ref_type(btfe, BTF_KIND_TYPEDEF, ref_type_id, name, false);
+ name = namespace__name(tag__namespace(tag));
+ return btf_encoder__add_ref_type(encoder, BTF_KIND_TYPEDEF, ref_type_id, name, false);
+ case DW_TAG_LLVM_annotation:
+ name = tag__btf_type_tag(tag)->value;
+ return btf_encoder__add_ref_type(encoder, BTF_KIND_TYPE_TAG, ref_type_id, name, false);
case DW_TAG_structure_type:
case DW_TAG_union_type:
case DW_TAG_class_type:
- name = dwarves__active_loader->strings__ptr(cu, tag__namespace(tag)->name);
+ name = namespace__name(tag__namespace(tag));
if (tag__type(tag)->declaration)
- return btf_elf__add_ref_type(btfe, BTF_KIND_FWD, 0, name, tag->tag == DW_TAG_union_type);
+ return btf_encoder__add_ref_type(encoder, BTF_KIND_FWD, 0, name, tag->tag == DW_TAG_union_type);
else
- return structure_type__encode(btfe, cu, tag, type_id_off);
+ return btf_encoder__add_struct_type(encoder, tag, type_id_off);
case DW_TAG_array_type:
/* TODO: Encode one dimension at a time. */
- need_index_type = true;
- return btf_elf__add_array(btfe, ref_type_id, array_index_id, array_type__nelems(tag));
+ encoder->need_index_type = true;
+ return btf_encoder__add_array(encoder, ref_type_id, encoder->array_index_id, array_type__nelems(tag));
case DW_TAG_enumeration_type:
- return enumeration_type__encode(btfe, cu, tag);
+ return btf_encoder__add_enum_type(encoder, tag);
case DW_TAG_subroutine_type:
- return btf_elf__add_func_proto(btfe, cu, tag__ftype(tag), type_id_off);
+ return btf_encoder__add_func_proto(encoder, tag__ftype(tag), type_id_off);
default:
fprintf(stderr, "Unsupported DW_TAG_%s(0x%x)\n",
dwarf_tag_name(tag->tag), tag->tag);
@@ -482,35 +892,172 @@ static int tag__encode_btf(struct cu *cu, struct tag *tag, uint32_t core_id, str
}
}
-static struct btf_elf *btfe;
-static uint32_t array_index_id;
-static bool has_index_type;
+static int btf_encoder__write_raw_file(struct btf_encoder *encoder)
+{
+ const char *filename = encoder->filename;
+ uint32_t raw_btf_size;
+ const void *raw_btf_data;
+ int fd, err;
+
+ raw_btf_data = btf__get_raw_data(encoder->btf, &raw_btf_size);
+ if (raw_btf_data == NULL) {
+ fprintf(stderr, "%s: btf__get_raw_data failed!\n", __func__);
+ return -1;
+ }
+
+ fd = open(filename, O_WRONLY | O_CREAT, 0640);
+ if (fd < 0) {
+ fprintf(stderr, "%s: Couldn't open %s for writing the raw BTF info: %s\n", __func__, filename, strerror(errno));
+ return -1;
+ }
+ err = write(fd, raw_btf_data, raw_btf_size);
+ if (err < 0)
+ fprintf(stderr, "%s: Couldn't write the raw BTF info to %s: %s\n", __func__, filename, strerror(errno));
+
+ close(fd);
-int btf_encoder__encode()
+ if ((uint32_t)err != raw_btf_size) {
+ fprintf(stderr, "%s: Could only write %d bytes to %s of raw BTF info out of %d, aborting\n", __func__, err, filename, raw_btf_size);
+ unlink(filename);
+ err = -1;
+ } else {
+ /* go from bytes written == raw_btf_size to an indication that all went fine */
+ err = 0;
+ }
+
+ return err;
+}
+
+static int btf_encoder__write_elf(struct btf_encoder *encoder)
{
- int err;
+ struct btf *btf = encoder->btf;
+ const char *filename = encoder->filename;
+ GElf_Shdr shdr_mem, *shdr;
+ Elf_Data *btf_data = NULL;
+ Elf_Scn *scn = NULL;
+ Elf *elf = NULL;
+ const void *raw_btf_data;
+ uint32_t raw_btf_size;
+ int fd, err = -1;
+ size_t strndx;
+
+ fd = open(filename, O_RDWR);
+ if (fd < 0) {
+ fprintf(stderr, "Cannot open %s\n", filename);
+ return -1;
+ }
+
+ if (elf_version(EV_CURRENT) == EV_NONE) {
+ elf_error("Cannot set libelf version");
+ goto out;
+ }
+
+ elf = elf_begin(fd, ELF_C_RDWR, NULL);
+ if (elf == NULL) {
+ elf_error("Cannot update ELF file");
+ goto out;
+ }
- if (gobuffer__size(&btfe->percpu_secinfo) != 0)
- btf_elf__add_datasec_type(btfe, PERCPU_SECTION, &btfe->percpu_secinfo);
+ elf_flagelf(elf, ELF_C_SET, ELF_F_DIRTY);
- err = btf_elf__encode(btfe, 0);
- delete_functions();
- btf_elf__delete(btfe);
- btfe = NULL;
+ /*
+ * First we look if there was already a .BTF section to overwrite.
+ */
+ elf_getshdrstrndx(elf, &strndx);
+ while ((scn = elf_nextscn(elf, scn)) != NULL) {
+ shdr = gelf_getshdr(scn, &shdr_mem);
+ if (shdr == NULL)
+ continue;
+ char *secname = elf_strptr(elf, strndx, shdr->sh_name);
+ if (strcmp(secname, ".BTF") == 0) {
+ btf_data = elf_getdata(scn, btf_data);
+ break;
+ }
+ }
+
+ raw_btf_data = btf__get_raw_data(btf, &raw_btf_size);
+
+ if (btf_data) {
+ /* Existing .BTF section found */
+ btf_data->d_buf = (void *)raw_btf_data;
+ btf_data->d_size = raw_btf_size;
+ elf_flagdata(btf_data, ELF_C_SET, ELF_F_DIRTY);
+
+ if (elf_update(elf, ELF_C_NULL) >= 0 &&
+ elf_update(elf, ELF_C_WRITE) >= 0)
+ err = 0;
+ else
+ elf_error("elf_update failed");
+ } else {
+ const char *llvm_objcopy;
+ char tmp_fn[PATH_MAX];
+ char cmd[PATH_MAX * 2];
+
+ llvm_objcopy = getenv("LLVM_OBJCOPY");
+ if (!llvm_objcopy)
+ llvm_objcopy = "llvm-objcopy";
+
+ /* Use objcopy to add a .BTF section */
+ snprintf(tmp_fn, sizeof(tmp_fn), "%s.btf", filename);
+ close(fd);
+ fd = creat(tmp_fn, S_IRUSR | S_IWUSR);
+ if (fd == -1) {
+ fprintf(stderr, "%s: open(%s) failed!\n", __func__,
+ tmp_fn);
+ goto out;
+ }
+
+ if (write(fd, raw_btf_data, raw_btf_size) != raw_btf_size) {
+ fprintf(stderr, "%s: write of %d bytes to '%s' failed: %d!\n",
+ __func__, raw_btf_size, tmp_fn, errno);
+ goto unlink;
+ }
+
+ snprintf(cmd, sizeof(cmd), "%s --add-section .BTF=%s %s",
+ llvm_objcopy, tmp_fn, filename);
+ if (system(cmd)) {
+ fprintf(stderr, "%s: failed to add .BTF section to '%s': %d!\n",
+ __func__, filename, errno);
+ goto unlink;
+ }
+
+ err = 0;
+ unlink:
+ unlink(tmp_fn);
+ }
+
+out:
+ if (fd != -1)
+ close(fd);
+ if (elf)
+ elf_end(elf);
return err;
}
-#define MAX_PERCPU_VAR_CNT 4096
+int btf_encoder__encode(struct btf_encoder *encoder)
+{
+ int err;
-struct var_info {
- uint64_t addr;
- uint32_t sz;
- const char *name;
-};
+ if (gobuffer__size(&encoder->percpu_secinfo) != 0)
+ btf_encoder__add_datasec(encoder, PERCPU_SECTION);
-static struct var_info percpu_vars[MAX_PERCPU_VAR_CNT];
-static int percpu_var_cnt;
+ /* Empty file, nothing to do, so... done! */
+ if (btf__get_nr_types(encoder->btf) == 0)
+ return 0;
+
+ if (btf__dedup(encoder->btf, NULL, NULL)) {
+ fprintf(stderr, "%s: btf__dedup failed!\n", __func__);
+ return -1;
+ }
+
+ if (encoder->raw_output)
+ err = btf_encoder__write_raw_file(encoder);
+ else
+ err = btf_encoder__write_elf(encoder);
+
+ return err;
+}
static int percpu_var_cmp(const void *_a, const void *_b)
{
@@ -522,14 +1069,11 @@ static int percpu_var_cmp(const void *_a, const void *_b)
return a->addr < b->addr ? -1 : 1;
}
-static bool percpu_var_exists(uint64_t addr, uint32_t *sz, const char **name)
+static bool btf_encoder__percpu_var_exists(struct btf_encoder *encoder, uint64_t addr, uint32_t *sz, const char **name)
{
- const struct var_info *p;
struct var_info key = { .addr = addr };
-
- p = bsearch(&key, percpu_vars, percpu_var_cnt,
- sizeof(percpu_vars[0]), percpu_var_cmp);
-
+ const struct var_info *p = bsearch(&key, encoder->percpu.vars, encoder->percpu.var_cnt,
+ sizeof(encoder->percpu.vars[0]), percpu_var_cmp);
if (!p)
return false;
@@ -538,14 +1082,14 @@ static bool percpu_var_exists(uint64_t addr, uint32_t *sz, const char **name)
return true;
}
-static int collect_percpu_var(struct btf_elf *btfe, GElf_Sym *sym)
+static int btf_encoder__collect_percpu_var(struct btf_encoder *encoder, GElf_Sym *sym, size_t sym_sec_idx)
{
const char *sym_name;
uint64_t addr;
uint32_t size;
/* compare a symbol's shndx to determine if it's a percpu variable */
- if (elf_sym__section(sym) != btfe->percpu_shndx)
+ if (sym_sec_idx != encoder->percpu.shndx)
return 0;
if (elf_sym__type(sym) != STT_OBJECT)
return 0;
@@ -556,238 +1100,125 @@ static int collect_percpu_var(struct btf_elf *btfe, GElf_Sym *sym)
if (!size)
return 0; /* ignore zero-sized symbols */
- sym_name = elf_sym__name(sym, btfe->symtab);
+ sym_name = elf_sym__name(sym, encoder->symtab);
if (!btf_name_valid(sym_name)) {
dump_invalid_symbol("Found symbol of invalid name when encoding btf",
- sym_name, btf_elf__verbose, btf_elf__force);
- if (btf_elf__force)
+ sym_name, encoder->verbose, encoder->force);
+ if (encoder->force)
return 0;
return -1;
}
- if (btf_elf__verbose)
+ if (encoder->verbose)
printf("Found per-CPU symbol '%s' at address 0x%" PRIx64 "\n", sym_name, addr);
- if (percpu_var_cnt == MAX_PERCPU_VAR_CNT) {
+ /* Make sure addr is section-relative. For kernel modules (which are
+ * ET_REL files) this is already the case. For vmlinux (which is an
+ * ET_EXEC file) we need to subtract the section address.
+ */
+ if (!encoder->is_rel)
+ addr -= encoder->percpu.base_addr;
+
+ if (encoder->percpu.var_cnt == MAX_PERCPU_VAR_CNT) {
fprintf(stderr, "Reached the limit of per-CPU variables: %d\n",
MAX_PERCPU_VAR_CNT);
return -1;
}
- percpu_vars[percpu_var_cnt].addr = addr;
- percpu_vars[percpu_var_cnt].sz = size;
- percpu_vars[percpu_var_cnt].name = sym_name;
- percpu_var_cnt++;
+ encoder->percpu.vars[encoder->percpu.var_cnt].addr = addr;
+ encoder->percpu.vars[encoder->percpu.var_cnt].sz = size;
+ encoder->percpu.vars[encoder->percpu.var_cnt].name = sym_name;
+ encoder->percpu.var_cnt++;
return 0;
}
-static void collect_symbol(GElf_Sym *sym, struct funcs_layout *fl)
+static int btf_encoder__collect_symbols(struct btf_encoder *encoder, bool collect_percpu_vars)
{
- if (!fl->mcount_start &&
- !strcmp("__start_mcount_loc", elf_sym__name(sym, btfe->symtab))) {
- fl->mcount_start = sym->st_value;
- fl->mcount_sec_idx = sym->st_shndx;
- }
-
- if (!fl->mcount_stop &&
- !strcmp("__stop_mcount_loc", elf_sym__name(sym, btfe->symtab)))
- fl->mcount_stop = sym->st_value;
-}
-
-static int collect_symbols(struct btf_elf *btfe, bool collect_percpu_vars)
-{
- struct funcs_layout fl = { };
+ Elf32_Word sym_sec_idx;
uint32_t core_id;
GElf_Sym sym;
/* cache variables' addresses, preparing for searching in symtab. */
- percpu_var_cnt = 0;
+ encoder->percpu.var_cnt = 0;
/* search within symtab for percpu variables */
- elf_symtab__for_each_symbol(btfe->symtab, core_id, sym) {
- if (collect_percpu_vars && collect_percpu_var(btfe, &sym))
+ elf_symtab__for_each_symbol_index(encoder->symtab, core_id, sym, sym_sec_idx) {
+ if (collect_percpu_vars && btf_encoder__collect_percpu_var(encoder, &sym, sym_sec_idx))
return -1;
- if (collect_function(btfe, &sym))
+ if (btf_encoder__collect_function(encoder, &sym))
return -1;
- collect_symbol(&sym, &fl);
}
if (collect_percpu_vars) {
- if (percpu_var_cnt)
- qsort(percpu_vars, percpu_var_cnt, sizeof(percpu_vars[0]), percpu_var_cmp);
+ if (encoder->percpu.var_cnt)
+ qsort(encoder->percpu.vars, encoder->percpu.var_cnt, sizeof(encoder->percpu.vars[0]), percpu_var_cmp);
- if (btf_elf__verbose)
- printf("Found %d per-CPU variables!\n", percpu_var_cnt);
+ if (encoder->verbose)
+ printf("Found %d per-CPU variables!\n", encoder->percpu.var_cnt);
}
- if (functions_cnt && setup_functions(btfe, &fl)) {
- fprintf(stderr, "Failed to filter DWARF functions\n");
- return -1;
+ if (encoder->functions.cnt) {
+ qsort(encoder->functions.entries, encoder->functions.cnt, sizeof(encoder->functions.entries[0]),
+ functions_cmp);
+ if (encoder->verbose)
+ printf("Found %d functions!\n", encoder->functions.cnt);
}
return 0;
}
-static bool has_arg_names(struct cu *cu, struct ftype *ftype)
+static bool ftype__has_arg_names(const struct ftype *ftype)
{
struct parameter *param;
- const char *name;
ftype__for_each_parameter(ftype, param) {
- name = dwarves__active_loader->strings__ptr(cu, param->name);
- if (name == NULL)
+ if (parameter__name(param) == NULL)
return false;
}
return true;
}
-int cu__encode_btf(struct cu *cu, int verbose, bool force,
- bool skip_encoding_vars)
+static int btf_encoder__encode_cu_variables(struct btf_encoder *encoder, struct cu *cu, uint32_t type_id_off)
{
- uint32_t type_id_off;
uint32_t core_id;
- struct variable *var;
- struct function *fn;
struct tag *pos;
- int err = 0;
-
- btf_elf__verbose = verbose;
- btf_elf__force = force;
+ int err = -1;
- if (btfe && strcmp(btfe->filename, cu->filename)) {
- err = btf_encoder__encode();
- if (err)
- goto out;
-
- /* Finished one file, add one empty line */
- if (verbose)
- printf("\n");
- }
-
- if (!btfe) {
- btfe = btf_elf__new(cu->filename, cu->elf, base_btf);
- if (!btfe)
- return -1;
-
- err = collect_symbols(btfe, !skip_encoding_vars);
- if (err)
- goto out;
-
- has_index_type = false;
- need_index_type = false;
- array_index_id = 0;
-
- if (verbose)
- printf("File %s:\n", btfe->filename);
- }
-
- type_id_off = btf__get_nr_types(btfe->btf);
-
- if (!has_index_type) {
- /* cu__find_base_type_by_name() takes "type_id_t *id" */
- type_id_t id;
- if (cu__find_base_type_by_name(cu, "int", &id)) {
- has_index_type = true;
- array_index_id = type_id_off + id;
- } else {
- has_index_type = false;
- array_index_id = type_id_off + cu->types_table.nr_entries;
- }
- }
-
- cu__for_each_type(cu, core_id, pos) {
- int32_t btf_type_id = tag__encode_btf(cu, pos, core_id, btfe, array_index_id, type_id_off);
-
- if (btf_type_id < 0 ||
- tag__check_id_drift(pos, core_id, btf_type_id, type_id_off)) {
- err = -1;
- goto out;
- }
- }
-
- if (need_index_type && !has_index_type) {
- struct base_type bt = {};
-
- bt.name = 0;
- bt.bit_size = 32;
- btf_elf__add_base_type(btfe, &bt, "__ARRAY_SIZE_TYPE__");
- has_index_type = true;
- }
-
- cu__for_each_function(cu, core_id, fn) {
- int btf_fnproto_id, btf_fn_id;
- const char *name;
-
- /*
- * Skip functions that:
- * - are marked as declarations
- * - do not have full argument names
- * - are not in ftrace list (if it's available)
- * - are not external (in case ftrace filter is not available)
- */
- if (fn->declaration)
- continue;
- if (!has_arg_names(cu, &fn->proto))
- continue;
- if (functions_cnt) {
- struct elf_function *func;
-
- func = find_function(btfe, function__name(fn, cu));
- if (!func || func->generated)
- continue;
- func->generated = true;
- } else {
- if (!fn->external)
- continue;
- }
-
- btf_fnproto_id = btf_elf__add_func_proto(btfe, cu, &fn->proto, type_id_off);
- name = dwarves__active_loader->strings__ptr(cu, fn->name);
- btf_fn_id = btf_elf__add_ref_type(btfe, BTF_KIND_FUNC, btf_fnproto_id, name, false);
- if (btf_fnproto_id < 0 || btf_fn_id < 0) {
- err = -1;
- printf("error: failed to encode function '%s'\n", function__name(fn, cu));
- goto out;
- }
- }
-
- if (skip_encoding_vars)
- goto out;
-
- if (btfe->percpu_shndx == 0 || !btfe->symtab)
- goto out;
+ if (encoder->percpu.shndx == 0 || !encoder->symtab)
+ return 0;
- if (verbose)
+ if (encoder->verbose)
printf("search cu '%s' for percpu global variables.\n", cu->name);
cu__for_each_variable(cu, core_id, pos) {
+ struct variable *var = tag__variable(pos);
uint32_t size, type, linkage;
const char *name, *dwarf_name;
+ struct llvm_annotation *annot;
+ const struct tag *tag;
uint64_t addr;
int id;
- var = tag__variable(pos);
if (var->declaration && !var->spec)
continue;
+
/* percpu variables are allocated in global space */
if (variable__scope(var) != VSCOPE_GLOBAL && !var->spec)
continue;
/* addr has to be recorded before we follow spec */
addr = var->ip.addr;
+ dwarf_name = variable__name(var);
- /* DWARF takes into account .data..percpu section offset
- * within its segment, which for vmlinux is 0, but for kernel
- * modules is >0. ELF symbols, on the other hand, don't take
- * into account these offsets (as they are relative to the
- * section start), so to match DWARF and ELF symbols we need
- * to negate the section base address here.
+ /* Make sure addr is section-relative. DWARF, unlike ELF,
+ * always contains virtual symbol addresses, so subtract
+ * the section address unconditionally.
*/
- if (addr < btfe->percpu_base_addr || addr >= btfe->percpu_base_addr + btfe->percpu_sec_sz)
+ if (addr < encoder->percpu.base_addr || addr >= encoder->percpu.base_addr + encoder->percpu.sec_sz)
continue;
- addr -= btfe->percpu_base_addr;
+ addr -= encoder->percpu.base_addr;
- if (!percpu_var_exists(addr, &size, &name))
+ if (!btf_encoder__percpu_var_exists(encoder, addr, &size, &name))
continue; /* not a per-CPU variable */
/* A lot of "special" DWARF variables (e.g, __UNIQUE_ID___xxx)
@@ -808,7 +1239,6 @@ int cu__encode_btf(struct cu *cu, int verbose, bool force,
* per-CPU symbols have non-zero values.
*/
if (var->ip.addr == 0) {
- dwarf_name = variable__name(var, cu);
if (!dwarf_name || strcmp(dwarf_name, name))
continue;
}
@@ -819,47 +1249,283 @@ int cu__encode_btf(struct cu *cu, int verbose, bool force,
if (var->ip.tag.type == 0) {
fprintf(stderr, "error: found variable '%s' in CU '%s' that has void type\n",
name, cu->name);
- if (force)
+ if (encoder->force)
continue;
err = -1;
break;
}
+ tag = cu__type(cu, var->ip.tag.type);
+ if (tag__size(tag, cu) == 0) {
+ if (encoder->verbose)
+ fprintf(stderr, "Ignoring zero-sized per-CPU variable '%s'...\n", dwarf_name ?: "<missing name>");
+ continue;
+ }
+
type = var->ip.tag.type + type_id_off;
linkage = var->external ? BTF_VAR_GLOBAL_ALLOCATED : BTF_VAR_STATIC;
- if (btf_elf__verbose) {
+ if (encoder->verbose) {
printf("Variable '%s' from CU '%s' at address 0x%" PRIx64 " encoded\n",
name, cu->name, addr);
}
- /* add a BTF_KIND_VAR in btfe->types */
- id = btf_elf__add_var_type(btfe, type, name, linkage);
+ /* add a BTF_KIND_VAR in encoder->types */
+ id = btf_encoder__add_var(encoder, type, name, linkage);
if (id < 0) {
- err = -1;
fprintf(stderr, "error: failed to encode variable '%s' at addr 0x%" PRIx64 "\n",
name, addr);
- break;
+ goto out;
+ }
+
+ list_for_each_entry(annot, &var->annots, node) {
+ int tag_type_id = btf_encoder__add_decl_tag(encoder, annot->value, id, annot->component_idx);
+ if (tag_type_id < 0) {
+ fprintf(stderr, "error: failed to encode tag '%s' to variable '%s' with component_idx %d\n",
+ annot->value, name, annot->component_idx);
+ goto out;
+ }
}
/*
- * add a BTF_VAR_SECINFO in btfe->percpu_secinfo, which will be added into
- * btfe->types later when we add BTF_VAR_DATASEC.
+ * add a BTF_VAR_SECINFO in encoder->percpu_secinfo, which will be added into
+ * encoder->types later when we add BTF_VAR_DATASEC.
*/
- id = btf_elf__add_var_secinfo(&btfe->percpu_secinfo, id, addr, size);
+ id = btf_encoder__add_var_secinfo(encoder, id, addr, size);
if (id < 0) {
- err = -1;
fprintf(stderr, "error: failed to encode section info for variable '%s' at addr 0x%" PRIx64 "\n",
name, addr);
- break;
+ goto out;
}
}
+ err = 0;
out:
- if (err) {
- delete_functions();
- btf_elf__delete(btfe);
- btfe = NULL;
+ return err;
+}
+
+struct btf_encoder *btf_encoder__new(struct cu *cu, const char *detached_filename, struct btf *base_btf, bool skip_encoding_vars, bool force, bool gen_floats, bool verbose)
+{
+ struct btf_encoder *encoder = zalloc(sizeof(*encoder));
+
+ if (encoder) {
+ encoder->raw_output = detached_filename != NULL;
+ encoder->filename = strdup(encoder->raw_output ? detached_filename : cu->filename);
+ if (encoder->filename == NULL)
+ goto out_delete;
+
+ encoder->btf = btf__new_empty_split(base_btf);
+ if (encoder->btf == NULL)
+ goto out_delete;
+
+ encoder->force = force;
+ encoder->gen_floats = gen_floats;
+ encoder->skip_encoding_vars = skip_encoding_vars;
+ encoder->verbose = verbose;
+ encoder->has_index_type = false;
+ encoder->need_index_type = false;
+ encoder->array_index_id = 0;
+
+ GElf_Ehdr ehdr;
+
+ if (gelf_getehdr(cu->elf, &ehdr) == NULL) {
+ if (encoder->verbose)
+ elf_error("cannot get ELF header");
+ goto out_delete;
+ }
+
+ encoder->is_rel = ehdr.e_type == ET_REL;
+
+ switch (ehdr.e_ident[EI_DATA]) {
+ case ELFDATA2LSB:
+ btf__set_endianness(encoder->btf, BTF_LITTLE_ENDIAN);
+ break;
+ case ELFDATA2MSB:
+ btf__set_endianness(encoder->btf, BTF_BIG_ENDIAN);
+ break;
+ default:
+ fprintf(stderr, "%s: unknown ELF endianness.\n", __func__);
+ goto out_delete;
+ }
+
+ encoder->symtab = elf_symtab__new(NULL, cu->elf);
+ if (!encoder->symtab) {
+ if (encoder->verbose)
+ printf("%s: '%s' doesn't have symtab.\n", __func__, cu->filename);
+ goto out;
+ }
+
+ /* find percpu section's shndx */
+
+ GElf_Shdr shdr;
+ Elf_Scn *sec = elf_section_by_name(cu->elf, &shdr, PERCPU_SECTION, NULL);
+
+ if (!sec) {
+ if (encoder->verbose)
+ printf("%s: '%s' doesn't have '%s' section\n", __func__, cu->filename, PERCPU_SECTION);
+ } else {
+ encoder->percpu.shndx = elf_ndxscn(sec);
+ encoder->percpu.base_addr = shdr.sh_addr;
+ encoder->percpu.sec_sz = shdr.sh_size;
+ }
+
+ if (btf_encoder__collect_symbols(encoder, !encoder->skip_encoding_vars))
+ goto out_delete;
+
+ if (encoder->verbose)
+ printf("File %s:\n", cu->filename);
+ }
+out:
+ return encoder;
+
+out_delete:
+ btf_encoder__delete(encoder);
+ return NULL;
+}
+
+void btf_encoder__delete(struct btf_encoder *encoder)
+{
+ if (encoder == NULL)
+ return;
+
+ __gobuffer__delete(&encoder->percpu_secinfo);
+ zfree(&encoder->filename);
+ btf__free(encoder->btf);
+ encoder->btf = NULL;
+ elf_symtab__delete(encoder->symtab);
+
+ encoder->functions.allocated = encoder->functions.cnt = 0;
+ free(encoder->functions.entries);
+ encoder->functions.entries = NULL;
+
+ free(encoder);
+}
+
+int btf_encoder__encode_cu(struct btf_encoder *encoder, struct cu *cu)
+{
+ uint32_t type_id_off = btf__get_nr_types(encoder->btf);
+ struct llvm_annotation *annot;
+ int btf_type_id, tag_type_id;
+ uint32_t core_id;
+ struct function *fn;
+ struct tag *pos;
+ int err = 0;
+
+
+ if (!encoder->has_index_type) {
+ /* cu__find_base_type_by_name() takes "type_id_t *id" */
+ type_id_t id;
+ if (cu__find_base_type_by_name(cu, "int", &id)) {
+ encoder->has_index_type = true;
+ encoder->array_index_id = type_id_off + id;
+ } else {
+ encoder->has_index_type = false;
+ encoder->array_index_id = type_id_off + cu->types_table.nr_entries;
+ }
+ }
+
+ cu__for_each_type(cu, core_id, pos) {
+ btf_type_id = btf_encoder__encode_tag(encoder, pos, type_id_off);
+
+ if (btf_type_id < 0 ||
+ tag__check_id_drift(pos, core_id, btf_type_id, type_id_off)) {
+ err = -1;
+ goto out;
+ }
+ }
+
+ if (encoder->need_index_type && !encoder->has_index_type) {
+ struct base_type bt = {};
+
+ bt.name = 0;
+ bt.bit_size = 32;
+ btf_encoder__add_base_type(encoder, &bt, "__ARRAY_SIZE_TYPE__");
+ encoder->has_index_type = true;
+ }
+
+ cu__for_each_type(cu, core_id, pos) {
+ struct namespace *ns;
+ const char *tag_name;
+
+ switch (pos->tag) {
+ case DW_TAG_structure_type:
+ tag_name = "struct";
+ break;
+ case DW_TAG_union_type:
+ tag_name = "union";
+ break;
+ case DW_TAG_typedef:
+ tag_name = "typedef";
+ break;
+ default:
+ continue;
+ }
+
+ btf_type_id = type_id_off + core_id;
+ ns = tag__namespace(pos);
+ list_for_each_entry(annot, &ns->annots, node) {
+ tag_type_id = btf_encoder__add_decl_tag(encoder, annot->value, btf_type_id, annot->component_idx);
+ if (tag_type_id < 0) {
+ fprintf(stderr, "error: failed to encode tag '%s' to %s '%s' with component_idx %d\n",
+ annot->value, tag_name, namespace__name(ns), annot->component_idx);
+ goto out;
+ }
+ }
+ }
+
+ cu__for_each_function(cu, core_id, fn) {
+ int btf_fnproto_id, btf_fn_id;
+ const char *name;
+
+ /*
+ * Skip functions that:
+ * - are marked as declarations
+ * - do not have full argument names
+ * - are not in ftrace list (if it's available)
+ * - are not external (in case ftrace filter is not available)
+ */
+ if (fn->declaration)
+ continue;
+ if (!ftype__has_arg_names(&fn->proto))
+ continue;
+ if (encoder->functions.cnt) {
+ struct elf_function *func;
+ const char *name;
+
+ name = function__name(fn);
+ if (!name)
+ continue;
+
+ func = btf_encoder__find_function(encoder, name);
+ if (!func || func->generated)
+ continue;
+ func->generated = true;
+ } else {
+ if (!fn->external)
+ continue;
+ }
+
+ btf_fnproto_id = btf_encoder__add_func_proto(encoder, &fn->proto, type_id_off);
+ name = function__name(fn);
+ btf_fn_id = btf_encoder__add_ref_type(encoder, BTF_KIND_FUNC, btf_fnproto_id, name, false);
+ if (btf_fnproto_id < 0 || btf_fn_id < 0) {
+ err = -1;
+ printf("error: failed to encode function '%s'\n", function__name(fn));
+ goto out;
+ }
+
+ list_for_each_entry(annot, &fn->annots, node) {
+ tag_type_id = btf_encoder__add_decl_tag(encoder, annot->value, btf_fn_id, annot->component_idx);
+ if (tag_type_id < 0) {
+ fprintf(stderr, "error: failed to encode tag '%s' to func %s with component_idx %d\n",
+ annot->value, name, annot->component_idx);
+ goto out;
+ }
+ }
}
+
+ if (!encoder->skip_encoding_vars)
+ err = btf_encoder__encode_cu_variables(encoder, cu, type_id_off);
+out:
return err;
}
diff --git a/btf_encoder.h b/btf_encoder.h
index 46fb231..f133b0d 100644
--- a/btf_encoder.h
+++ b/btf_encoder.h
@@ -9,11 +9,24 @@
Copyright (C) Arnaldo Carvalho de Melo <acme@redhat.com>
*/
+#include <stdbool.h>
+
+struct btf_encoder;
+struct btf;
struct cu;
+struct list_head;
+
+struct btf_encoder *btf_encoder__new(struct cu *cu, const char *detached_filename, struct btf *base_btf, bool skip_encoding_vars, bool force, bool gen_floats, bool verbose);
+void btf_encoder__delete(struct btf_encoder *encoder);
+
+int btf_encoder__encode(struct btf_encoder *encoder);
+
+int btf_encoder__encode_cu(struct btf_encoder *encoder, struct cu *cu);
+
+void btf_encoders__add(struct list_head *encoders, struct btf_encoder *encoder);
-int btf_encoder__encode();
+struct btf_encoder *btf_encoders__first(struct list_head *encoders);
-int cu__encode_btf(struct cu *cu, int verbose, bool force,
- bool skip_encoding_vars);
+struct btf_encoder *btf_encoders__next(struct btf_encoder *encoder);
#endif /* _BTF_ENCODER_H_ */
diff --git a/btf_loader.c b/btf_loader.c
index ec286f4..7a5b16f 100644
--- a/btf_loader.c
+++ b/btf_loader.c
@@ -20,20 +20,20 @@
#include <string.h>
#include <limits.h>
#include <libgen.h>
+#include <linux/btf.h>
+#include <bpf/btf.h>
+#include <bpf/libbpf.h>
#include <zlib.h>
#include <gelf.h>
-#include "libbtf.h"
-#include "lib/bpf/include/uapi/linux/btf.h"
#include "dutil.h"
#include "dwarves.h"
-/*
- * FIXME: We should just get the table from the BTF ELF section
- * and use it directly
- */
-extern struct strings *strings;
+static const char *cu__btf_str(struct cu *cu, uint32_t offset)
+{
+ return offset ? btf__str_by_offset(cu->priv, offset) : NULL;
+}
static void *tag__alloc(const size_t size)
{
@@ -45,8 +45,7 @@ static void *tag__alloc(const size_t size)
return tag;
}
-static int btf_elf__load_ftype(struct btf_elf *btfe, struct ftype *proto, uint32_t tag,
- const struct btf_type *tp, uint32_t id)
+static int cu__load_ftype(struct cu *cu, struct ftype *proto, uint32_t tag, const struct btf_type *tp, uint32_t id)
{
const struct btf_param *param = btf_params(tp);
int i, vlen = btf_vlen(tp);
@@ -65,20 +64,20 @@ static int btf_elf__load_ftype(struct btf_elf *btfe, struct ftype *proto, uint32
goto out_free_parameters;
p->tag.tag = DW_TAG_formal_parameter;
p->tag.type = param->type;
- p->name = param->name_off;
+ p->name = cu__btf_str(cu, param->name_off);
ftype__add_parameter(proto, p);
}
}
- cu__add_tag_with_id(btfe->priv, &proto->tag, id);
+ cu__add_tag_with_id(cu, &proto->tag, id);
return 0;
out_free_parameters:
- ftype__delete(proto, btfe->priv);
+ ftype__delete(proto);
return -ENOMEM;
}
-static int create_new_function(struct btf_elf *btfe, const struct btf_type *tp, uint32_t id)
+static int create_new_function(struct cu *cu, const struct btf_type *tp, uint32_t id)
{
struct function *func = tag__alloc(sizeof(*func));
@@ -90,14 +89,14 @@ static int create_new_function(struct btf_elf *btfe, const struct btf_type *tp,
func->btf = 1;
func->proto.tag.tag = DW_TAG_subprogram;
func->proto.tag.type = tp->type;
- func->name = tp->name_off;
+ func->name = cu__btf_str(cu, tp->name_off);
INIT_LIST_HEAD(&func->lexblock.tags);
- cu__add_tag_with_id(btfe->priv, &func->proto.tag, id);
+ cu__add_tag_with_id(cu, &func->proto.tag, id);
return 0;
}
-static struct base_type *base_type__new(strings_t name, uint32_t attrs,
+static struct base_type *base_type__new(const char *name, uint32_t attrs,
uint8_t float_type, size_t size)
{
struct base_type *bt = tag__alloc(sizeof(*bt));
@@ -113,18 +112,16 @@ static struct base_type *base_type__new(strings_t name, uint32_t attrs,
return bt;
}
-static void type__init(struct type *type, uint32_t tag,
- strings_t name, size_t size)
+static void type__init(struct type *type, uint32_t tag, const char *name, size_t size)
{
__type__init(type);
INIT_LIST_HEAD(&type->namespace.tags);
type->size = size;
type->namespace.tag.tag = tag;
type->namespace.name = name;
- type->namespace.sname = 0;
}
-static struct type *type__new(uint16_t tag, strings_t name, size_t size)
+static struct type *type__new(uint16_t tag, const char *name, size_t size)
{
struct type *type = tag__alloc(sizeof(*type));
@@ -134,7 +131,7 @@ static struct type *type__new(uint16_t tag, strings_t name, size_t size)
return type;
}
-static struct class *class__new(strings_t name, size_t size, bool is_union)
+static struct class *class__new(const char *name, size_t size, bool is_union)
{
struct class *class = tag__alloc(sizeof(*class));
uint32_t tag = is_union ? DW_TAG_union_type : DW_TAG_structure_type;
@@ -147,7 +144,7 @@ static struct class *class__new(strings_t name, size_t size, bool is_union)
return class;
}
-static struct variable *variable__new(strings_t name, uint32_t linkage)
+static struct variable *variable__new(const char *name, uint32_t linkage)
{
struct variable *var = tag__alloc(sizeof(*var));
@@ -160,22 +157,36 @@ static struct variable *variable__new(strings_t name, uint32_t linkage)
return var;
}
-static int create_new_base_type(struct btf_elf *btfe, const struct btf_type *tp, uint32_t id)
+static int create_new_int_type(struct cu *cu, const struct btf_type *tp, uint32_t id)
{
uint32_t attrs = btf_int_encoding(tp);
- strings_t name = tp->name_off;
+ const char *name = cu__btf_str(cu, tp->name_off);
struct base_type *base = base_type__new(name, attrs, 0, btf_int_bits(tp));
if (base == NULL)
return -ENOMEM;
base->tag.tag = DW_TAG_base_type;
- cu__add_tag_with_id(btfe->priv, &base->tag, id);
+ cu__add_tag_with_id(cu, &base->tag, id);
return 0;
}
-static int create_new_array(struct btf_elf *btfe, const struct btf_type *tp, uint32_t id)
+static int create_new_float_type(struct cu *cu, const struct btf_type *tp, uint32_t id)
+{
+ const char *name = cu__btf_str(cu, tp->name_off);
+ struct base_type *base = base_type__new(name, 0, BT_FP_SINGLE, tp->size * 8);
+
+ if (base == NULL)
+ return -ENOMEM;
+
+ base->tag.tag = DW_TAG_base_type;
+ cu__add_tag_with_id(cu, &base->tag, id);
+
+ return 0;
+}
+
+static int create_new_array(struct cu *cu, const struct btf_type *tp, uint32_t id)
{
struct btf_array *ap = btf_array(tp);
struct array_type *array = tag__alloc(sizeof(*array));
@@ -197,13 +208,12 @@ static int create_new_array(struct btf_elf *btfe, const struct btf_type *tp, uin
array->tag.tag = DW_TAG_array_type;
array->tag.type = ap->type;
- cu__add_tag_with_id(btfe->priv, &array->tag, id);
+ cu__add_tag_with_id(cu, &array->tag, id);
return 0;
}
-static int create_members(struct btf_elf *btfe, const struct btf_type *tp,
- struct type *class)
+static int create_members(struct cu *cu, const struct btf_type *tp, struct type *class)
{
struct btf_member *mp = btf_members(tp);
int i, vlen = btf_vlen(tp);
@@ -216,7 +226,7 @@ static int create_members(struct btf_elf *btfe, const struct btf_type *tp,
member->tag.tag = DW_TAG_member;
member->tag.type = mp[i].type;
- member->name = mp[i].name_off;
+ member->name = cu__btf_str(cu, mp[i].name_off);
member->bit_offset = btf_member_bit_offset(tp, i);
member->bitfield_size = btf_member_bitfield_size(tp, i);
member->byte_offset = member->bit_offset / 8;
@@ -227,39 +237,39 @@ static int create_members(struct btf_elf *btfe, const struct btf_type *tp,
return 0;
}
-static int create_new_class(struct btf_elf *btfe, const struct btf_type *tp, uint32_t id)
+static int create_new_class(struct cu *cu, const struct btf_type *tp, uint32_t id)
{
- struct class *class = class__new(tp->name_off, tp->size, false);
- int member_size = create_members(btfe, tp, &class->type);
+ struct class *class = class__new(cu__btf_str(cu, tp->name_off), tp->size, false);
+ int member_size = create_members(cu, tp, &class->type);
if (member_size < 0)
goto out_free;
- cu__add_tag_with_id(btfe->priv, &class->type.namespace.tag, id);
+ cu__add_tag_with_id(cu, &class->type.namespace.tag, id);
return 0;
out_free:
- class__delete(class, btfe->priv);
+ class__delete(class);
return -ENOMEM;
}
-static int create_new_union(struct btf_elf *btfe, const struct btf_type *tp, uint32_t id)
+static int create_new_union(struct cu *cu, const struct btf_type *tp, uint32_t id)
{
- struct type *un = type__new(DW_TAG_union_type, tp->name_off, tp->size);
- int member_size = create_members(btfe, tp, un);
+ struct type *un = type__new(DW_TAG_union_type, cu__btf_str(cu, tp->name_off), tp->size);
+ int member_size = create_members(cu, tp, un);
if (member_size < 0)
goto out_free;
- cu__add_tag_with_id(btfe->priv, &un->namespace.tag, id);
+ cu__add_tag_with_id(cu, &un->namespace.tag, id);
return 0;
out_free:
- type__delete(un, btfe->priv);
+ type__delete(un);
return -ENOMEM;
}
-static struct enumerator *enumerator__new(strings_t name, uint32_t value)
+static struct enumerator *enumerator__new(const char *name, uint32_t value)
{
struct enumerator *en = tag__alloc(sizeof(*en));
@@ -272,19 +282,19 @@ static struct enumerator *enumerator__new(strings_t name, uint32_t value)
return en;
}
-static int create_new_enumeration(struct btf_elf *btfe, const struct btf_type *tp, uint32_t id)
+static int create_new_enumeration(struct cu *cu, const struct btf_type *tp, uint32_t id)
{
struct btf_enum *ep = btf_enum(tp);
uint16_t i, vlen = btf_vlen(tp);
struct type *enumeration = type__new(DW_TAG_enumeration_type,
- tp->name_off,
+ cu__btf_str(cu, tp->name_off),
tp->size ? tp->size * 8 : (sizeof(int) * 8));
if (enumeration == NULL)
return -ENOMEM;
for (i = 0; i < vlen; i++) {
- strings_t name = ep[i].name_off;
+ const char *name = cu__btf_str(cu, ep[i].name_off);
uint32_t value = ep[i].val;
struct enumerator *enumerator = enumerator__new(name, value);
@@ -294,66 +304,64 @@ static int create_new_enumeration(struct btf_elf *btfe, const struct btf_type *t
enumeration__add(enumeration, enumerator);
}
- cu__add_tag_with_id(btfe->priv, &enumeration->namespace.tag, id);
+ cu__add_tag_with_id(cu, &enumeration->namespace.tag, id);
return 0;
out_free:
- enumeration__delete(enumeration, btfe->priv);
+ enumeration__delete(enumeration);
return -ENOMEM;
}
-static int create_new_subroutine_type(struct btf_elf *btfe, const struct btf_type *tp, uint32_t id)
+static int create_new_subroutine_type(struct cu *cu, const struct btf_type *tp, uint32_t id)
{
struct ftype *proto = tag__alloc(sizeof(*proto));
if (proto == NULL)
return -ENOMEM;
- return btf_elf__load_ftype(btfe, proto, DW_TAG_subroutine_type, tp, id);
+ return cu__load_ftype(cu, proto, DW_TAG_subroutine_type, tp, id);
}
-static int create_new_forward_decl(struct btf_elf *btfe, const struct btf_type *tp, uint32_t id)
+static int create_new_forward_decl(struct cu *cu, const struct btf_type *tp, uint32_t id)
{
- struct class *fwd = class__new(tp->name_off, 0, btf_kflag(tp));
+ struct class *fwd = class__new(cu__btf_str(cu, tp->name_off), 0, btf_kflag(tp));
if (fwd == NULL)
return -ENOMEM;
fwd->type.declaration = 1;
- cu__add_tag_with_id(btfe->priv, &fwd->type.namespace.tag, id);
+ cu__add_tag_with_id(cu, &fwd->type.namespace.tag, id);
return 0;
}
-static int create_new_typedef(struct btf_elf *btfe, const struct btf_type *tp, uint32_t id)
+static int create_new_typedef(struct cu *cu, const struct btf_type *tp, uint32_t id)
{
- struct type *type = type__new(DW_TAG_typedef, tp->name_off, 0);
+ struct type *type = type__new(DW_TAG_typedef, cu__btf_str(cu, tp->name_off), 0);
if (type == NULL)
return -ENOMEM;
type->namespace.tag.type = tp->type;
- cu__add_tag_with_id(btfe->priv, &type->namespace.tag, id);
+ cu__add_tag_with_id(cu, &type->namespace.tag, id);
return 0;
}
-static int create_new_variable(struct btf_elf *btfe, const struct btf_type *tp, uint32_t id)
+static int create_new_variable(struct cu *cu, const struct btf_type *tp, uint32_t id)
{
struct btf_var *bvar = btf_var(tp);
- struct variable *var = variable__new(tp->name_off, bvar->linkage);
+ struct variable *var = variable__new(cu__btf_str(cu, tp->name_off), bvar->linkage);
if (var == NULL)
return -ENOMEM;
var->ip.tag.type = tp->type;
- cu__add_tag_with_id(btfe->priv, &var->ip.tag, id);
+ cu__add_tag_with_id(cu, &var->ip.tag, id);
return 0;
}
-static int create_new_datasec(struct btf_elf *btfe, const struct btf_type *tp, uint32_t id)
+static int create_new_datasec(struct cu *cu __maybe_unused, const struct btf_type *tp __maybe_unused, uint32_t id __maybe_unused)
{
- //strings_t name = btf_elf__get32(btfe, &tp->name_off);
-
- //cu__add_tag_with_id(btfe->priv, &datasec->tag, id);
+ //cu__add_tag_with_id(cu, &datasec->tag, id);
/*
* FIXME: this will not be used to reconstruct some original C code,
@@ -362,7 +370,7 @@ static int create_new_datasec(struct btf_elf *btfe, const struct btf_type *tp, u
return 0;
}
-static int create_new_tag(struct btf_elf *btfe, int type, const struct btf_type *tp, uint32_t id)
+static int create_new_tag(struct cu *cu, int type, const struct btf_type *tp, uint32_t id)
{
struct tag *tag = zalloc(sizeof(*tag));
@@ -381,66 +389,69 @@ static int create_new_tag(struct btf_elf *btfe, int type, const struct btf_type
}
tag->type = tp->type;
- cu__add_tag_with_id(btfe->priv, tag, id);
+ cu__add_tag_with_id(cu, tag, id);
return 0;
}
-static int btf_elf__load_types(struct btf_elf *btfe)
+static int btf__load_types(struct btf *btf, struct cu *cu)
{
uint32_t type_index;
int err;
- for (type_index = 1; type_index <= btf__get_nr_types(btfe->btf); type_index++) {
- const struct btf_type *type_ptr = btf__type_by_id(btfe->btf, type_index);
+ for (type_index = 1; type_index <= btf__get_nr_types(btf); type_index++) {
+ const struct btf_type *type_ptr = btf__type_by_id(btf, type_index);
uint32_t type = btf_kind(type_ptr);
switch (type) {
case BTF_KIND_INT:
- err = create_new_base_type(btfe, type_ptr, type_index);
+ err = create_new_int_type(cu, type_ptr, type_index);
break;
case BTF_KIND_ARRAY:
- err = create_new_array(btfe, type_ptr, type_index);
+ err = create_new_array(cu, type_ptr, type_index);
break;
case BTF_KIND_STRUCT:
- err = create_new_class(btfe, type_ptr, type_index);
+ err = create_new_class(cu, type_ptr, type_index);
break;
case BTF_KIND_UNION:
- err = create_new_union(btfe, type_ptr, type_index);
+ err = create_new_union(cu, type_ptr, type_index);
break;
case BTF_KIND_ENUM:
- err = create_new_enumeration(btfe, type_ptr, type_index);
+ err = create_new_enumeration(cu, type_ptr, type_index);
break;
case BTF_KIND_FWD:
- err = create_new_forward_decl(btfe, type_ptr, type_index);
+ err = create_new_forward_decl(cu, type_ptr, type_index);
break;
case BTF_KIND_TYPEDEF:
- err = create_new_typedef(btfe, type_ptr, type_index);
+ err = create_new_typedef(cu, type_ptr, type_index);
break;
case BTF_KIND_VAR:
- err = create_new_variable(btfe, type_ptr, type_index);
+ err = create_new_variable(cu, type_ptr, type_index);
break;
case BTF_KIND_DATASEC:
- err = create_new_datasec(btfe, type_ptr, type_index);
+ err = create_new_datasec(cu, type_ptr, type_index);
break;
case BTF_KIND_VOLATILE:
case BTF_KIND_PTR:
case BTF_KIND_CONST:
case BTF_KIND_RESTRICT:
- err = create_new_tag(btfe, type, type_ptr, type_index);
+ err = create_new_tag(cu, type, type_ptr, type_index);
break;
case BTF_KIND_UNKN:
- cu__table_nullify_type_entry(btfe->priv, type_index);
+ cu__table_nullify_type_entry(cu, type_index);
fprintf(stderr, "BTF: idx: %d, Unknown kind %d\n", type_index, type);
fflush(stderr);
err = 0;
break;
case BTF_KIND_FUNC_PROTO:
- err = create_new_subroutine_type(btfe, type_ptr, type_index);
+ err = create_new_subroutine_type(cu, type_ptr, type_index);
break;
case BTF_KIND_FUNC:
// BTF_KIND_FUNC corresponding to a defined subprogram.
- err = create_new_function(btfe, type_ptr, type_index);
+ err = create_new_function(cu, type_ptr, type_index);
+ break;
+ case BTF_KIND_FLOAT:
+ err = create_new_float_type(cu, type_ptr, type_index);
break;
default:
fprintf(stderr, "BTF: idx: %d, Unknown kind %d\n", type_index, type);
@@ -455,15 +466,53 @@ static int btf_elf__load_types(struct btf_elf *btfe)
return 0;
}
-static int btf_elf__load_sections(struct btf_elf *btfe)
+static int btf__load_sections(struct btf *btf, struct cu *cu)
{
- return btf_elf__load_types(btfe);
+ return btf__load_types(btf, cu);
}
-static int class__fixup_btf_bitfields(struct tag *tag, struct cu *cu, struct btf_elf *btfe)
+static uint32_t class__infer_alignment(const struct conf_load *conf,
+ uint32_t byte_offset,
+ uint32_t natural_alignment,
+ uint32_t smallest_offset)
+{
+ uint16_t cacheline_size = conf->conf_fprintf->cacheline_size;
+ uint32_t alignment = 0;
+ uint32_t offset_delta = byte_offset - smallest_offset;
+
+ if (offset_delta) {
+ if (byte_offset % 2 == 0) {
+ /* Find the power of 2 immediately higher than
+ * offset_delta
+ */
+ alignment = 1 << (8 * sizeof(offset_delta) -
+ __builtin_clz(offset_delta));
+ } else {
+ alignment = 0;
+ }
+ }
+
+ /* Natural alignment, nothing to do */
+ if (alignment <= natural_alignment || alignment == 1)
+ alignment = 0;
+ /* If the offset is compatible with being aligned on the cacheline size
+ * and this would only result in increasing the alignment, use the
+ * cacheline size as it is safe and quite likely to be what was in the
+ * source.
+ */
+ else if (alignment < cacheline_size &&
+ cacheline_size % alignment == 0 &&
+ byte_offset % cacheline_size == 0)
+ alignment = cacheline_size;
+
+ return alignment;
+}
+
+static int class__fixup_btf_bitfields(const struct conf_load *conf, struct tag *tag, struct cu *cu)
{
struct class_member *pos;
struct type *tag_type = tag__type(tag);
+ uint32_t smallest_offset = 0;
type__for_each_data_member(tag_type, pos) {
struct tag *type = tag__strip_typedefs_and_modifiers(&pos->tag, cu);
@@ -475,42 +524,52 @@ static int class__fixup_btf_bitfields(struct tag *tag, struct cu *cu, struct btf
pos->byte_size = tag__size(type, cu);
pos->bit_size = pos->byte_size * 8;
- /* bitfield fixup is needed for enums and base types only */
- if (type->tag != DW_TAG_base_type && type->tag != DW_TAG_enumeration_type)
- continue;
-
/* if BTF data is incorrect and has size == 0, skip field,
* instead of crashing */
if (pos->byte_size == 0) {
continue;
}
- if (pos->bitfield_size) {
- /* bitfields seem to be always aligned, no matter the packing */
- pos->byte_offset = pos->bit_offset / pos->bit_size * pos->bit_size / 8;
- pos->bitfield_offset = pos->bit_offset - pos->byte_offset * 8;
- /* re-adjust bitfield offset if it is negative */
- if (pos->bitfield_offset < 0) {
- pos->bitfield_offset += pos->bit_size;
- pos->byte_offset -= pos->byte_size;
- pos->bit_offset = pos->byte_offset * 8 + pos->bitfield_offset;
+ /* bitfield fixup is needed for enums and base types only */
+ if (type->tag == DW_TAG_base_type || type->tag == DW_TAG_enumeration_type) {
+ if (pos->bitfield_size) {
+ /* bitfields seem to be always aligned, no matter the packing */
+ pos->byte_offset = pos->bit_offset / pos->bit_size * pos->bit_size / 8;
+ pos->bitfield_offset = pos->bit_offset - pos->byte_offset * 8;
+ /* re-adjust bitfield offset if it is negative */
+ if (pos->bitfield_offset < 0) {
+ pos->bitfield_offset += pos->bit_size;
+ pos->byte_offset -= pos->byte_size;
+ pos->bit_offset = pos->byte_offset * 8 + pos->bitfield_offset;
+ }
+ } else {
+ pos->byte_offset = pos->bit_offset / 8;
}
- } else {
- pos->byte_offset = pos->bit_offset / 8;
}
+
+ pos->alignment = class__infer_alignment(conf,
+ pos->byte_offset,
+ tag__natural_alignment(type, cu),
+ smallest_offset);
+ smallest_offset = pos->byte_offset + pos->byte_size;
}
+ tag_type->alignment = class__infer_alignment(conf,
+ tag_type->size,
+ tag__natural_alignment(tag, cu),
+ smallest_offset);
+
return 0;
}
-static int cu__fixup_btf_bitfields(struct cu *cu, struct btf_elf *btfe)
+static int cu__fixup_btf_bitfields(const struct conf_load *conf, struct cu *cu)
{
int err = 0;
struct tag *pos;
list_for_each_entry(pos, &cu->tags, node)
if (tag__is_struct(pos) || tag__is_union(pos)) {
- err = class__fixup_btf_bitfields(pos, cu, btfe);
+ err = class__fixup_btf_bitfields(conf, pos, cu);
if (err)
break;
}
@@ -518,48 +577,49 @@ static int cu__fixup_btf_bitfields(struct cu *cu, struct btf_elf *btfe)
return err;
}
-static void btf_elf__cu_delete(struct cu *cu)
+static void btf__cu_delete(struct cu *cu)
{
- btf_elf__delete(cu->priv);
+ btf__free(cu->priv);
cu->priv = NULL;
}
-static const char *btf_elf__strings_ptr(const struct cu *cu, strings_t s)
+static int libbpf_log(enum libbpf_print_level level __maybe_unused, const char *format, va_list args)
{
- return btf_elf__string(cu->priv, s);
+ return vfprintf(stderr, format, args);
}
-struct debug_fmt_ops btf_elf__ops;
+struct debug_fmt_ops btf__ops;
-int btf_elf__load_file(struct cus *cus, struct conf_load *conf, const char *filename)
+static int cus__load_btf(struct cus *cus, struct conf_load *conf, const char *filename)
{
- int err;
- struct btf_elf *btfe = btf_elf__new(filename, NULL, base_btf);
-
- if (btfe == NULL)
- return -1;
+ int err = -1;
- struct cu *cu = cu__new(filename, btfe->wordsize, NULL, 0, filename);
+ // Pass a zero for addr_size, we'll get it after we load via btf__pointer_size()
+ struct cu *cu = cu__new(filename, 0, NULL, 0, filename, false);
if (cu == NULL)
return -1;
cu->language = LANG_C;
cu->uses_global_strings = false;
- cu->little_endian = !btfe->is_big_endian;
- cu->dfops = &btf_elf__ops;
- cu->priv = btfe;
- btfe->priv = cu;
- if (btf_elf__load(btfe) != 0)
- return -1;
+ cu->dfops = &btf__ops;
- err = btf_elf__load_sections(btfe);
+ libbpf_set_print(libbpf_log);
- if (err != 0) {
- cu__delete(cu);
- return err;
- }
+ struct btf *btf = btf__parse_split(filename, conf->base_btf);
+
+ err = libbpf_get_error(btf);
+ if (err)
+ goto out_free;
+
+ cu->priv = btf;
+ cu->little_endian = btf__endianness(btf) == BTF_LITTLE_ENDIAN;
+ cu->addr_size = btf__pointer_size(btf);
- err = cu__fixup_btf_bitfields(cu, btfe);
+ err = btf__load_sections(btf, cu);
+ if (err != 0)
+ goto out_free;
+
+ err = cu__fixup_btf_bitfields(conf, cu);
/*
* The app stole this cu, possibly deleting it,
* so forget about it
@@ -569,11 +629,14 @@ int btf_elf__load_file(struct cus *cus, struct conf_load *conf, const char *file
cus__add(cus, cu);
return err;
+
+out_free:
+ cu__delete(cu); // will call btf__free(cu->priv);
+ return err;
}
-struct debug_fmt_ops btf_elf__ops = {
+struct debug_fmt_ops btf__ops = {
.name = "btf",
- .load_file = btf_elf__load_file,
- .strings__ptr = btf_elf__strings_ptr,
- .cu__delete = btf_elf__cu_delete,
+ .load_file = cus__load_btf,
+ .cu__delete = btf__cu_delete,
};
diff --git a/btfdiff b/btfdiff
index 4db7032..cbdf652 100755
--- a/btfdiff
+++ b/btfdiff
@@ -8,24 +8,34 @@
# this information is not available when loading from BTF.
if [ $# -eq 0 ] ; then
- echo "Usage: btfdiff <filename_with_BTF_and_DWARF_info>"
+ echo "Usage: btfdiff <filename_with_DWARF_and_maybe_BTF_info> [<filename_with_BTF_info>]"
exit 1
fi
-file=$1
+dwarf_input=$1
+btf_input=$dwarf_input
+
+if [ $# -eq 2 ] ; then
+ btf_input=$2
+fi
+
btf_output=$(mktemp /tmp/btfdiff.btf.XXXXXX)
dwarf_output=$(mktemp /tmp/btfdiff.dwarf.XXXXXX)
pahole_bin=${PAHOLE-"pahole"}
${pahole_bin} -F dwarf \
--flat_arrays \
+ --sort \
+ --jobs \
--suppress_aligned_attribute \
--suppress_force_paddings \
--suppress_packed \
- --show_private_classes $file > $dwarf_output
+ --show_private_classes $dwarf_input > $dwarf_output
${pahole_bin} -F btf \
+ --sort \
+ --suppress_aligned_attribute \
--suppress_packed \
- $file > $btf_output
+ $btf_input > $btf_output
diff -up $dwarf_output $btf_output
diff --git a/buildcmd.sh b/buildcmd.sh
new file mode 100755
index 0000000..5a15d4b
--- /dev/null
+++ b/buildcmd.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+mkdir build
+cd build
+cmake -DCMAKE_BUILD_TYPE=Release ..
+cd ..
+make -j $(getconf _NPROCESSORS_ONLN) -C build
diff --git a/changes-v1.20 b/changes-v1.20
new file mode 100644
index 0000000..0dddfda
--- /dev/null
+++ b/changes-v1.20
@@ -0,0 +1,66 @@
+BTF encoder:
+
+ - Improve ELF error reporting using elf_errmsg(elf_errno()).
+
+ - Improve objcopy error handling.
+
+ - Fix handling of 'restrict' qualifier, that was being treated as a 'const'.
+
+ - Support SHN_XINDEX in st_shndx symbol indexes, to handle ELF objects with
+ more than 65534 sections, for instance, which happens with kernels built
+ with 'KCFLAGS="-ffunction-sections -fdata-sections", Other cases may
+ include when using FG-ASLR, LTO.
+
+ - Cope with functions without a name, as seen sometimes when building kernel
+ images with some versions of clang, when a SEGFAULT was taking place.
+
+ - Fix BTF variable generation for kernel modules, not skipping variables at
+ offset zero.
+
+ - Fix address size to match what is in the ELF file being processed, to fix using
+ a 64-bit pahole binary to generate BTF for a 32-bit vmlinux image.
+
+ - Use kernel module ftrace addresses when finding which functions to encode,
+ which increases the number of functions encoded.
+
+libbpf:
+
+ - Allow use of packaged version, for distros wanting to dynamically link with
+ the system's libbpf package instead of using the libbpf git submodule shipped
+ in pahole's source code.
+
+DWARF loader:
+
+ - Support DW_AT_data_bit_offset
+
+ This appeared in DWARF4 but is supported only in gcc's -gdwarf-5,
+ support it in a way that makes the output be the same for both cases.
+
+ $ gcc -gdwarf-5 -c examples/dwarf5/bf.c
+ $ pahole bf.o
+ struct pea {
+ long int a:1; /* 0: 0 8 */
+ long int b:1; /* 0: 1 8 */
+ long int c:1; /* 0: 2 8 */
+
+ /* XXX 29 bits hole, try to pack */
+ /* Bitfield combined with next fields */
+
+ int after_bitfield; /* 4 4 */
+
+ /* size: 8, cachelines: 1, members: 4 */
+ /* sum members: 4 */
+ /* sum bitfield members: 3 bits, bit holes: 1, sum bit holes: 29 bits */
+ /* last cacheline: 8 bytes */
+ };
+
+ - DW_FORM_implicit_const in attr_numeric() and attr_offset()
+
+ - Support DW_TAG_GNU_call_site, its the standardized rename of the previously supported
+ DW_TAG_GNU_call_site.
+
+build:
+
+ - Fix compilation on 32-bit architectures.
+
+Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
diff --git a/changes-v1.21 b/changes-v1.21
new file mode 100644
index 0000000..5b148c8
--- /dev/null
+++ b/changes-v1.21
@@ -0,0 +1,70 @@
+DWARF loader:
+
+- Handle DWARF5 DW_OP_addrx properly
+
+ Part of the effort to support the subset of DWARF5 that is generated when building the kernel.
+
+- Handle subprogram ret type with abstract_origin properly
+
+ Adds a second pass to resolve abstract origin DWARF description of functions to aid
+ the BTF encoder in getting the right return type.
+
+- Check .notes section for LTO build info
+
+ When LTO is used, currently only with clang, we need to do extra steps to handle references
+ from one object (compile unit, aka CU) to another, a way for DWARF to avoid duplicating
+ information.
+
+- Check .debug_abbrev for cross-CU references
+
+ When the kernel build process doesn't add an ELF note in vmlinux indicating that LTO was
+ used and thus intra-CU references are present and thus we need to use a more expensive
+ way to resolve types and (again) thus to encode BTF, we need to look at DWARF's .debug_abbrev
+ ELF section to figure out if such intra-CU references are present.
+
+- Permit merging all DWARF CU's for clang LTO built binary
+
+ Allow not trowing away previously supposedly self contained compile units
+ (objects, aka CU, aka Compile Units) as they have type descriptions that will
+ be used in later CUs.
+
+- Permit a flexible HASHTAGS__BITS
+
+ So that we can use a more expensive algorithm when we need to keep previously processed
+ compile units that will then be referenced by later ones to resolve types.
+
+- Use a better hashing function, from libbpf
+
+ Enabling patch to combine compile units when using LTO.
+
+BTF encoder:
+
+- Add --btf_gen_all flag
+
+ A new command line to allow asking for the generation of all BTF encodings, so that we
+ can stop adding new command line options to enable new encodings in the kernel Makefile.
+
+- Match ftrace addresses within ELF functions
+
+ To cope with differences in how DWARF and ftrace describes function boundaries.
+
+- Funnel ELF error reporting through a macro
+
+ To use libelf's elf_error() function, improving error messages.
+
+- Sanitize non-regular int base type
+
+ Cope with clang with dwarf5 non-regular int base types, tricky stuff, see yhs
+ full explanation in the relevant cset.
+
+- Add support for the floating-point types
+
+ S/390 has floats'n'doubles in its arch specific linux headers, cope with that.
+
+Pretty printer:
+
+- Honour conf_fprintf.hex when printing enumerations
+
+ If the user specifies --hex in the command line, honour it when printing enumerations.
+
+Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
diff --git a/changes-v1.22 b/changes-v1.22
new file mode 100644
index 0000000..9fd0972
--- /dev/null
+++ b/changes-v1.22
@@ -0,0 +1,95 @@
+pahole:
+
+- Allow encoding BTF to a separate BTF file (detached) instead of to a new
+ ".BTF" ELF section in the file being encoded (vmlinux usually).
+
+- Introduce -j/--jobs option to specify the number of threads to use. Without
+ arguments means one thread per CPU. So far used for the DWARF loader, will
+ be used as well for the BTF encoder.
+
+- Show all different types with the same name, not just the first one found.
+
+- Introduce sorted type output (--sort), needed with multithreaded DWARF loading,
+ to use with things like 'btfdiff' that expects the output from DWARF and BTF
+ types to be comparable using 'diff'.
+
+- Stop assuming that reading from stdin means pretty printing as this broke
+ pre-existing scripts, introduce a explicit --prettify command line option.
+
+- Improve type resolution for the --header command line option.
+
+- Disable incomplete CTF encoder, this needs to be done using the external
+ libctf library.
+
+- Do not consider the ftrace filter when encoding BTF for kernel functions.
+
+- Add --kabi_prefix to avoid deduplication woes when using _RH_KABI_REPLACE(),
+
+- Add --with_flexible_array to show just types with flexible arrays.
+
+DWARF Loader:
+
+- Multithreaded loading, requires elfutils >= 0.178.
+
+- Lock calls to non-thread safe elfutils' libdw functions (dwarf_decl_file()
+ and dwarf_decl_line())
+
+- Change hash table size to one that performs better with current typical
+ vmlinux files.
+
+- Allow tweaking the hash table size from the command line.
+
+- Stop allocating memory for strings obtained from libdw, just defer freeing
+ the Dwfl handler so that references to its strings can be safely kept.
+
+- Use a frontend cache for the latest lookup result.
+
+- Allow ignoring some DWARF tags when loading for encoding BTF, as BTF doesn't
+ have equivalents for things like DW_TAG_inline_expansion and DW_TAG_label.
+
+- Allow ignoring some DWARF tag attributes, such as DW_AT_alignment, not used
+ when encoding BTF.
+
+- Do not query for non-C attributes when loading a C language CU (compilation unit).
+
+BTF encoder:
+
+- Preparatory work for multithreaded encoding, the focus for 1.23.
+
+btfdiff:
+
+- Support diffing against a detached BTF file, e.g.: 'btfdiff vmlinux vmlinux.btf'
+
+- Support multithreaded DWARF loading, using the new pahole --sort option to have
+ the output from both BTF and DWARF sorted and thus comparable via 'diff'.
+
+Build:
+
+- Support building with libc libraries lacking either obstacks or argp, such
+ as Alpine Linux's musl libc.
+
+- Support systems without getconf() to obtain the data cacheline size, such
+ as musl libc.
+
+- Add a buildcmd.sh for test builds, tested using the same set of containers
+ used for testing the Linux kernel perf tools.
+
+- Enable selecting building with a shared libdwarves library or statically.
+
+- Allow to use the libbpf package found in distributions instead of with the
+ accompanying libbpf git submodule.
+
+Cleanups:
+
+- Address lots of compiler warnings accumulated by not using -Wextra, it'll
+ be added in the next release after allowing not to use it to build libbpf.
+
+- Address covscan report issues.
+
+Documentation:
+
+- Improve the --nr_methods/-m pahole man page entry.
+
+- Clarify that currently --nr_methods doesn't work together witn -C.
+
+Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
diff --git a/changes-v1.23 b/changes-v1.23
new file mode 100644
index 0000000..426f6f3
--- /dev/null
+++ b/changes-v1.23
@@ -0,0 +1,56 @@
+DWARF loader:
+
+- Read DW_TAG_LLVM_annotation tags, associating it with variables, functions,
+ types. So far this is only being used by the BTF encoder, but the pretty
+ printer should use this as well in a future release, printing these
+ attributes when available.
+
+- Initial support for DW_TAG_skeleton_unit, so far just suggest looking up a
+ matching .dwo file to be used instead. Automagically doing this is in the
+ plans for a future release.
+
+- Fix heap overflow when accessing variable specification.
+
+BTF encoder:
+
+- Support the new BTF type tag attribute, encoding DW_TAG_LLVM_annotation DWARF
+ tags as BTF_KIND_TYPE_TAG and BTF_KIND_DECL_TAG.
+
+ This allows __attribute__((btf_type_tag("tag1"))) to be used for variables,
+ functions, typedefs, so that contextual information can be stored in BTF and
+ used by the kernel BPF verifier for more checks.
+
+ The --skip_encoding_btf_type_tag option can be used to suppress this.
+
+- Fix handling of percpu symbols on s390.
+
+BTF loader:
+
+- Use cacheline size to infer alignment.
+
+btfdiff:
+
+- Now that the BTF loader infers struct member alingment, and as that is just
+ an heuristic, suppress printing the alignment when pretty printing from BTF
+ info like is done when printing from DWARF.
+
+pahole:
+
+- Add --skip_missing so that we don't stop when not finding one of the types passed
+ to -C.
+
+Pretty printer:
+
+- Fix __attribute__((__aligned__(N)) printing alignment for struct members.
+
+- Fix nested __attribute__(__aligned__(N)) struct printing order, so that
+ rebuilding from the printed source circles back to the original source code
+ alignment semantics.
+
+Build:
+
+- No need to download libbpf source when using the system library (libbpf-devel).
+
+- Make python optional
+
+Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
diff --git a/cmake/modules/Findargp.cmake b/cmake/modules/Findargp.cmake
new file mode 100644
index 0000000..db9dc09
--- /dev/null
+++ b/cmake/modules/Findargp.cmake
@@ -0,0 +1,41 @@
+# - Find argp
+# Figure out if argp is in glibc or if it argp-standalone
+#
+# ARGP_LIBRARY - Library to use argp
+# ARGP_FOUND - True if found.
+
+message(STATUS "Checking availability of argp library")
+
+INCLUDE(CheckLibraryExists)
+
+if (ARGP_LIBRARY)
+ # Already in cache, be silent
+ set(ARGP_FIND_QUIETLY TRUE)
+endif (ARGP_LIBRARY)
+
+find_library(ARGP_LIBRARY
+ NAMES argp
+ PATHS /usr/lib /usr/local/lib /usr/lib64 /usr/local/lib64 ~/usr/local/lib ~/usr/local/lib64
+)
+
+if (ARGP_LIBRARY)
+ set(ARGP_FOUND TRUE)
+ set(ARGP_LIBRARY ${ARGP_LIBRARY})
+ set(CMAKE_REQUIRED_LIBRARIES ${ARGP_LIBRARY})
+else (ARGP_LIBRARY)
+ set(ARGP_LIBRARY "")
+endif (ARGP_LIBRARY)
+
+if (ARGP_FOUND)
+ if (NOT ARGP_FIND_QUIETLY)
+ message(STATUS "Found argp library: ${ARGP_LIBRARY}")
+ endif (NOT ARGP_FIND_QUIETLY)
+else (ARGP_FOUND)
+ set(ARGP_FOUND TRUE)
+ message(STATUS "Assuming argp is in libc")
+endif (ARGP_FOUND)
+
+mark_as_advanced(ARGP_LIBRARY)
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake ${CMAKE_CURRENT_SOURCE_DIR}/config.h)
+
+message(STATUS "Checking availability of argp library - done")
diff --git a/cmake/modules/Findobstack.cmake b/cmake/modules/Findobstack.cmake
new file mode 100644
index 0000000..b0f6895
--- /dev/null
+++ b/cmake/modules/Findobstack.cmake
@@ -0,0 +1,41 @@
+# - Find obstack
+# Figure out if obstack is in glibc or if it musl-obstack or elsewhere
+#
+# OBSTACK_LIBRARY - Library to use obstack
+# OBSTACK_FOUND - True if found.
+
+message(STATUS "Checking availability of obstack library")
+
+INCLUDE(CheckLibraryExists)
+
+if (OBSTACK_LIBRARY)
+ # Already in cache, be silent
+ set(OBSTACK_FIND_QUIETLY TRUE)
+endif (OBSTACK_LIBRARY)
+
+find_library(OBSTACK_LIBRARY
+ NAMES obstack
+ PATHS /usr/lib /usr/local/lib /usr/lib64 /usr/local/lib64 ~/usr/local/lib ~/usr/local/lib64
+)
+
+if (OBSTACK_LIBRARY)
+ set(OBSTACK_FOUND TRUE)
+ set(OBSTACK_LIBRARY ${OBSTACK_LIBRARY})
+ set(CMAKE_REQUIRED_LIBRARIES ${OBSTACK_LIBRARY})
+else (OBSTACK_LIBRARY)
+ set(OBSTACK_LIBRARY "")
+endif (OBSTACK_LIBRARY)
+
+if (OBSTACK_FOUND)
+ if (NOT OBSTACK_FIND_QUIETLY)
+ message(STATUS "Found obstack library: ${OBSTACK_LIBRARY}")
+ endif (NOT OBSTACK_FIND_QUIETLY)
+else (OBSTACK_FOUND)
+ set(OBSTACK_FOUND TRUE)
+ message(STATUS "Assuming obstack is in libc")
+endif (OBSTACK_FOUND)
+
+mark_as_advanced(OBSTACK_LIBRARY)
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake ${CMAKE_CURRENT_SOURCE_DIR}/config.h)
+
+message(STATUS "Checking availability of obstack library - done")
diff --git a/codiff.c b/codiff.c
index 264b0af..35aee3f 100644
--- a/codiff.c
+++ b/codiff.c
@@ -87,7 +87,7 @@ static void diff_function(const struct cu *new_cu, struct function *function,
if (function->inlined || function->abstract_origin != 0)
return;
- name = function__name(function, cu);
+ name = function__name(function);
new_tag = cu__find_function_by_name(new_cu, name);
if (new_tag != NULL) {
struct function *new_function = tag__function(new_tag);
@@ -173,7 +173,7 @@ static int check_print_change(const struct class_member *old,
printf(" %s\n"
" from: %-21s /* %5u(%2u) %5zd(%2d) */\n"
" to: %-21s /* %5u(%2u) %5zd(%2u) */\n",
- class_member__name(old, old_cu),
+ class_member__name(old),
old_type_name, old->byte_offset, old->bitfield_offset,
old_size, old->bitfield_size,
new_type_name, new->byte_offset, new->bitfield_offset,
@@ -182,15 +182,15 @@ static int check_print_change(const struct class_member *old,
return changes;
}
-static struct class_member *class__find_pair_member(const struct class *structure, const struct cu *cu,
- const struct class_member *pair_member, const struct cu *pair_cu,
+static struct class_member *class__find_pair_member(const struct class *structure,
+ const struct class_member *pair_member,
int *nr_anonymousp)
{
- const char *member_name = class_member__name(pair_member, pair_cu);
+ const char *member_name = class_member__name(pair_member);
struct class_member *member;
if (member_name)
- return class__find_member_by_name(structure, cu, member_name);
+ return class__find_member_by_name(structure, member_name);
int nr_anonymous = ++*nr_anonymousp;
@@ -198,7 +198,7 @@ static struct class_member *class__find_pair_member(const struct class *structur
type__for_each_member(&structure->type, member) {
if (member->tag.tag == pair_member->tag.tag && /* Both are class/union/struct (unnamed) */
- class_member__name(member, cu) == member_name && /* Both are NULL? */
+ class_member__name(member) == member_name && /* Both are NULL? */
--nr_anonymous == 0)
return member;
}
@@ -217,7 +217,7 @@ static int check_print_members_changes(const struct class *structure,
uint16_t nr_twins_found = 0;
type__for_each_member(&structure->type, member) {
- struct class_member *twin = class__find_pair_member(new_structure, new_cu, member, cu, &nr_anonymous);
+ struct class_member *twin = class__find_pair_member(new_structure, member, &nr_anonymous);
if (twin != NULL) {
twin->tag.visited = 1;
++nr_twins_found;
@@ -231,7 +231,7 @@ static int check_print_members_changes(const struct class *structure,
type = cu__type(cu, member->tag.type);
printf(" %s\n"
" removed: %-21s /* %5u(%2u) %5zd(%2d) */\n",
- class_member__name(member, cu),
+ class_member__name(member),
tag__name(type, cu, name, sizeof(name), NULL),
member->byte_offset, member->bitfield_offset,
member->byte_size, member->bitfield_size);
@@ -254,7 +254,7 @@ static int check_print_members_changes(const struct class *structure,
type = cu__type(new_cu, member->tag.type);
printf(" %s\n"
" added: %-21s /* %5u(%2u) %5zd(%2d) */\n",
- class_member__name(member, new_cu),
+ class_member__name(member),
tag__name(type, new_cu, name, sizeof(name), NULL),
member->byte_offset, member->bitfield_offset,
member->byte_size, member->bitfield_size);
@@ -273,11 +273,10 @@ static void diff_struct(const struct cu *new_cu, struct class *structure,
assert(class__is_struct(structure));
- if (class__size(structure) == 0 || class__name(structure, cu) == NULL)
+ if (class__size(structure) == 0 || class__name(structure) == NULL)
return;
- new_tag = cu__find_struct_by_name(new_cu,
- class__name(structure, cu), 0, NULL);
+ new_tag = cu__find_struct_by_name(new_cu, class__name(structure), 0, NULL);
if (new_tag == NULL)
return;
@@ -299,20 +298,11 @@ static void diff_struct(const struct cu *new_cu, struct class *structure,
return;
++cu->nr_structures_changed;
- cu__check_max_len_changed_item(cu, class__name(structure, cu),
- sizeof("struct"));
+ cu__check_max_len_changed_item(cu, class__name(structure), sizeof("struct"));
structure->priv = diff_info__new(class__tag(new_structure),
new_cu, diff);
}
-static struct cu *cus__find_pair(struct cus *cus, const char *name)
-{
- if (cus->nr_entries == 1)
- return list_first_entry(&cus->cus, struct cu, node);
-
- return cus__find_cu_by_name(cus, name);
-}
-
static int cu_find_new_tags_iterator(struct cu *new_cu, void *old_cus)
{
struct cu *old_cu = cus__find_pair(old_cus, new_cu->name);
@@ -330,7 +320,7 @@ static int cu_find_new_tags_iterator(struct cu *new_cu, void *old_cus)
if (function->abstract_origin || function->inlined)
continue;
- const char *name = function__name(function, new_cu);
+ const char *name = function__name(function);
struct tag *old_function = cu__find_function_by_name(old_cu,
name);
if (old_function != NULL && !tag__function(old_function)->inlined)
@@ -346,7 +336,7 @@ static int cu_find_new_tags_iterator(struct cu *new_cu, void *old_cus)
struct class *class;
cu__for_each_struct(new_cu, id, class) {
- const char *name = class__name(class, new_cu);
+ const char *name = class__name(class);
if (name == NULL || class__size(class) == 0 ||
cu__find_struct_by_name(old_cu, name, 0, NULL))
continue;
@@ -386,7 +376,7 @@ static void show_diffs_function(struct function *function, const struct cu *cu,
printf(" %-*.*s | %+4d",
(int)cu->max_len_changed_item, (int)cu->max_len_changed_item,
- function__name(function, cu), di->diff);
+ function__name(function), di->diff);
if (!verbose) {
putchar('\n');
@@ -400,12 +390,12 @@ static void show_diffs_function(struct function *function, const struct cu *cu,
if (twin->inlined)
puts(cookie ? " (uninlined)" : " (inlined)");
- else if (strcmp(function__name(function, cu),
- function__name(twin, di->cu)) != 0)
+ else if (strcmp(function__name(function),
+ function__name(twin)) != 0)
printf("%s: BRAIN FART ALERT: comparing %s to %s, "
"should be the same name\n", __FUNCTION__,
- function__name(function, cu),
- function__name(twin, di->cu));
+ function__name(function),
+ function__name(twin));
else {
char proto[1024], twin_proto[1024];
@@ -446,7 +436,7 @@ static void show_changed_member(char change, const struct class_member *member,
tag__assert_search_result(type);
printf(" %c%-26s %-21s /* %5u %5zd */\n",
change, tag__name(type, cu, bf, sizeof(bf), NULL),
- class_member__name(member, cu),
+ class_member__name(member),
member->byte_offset, member->byte_size);
}
@@ -460,7 +450,7 @@ static void show_nr_members_changes(const struct class *structure,
/* Find the removed ones */
type__for_each_member(&structure->type, member) {
- struct class_member *twin = class__find_pair_member(new_structure, new_cu, member, cu, &nr_anonymous);
+ struct class_member *twin = class__find_pair_member(new_structure, member, &nr_anonymous);
if (twin == NULL)
show_changed_member('-', member, cu);
}
@@ -468,18 +458,17 @@ static void show_nr_members_changes(const struct class *structure,
nr_anonymous = 0;
/* Find the new ones */
type__for_each_member(&new_structure->type, member) {
- struct class_member *twin = class__find_pair_member(structure, cu, member, new_cu, &nr_anonymous);
+ struct class_member *twin = class__find_pair_member(structure, member, &nr_anonymous);
if (twin == NULL)
show_changed_member('+', member, new_cu);
}
}
-static void print_terse_type_changes(struct class *structure,
- const struct cu *cu)
+static void print_terse_type_changes(struct class *structure)
{
const char *sep = "";
- printf("struct %s: ", class__name(structure, cu));
+ printf("struct %s: ", class__name(structure));
if (terse_type_changes & TCHANGEF__SIZE) {
fputs("size", stdout);
@@ -549,7 +538,7 @@ static void show_diffs_structure(struct class *structure,
printf(" struct %-*.*s | %+4d\n",
(int)(cu->max_len_changed_item - sizeof("struct")),
(int)(cu->max_len_changed_item - sizeof("struct")),
- class__name(structure, cu), diff);
+ class__name(structure), diff);
if (diff != 0)
terse_type_changes |= TCHANGEF__SIZE;
@@ -595,13 +584,13 @@ static void show_diffs_structure(struct class *structure,
new_structure, di->cu, 1);
}
if (show_terse_type_changes)
- print_terse_type_changes(structure, cu);
+ print_terse_type_changes(structure);
}
static void show_structure_diffs_iterator(struct class *class, struct cu *cu)
{
if (class->priv != NULL) {
- const char *name = class__name(class, cu);
+ const char *name = class__name(class);
if (!strlist__has_entry(structs_printed, name)) {
show_diffs_structure(class, cu);
strlist__add(structs_printed, name);
@@ -672,17 +661,17 @@ static int cu_show_diffs_iterator(struct cu *cu, void *cookie)
return 0;
}
-static int cu_delete_priv(struct cu *cu, void *cookie __unused)
+static int cu_delete_priv(struct cu *cu, void *cookie __maybe_unused)
{
struct class *c;
struct function *f;
uint32_t id;
cu__for_each_struct(cu, id, c)
- free(c->priv);
+ zfree(&c->priv);
cu__for_each_function(cu, id, f)
- free(f->priv);
+ zfree(&f->priv);
return 0;
}
@@ -746,8 +735,8 @@ static const struct argp_option codiff__options[] = {
}
};
-static error_t codiff__options_parser(int key, char *arg __unused,
- struct argp_state *state __unused)
+static error_t codiff__options_parser(int key, char *arg __maybe_unused,
+ struct argp_state *state __maybe_unused)
{
switch (key) {
case 'f': show_function_diffs = 1; break;
@@ -789,11 +778,13 @@ failure:
goto out;
}
- if (dwarves__init(0)) {
+ if (dwarves__init()) {
fputs("codiff: insufficient memory\n", stderr);
goto out;
}
+ dwarves__resolve_cacheline_size(&conf_load, 0);
+
if (show_function_diffs == 0 && show_struct_diffs == 0 &&
show_terse_type_changes == 0)
show_function_diffs = show_struct_diffs = 1;
@@ -814,7 +805,7 @@ failure:
/* If old_file is a character device, leave its cus empty */
if (!S_ISCHR(st.st_mode)) {
err = cus__load_file(old_cus, &conf_load, old_filename);
- if (err != 0) {
+ if (err < 0) {
cus__print_error_msg("codiff", old_cus, old_filename, err);
goto out_cus_delete_priv;
}
@@ -828,7 +819,7 @@ failure:
/* If old_file is a character device, leave its cus empty */
if (!S_ISCHR(st.st_mode)) {
err = cus__load_file(new_cus, &conf_load, new_filename);
- if (err != 0) {
+ if (err < 0) {
cus__print_error_msg("codiff", new_cus, new_filename, err);
goto out_cus_delete_priv;
}
@@ -837,7 +828,7 @@ failure:
cus__for_each_cu(old_cus, cu_diff_iterator, new_cus, NULL);
cus__for_each_cu(new_cus, cu_find_new_tags_iterator, old_cus, NULL);
cus__for_each_cu(old_cus, cu_show_diffs_iterator, NULL, NULL);
- if (new_cus->nr_entries > 1)
+ if (cus__nr_entries(new_cus) > 1)
cus__for_each_cu(new_cus, cu_show_diffs_iterator, (void *)1, NULL);
if (total_cus_changed > 1) {
diff --git a/ctf_loader.c b/ctf_loader.c
index 9f03f09..7c34739 100644
--- a/ctf_loader.c
+++ b/ctf_loader.c
@@ -24,12 +24,6 @@
#include "dutil.h"
#include "dwarves.h"
-/*
- * FIXME: We should just get the table from the CTF ELF section
- * and use it directly
- */
-extern struct strings *strings;
-
static void *tag__alloc(const size_t size)
{
struct tag *tag = zalloc(size);
@@ -82,7 +76,7 @@ static int ctf__load_ftype(struct ctf *ctf, struct ftype *proto, uint16_t tag,
return vlen;
out_free_parameters:
- ftype__delete(proto, ctf->priv);
+ ftype__delete(proto);
return -ENOMEM;
}
@@ -94,7 +88,7 @@ static struct function *function__new(uint16_t **ptr, GElf_Sym *sym,
if (func != NULL) {
func->lexblock.ip.addr = elf_sym__value(sym);
func->lexblock.size = elf_sym__size(sym);
- func->name = sym->st_name;
+ func->name = elf_sym__name(sym, ctf->symtab);
func->vtable_entry = -1;
func->external = elf_sym__bind(sym) == STB_GLOBAL;
INIT_LIST_HEAD(&func->vtable_node);
@@ -150,7 +144,7 @@ static int ctf__load_funcs(struct ctf *ctf)
return 0;
}
-static struct base_type *base_type__new(strings_t name, uint32_t attrs,
+static struct base_type *base_type__new(const char *name, uint32_t attrs,
uint8_t float_type, size_t size)
{
struct base_type *bt = tag__alloc(sizeof(*bt));
@@ -167,18 +161,16 @@ static struct base_type *base_type__new(strings_t name, uint32_t attrs,
return bt;
}
-static void type__init(struct type *type, uint16_t tag,
- strings_t name, size_t size)
+static void type__init(struct type *type, uint16_t tag, const char *name, size_t size)
{
__type__init(type);
INIT_LIST_HEAD(&type->namespace.tags);
type->size = size;
type->namespace.tag.tag = tag;
type->namespace.name = name;
- type->namespace.sname = 0;
}
-static struct type *type__new(uint16_t tag, strings_t name, size_t size)
+static struct type *type__new(uint16_t tag, const char *name, size_t size)
{
struct type *type = tag__alloc(sizeof(*type));
@@ -188,7 +180,7 @@ static struct type *type__new(uint16_t tag, strings_t name, size_t size)
return type;
}
-static struct class *class__new(strings_t name, size_t size)
+static struct class *class__new(const char *name, size_t size)
{
struct class *class = tag__alloc(sizeof(*class));
@@ -206,8 +198,8 @@ static int create_new_base_type(struct ctf *ctf, void *ptr,
uint32_t *enc = ptr;
uint32_t eval = ctf__get32(ctf, enc);
uint32_t attrs = CTF_TYPE_INT_ATTRS(eval);
- strings_t name = ctf__get32(ctf, &tp->base.ctf_name);
- struct base_type *base = base_type__new(name, attrs, 0,
+ uint32_t name = ctf__get32(ctf, &tp->base.ctf_name);
+ struct base_type *base = base_type__new(ctf__string(ctf, name), attrs, 0,
CTF_TYPE_INT_BITS(eval));
if (base == NULL)
return -ENOMEM;
@@ -222,9 +214,9 @@ static int create_new_base_type_float(struct ctf *ctf, void *ptr,
struct ctf_full_type *tp,
uint32_t id)
{
- strings_t name = ctf__get32(ctf, &tp->base.ctf_name);
+ uint32_t name = ctf__get32(ctf, &tp->base.ctf_name);
uint32_t *enc = ptr, eval = ctf__get32(ctf, enc);
- struct base_type *base = base_type__new(name, 0, eval,
+ struct base_type *base = base_type__new(ctf__string(ctf, name), 0, eval,
CTF_TYPE_FP_BITS(eval));
if (base == NULL)
return -ENOMEM;
@@ -292,7 +284,7 @@ static int create_full_members(struct ctf *ctf, void *ptr,
member->tag.tag = DW_TAG_member;
member->tag.type = ctf__get16(ctf, &mp[i].ctf_member_type);
- member->name = ctf__get32(ctf, &mp[i].ctf_member_name);
+ member->name = ctf__string(ctf, ctf__get32(ctf, &mp[i].ctf_member_name));
member->bit_offset = (ctf__get32(ctf, &mp[i].ctf_member_offset_high) << 16) |
ctf__get32(ctf, &mp[i].ctf_member_offset_low);
/* sizes and offsets will be corrected at class__fixup_ctf_bitfields */
@@ -316,7 +308,7 @@ static int create_short_members(struct ctf *ctf, void *ptr,
member->tag.tag = DW_TAG_member;
member->tag.type = ctf__get16(ctf, &mp[i].ctf_member_type);
- member->name = ctf__get32(ctf, &mp[i].ctf_member_name);
+ member->name = ctf__string(ctf, ctf__get32(ctf, &mp[i].ctf_member_name));
member->bit_offset = ctf__get16(ctf, &mp[i].ctf_member_offset);
/* sizes and offsets will be corrected at class__fixup_ctf_bitfields */
@@ -331,7 +323,7 @@ static int create_new_class(struct ctf *ctf, void *ptr,
uint64_t size, uint32_t id)
{
int member_size;
- strings_t name = ctf__get32(ctf, &tp->base.ctf_name);
+ const char *name = ctf__string(ctf, ctf__get32(ctf, &tp->base.ctf_name));
struct class *class = class__new(name, size);
if (size >= CTF_SHORT_MEMBER_LIMIT) {
@@ -347,7 +339,7 @@ static int create_new_class(struct ctf *ctf, void *ptr,
return (vlen * member_size);
out_free:
- class__delete(class, ctf->priv);
+ class__delete(class);
return -ENOMEM;
}
@@ -356,7 +348,7 @@ static int create_new_union(struct ctf *ctf, void *ptr,
uint64_t size, uint32_t id)
{
int member_size;
- strings_t name = ctf__get32(ctf, &tp->base.ctf_name);
+ const char *name = ctf__string(ctf, ctf__get32(ctf, &tp->base.ctf_name));
struct type *un = type__new(DW_TAG_union_type, name, size);
if (size >= CTF_SHORT_MEMBER_LIMIT) {
@@ -372,11 +364,11 @@ static int create_new_union(struct ctf *ctf, void *ptr,
return (vlen * member_size);
out_free:
- type__delete(un, ctf->priv);
+ type__delete(un);
return -ENOMEM;
}
-static struct enumerator *enumerator__new(strings_t name, uint32_t value)
+static struct enumerator *enumerator__new(const char *name, uint32_t value)
{
struct enumerator *en = tag__alloc(sizeof(*en));
@@ -395,16 +387,14 @@ static int create_new_enumeration(struct ctf *ctf, void *ptr,
{
struct ctf_enum *ep = ptr;
uint16_t i;
- struct type *enumeration = type__new(DW_TAG_enumeration_type,
- ctf__get32(ctf,
- &tp->base.ctf_name),
- size ?: (sizeof(int) * 8));
+ const char *name = ctf__string(ctf, ctf__get32(ctf, &tp->base.ctf_name));
+ struct type *enumeration = type__new(DW_TAG_enumeration_type, name, size ?: (sizeof(int) * 8));
if (enumeration == NULL)
return -ENOMEM;
for (i = 0; i < vlen; i++) {
- strings_t name = ctf__get32(ctf, &ep[i].ctf_enum_name);
+ const char *name = ctf__string(ctf, ctf__get32(ctf, &ep[i].ctf_enum_name));
uint32_t value = ctf__get32(ctf, &ep[i].ctf_enum_val);
struct enumerator *enumerator = enumerator__new(name, value);
@@ -418,14 +408,14 @@ static int create_new_enumeration(struct ctf *ctf, void *ptr,
return (vlen * sizeof(*ep));
out_free:
- enumeration__delete(enumeration, ctf->priv);
+ enumeration__delete(enumeration);
return -ENOMEM;
}
static int create_new_forward_decl(struct ctf *ctf, struct ctf_full_type *tp,
uint64_t size, uint32_t id)
{
- strings_t name = ctf__get32(ctf, &tp->base.ctf_name);
+ const char *name = ctf__string(ctf, ctf__get32(ctf, &tp->base.ctf_name));
struct class *fwd = class__new(name, size);
if (fwd == NULL)
@@ -438,7 +428,7 @@ static int create_new_forward_decl(struct ctf *ctf, struct ctf_full_type *tp,
static int create_new_typedef(struct ctf *ctf, struct ctf_full_type *tp,
uint64_t size, uint32_t id)
{
- strings_t name = ctf__get32(ctf, &tp->base.ctf_name);
+ const char *name = ctf__string(ctf, ctf__get32(ctf, &tp->base.ctf_name));
unsigned int type_id = ctf__get16(ctf, &tp->base.ctf_type);
struct type *type = type__new(DW_TAG_typedef, name, size);
@@ -560,7 +550,7 @@ static struct variable *variable__new(uint16_t type, GElf_Sym *sym,
if (var != NULL) {
var->scope = VSCOPE_GLOBAL;
var->ip.addr = elf_sym__value(sym);
- var->name = sym->st_name;
+ var->name = ctf->symtab->symstrs->d_buf + sym->st_name;
var->external = elf_sym__bind(sym) == STB_GLOBAL;
var->ip.tag.tag = DW_TAG_variable;
var->ip.tag.type = type;
@@ -642,8 +632,7 @@ static int class__fixup_ctf_bitfields(struct tag *tag, struct cu *cu)
integral_bit_size = base_type__name_to_size(bt, cu);
if (integral_bit_size == 0)
fprintf(stderr, "%s: unknown base type name \"%s\"!\n",
- __func__, base_type__name(bt, cu, name,
- sizeof(name)));
+ __func__, base_type__name(bt, name, sizeof(name)));
}
break;
default:
@@ -691,33 +680,12 @@ static int cu__fixup_ctf_bitfields(struct cu *cu)
return err;
}
-static const char *ctf__function_name(struct function *func,
- const struct cu *cu)
-{
- struct ctf *ctf = cu->priv;
-
- return ctf->symtab->symstrs->d_buf + func->name;
-}
-
-static const char *ctf__variable_name(const struct variable *var,
- const struct cu *cu)
-{
- struct ctf *ctf = cu->priv;
-
- return ctf->symtab->symstrs->d_buf + var->name;
-}
-
static void ctf__cu_delete(struct cu *cu)
{
ctf__delete(cu->priv);
cu->priv = NULL;
}
-static const char *ctf__strings_ptr(const struct cu *cu, strings_t s)
-{
- return ctf__string(cu->priv, s);
-}
-
struct debug_fmt_ops ctf__ops;
int ctf__load_file(struct cus *cus, struct conf_load *conf,
@@ -729,7 +697,7 @@ int ctf__load_file(struct cus *cus, struct conf_load *conf,
if (state == NULL)
return -1;
- struct cu *cu = cu__new(filename, state->wordsize, NULL, 0, filename);
+ struct cu *cu = cu__new(filename, state->wordsize, NULL, 0, filename, false);
if (cu == NULL)
return -1;
@@ -763,9 +731,6 @@ int ctf__load_file(struct cus *cus, struct conf_load *conf,
struct debug_fmt_ops ctf__ops = {
.name = "ctf",
- .function__name = ctf__function_name,
.load_file = ctf__load_file,
- .variable__name = ctf__variable_name,
- .strings__ptr = ctf__strings_ptr,
.cu__delete = ctf__cu_delete,
};
diff --git a/ctracer.c b/ctracer.c
index 0098aa0..10ecac6 100644
--- a/ctracer.c
+++ b/ctracer.c
@@ -130,7 +130,7 @@ static LIST_HEAD(pointers);
static const char *structure__name(const struct structure *st)
{
- return class__name(tag__class(st->class), st->cu);
+ return class__name(tag__class(st->class));
}
static struct structure *structures__find(struct list_head *list, const char *name)
@@ -198,7 +198,7 @@ static struct function *function__filter(struct function *function,
function->abstract_origin != 0 ||
!list_empty(&function->tool_node) ||
!ftype__has_parm_of_type(&function->proto, target_type_id, cu) ||
- strlist__has_entry(init_blacklist, function__name(function, cu))) {
+ strlist__has_entry(init_blacklist, function__name(function))) {
return NULL;
}
@@ -309,15 +309,14 @@ static struct class_member *class__remove_member(struct class *class, const stru
return list_entry(next, struct class_member, tag.node);
}
-static size_t class__find_biggest_member_name(const struct class *class,
- const struct cu *cu)
+static size_t class__find_biggest_member_name(const struct class *class)
{
struct class_member *pos;
size_t biggest_name_len = 0;
type__for_each_data_member(&class->type, pos) {
const size_t len = pos->name ?
- strlen(class_member__name(pos, cu)) : 0;
+ strlen(class_member__name(pos)) : 0;
if (len > biggest_name_len)
biggest_name_len = len;
@@ -326,23 +325,21 @@ static size_t class__find_biggest_member_name(const struct class *class,
return biggest_name_len;
}
-static void class__emit_class_state_collector(struct class *class,
- const struct cu *cu,
- struct class *clone)
+static void class__emit_class_state_collector(struct class *class, struct class *clone)
{
struct class_member *pos;
- int len = class__find_biggest_member_name(clone, cu);
+ int len = class__find_biggest_member_name(clone);
fprintf(fp_collector,
"void ctracer__class_state(const void *from, void *to)\n"
"{\n"
"\tconst struct %s *obj = from;\n"
"\tstruct %s *mini_obj = to;\n\n",
- class__name(class, cu), class__name(clone, cu));
+ class__name(class), class__name(clone));
type__for_each_data_member(&clone->type, pos)
fprintf(fp_collector, "\tmini_obj->%-*s = obj->%s;\n", len,
- class_member__name(pos, cu),
- class_member__name(pos, cu));
+ class_member__name(pos),
+ class_member__name(pos));
fputs("}\n\n", fp_collector);
}
@@ -352,7 +349,7 @@ static struct class *class__clone_base_types(const struct tag *tag,
{
struct class *class = tag__class(tag);
struct class_member *pos, *next;
- struct class *clone = class__clone(class, new_class_name, cu);
+ struct class *clone = class__clone(class, new_class_name);
if (clone == NULL)
return NULL;
@@ -363,7 +360,7 @@ static struct class *class__clone_base_types(const struct tag *tag,
tag__assert_search_result(member_type);
if (!tag__is_base_type(member_type, cu)) {
next = class__remove_member(clone, cu, pos);
- class_member__delete(pos, cu);
+ class_member__delete(pos);
}
}
class__fixup_alignment(clone, cu);
@@ -390,20 +387,19 @@ static void emit_struct_member_table_entry(FILE *fp,
* ostra-cg to preprocess the raw data collected from the debugfs/relay
* channel.
*/
-static int class__emit_ostra_converter(struct tag *tag,
- const struct cu *cu)
+static int class__emit_ostra_converter(struct tag *tag)
{
struct class *class = tag__class(tag);
struct class_member *pos;
struct type *type = &mini_class->type;
int field = 0, first = 1;
char filename[128];
- char parm_list[1024];
+ char parm_list[1024] = "";
char *p = parm_list;
size_t n;
size_t plen = sizeof(parm_list);
FILE *fp_fields, *fp_converter;
- const char *name = class__name(class, cu);
+ const char *name = class__name(class);
snprintf(filename, sizeof(filename), "%s/%s.fields", src_dir, name);
fp_fields = fopen(filename, "w");
@@ -461,10 +457,10 @@ static int class__emit_ostra_converter(struct tag *tag,
plen -= n; p += n;
}
fprintf(fp_converter, "%%u");
- n = snprintf(p, plen, "obj.%s", class_member__name(pos, cu));
+ n = snprintf(p, plen, "obj.%s", class_member__name(pos));
plen -= n; p += n;
emit_struct_member_table_entry(fp_fields, field++,
- class_member__name(pos, cu),
+ class_member__name(pos),
1, "entry,exit");
}
fprintf(fp_converter,
@@ -495,7 +491,7 @@ static struct tag *pointer_filter(struct tag *tag, struct cu *cu,
if (type->nr_members == 0)
return NULL;
- class_name = class__name(tag__class(tag), cu);
+ class_name = class__name(tag__class(tag));
if (class_name == NULL || structures__find(&pointers, class_name))
return NULL;
@@ -539,8 +535,7 @@ static void class__find_pointers(const char *class_name)
* We want just the DW_TAG_structure_type tags that have as its first member
* a struct of type target.
*/
-static struct tag *alias_filter(struct tag *tag, const struct cu *cu,
- type_id_t target_type_id)
+static struct tag *alias_filter(struct tag *tag, type_id_t target_type_id)
{
struct type *type;
struct class_member *first_member;
@@ -557,7 +552,7 @@ static struct tag *alias_filter(struct tag *tag, const struct cu *cu,
if (first_member->tag.type != target_type_id)
return NULL;
- if (structures__find(&aliases, class__name(tag__class(tag), cu)))
+ if (structures__find(&aliases, class__name(tag__class(tag))))
return NULL;
return tag;
@@ -578,8 +573,8 @@ static int cu_find_aliases_iterator(struct cu *cu, void *class_name)
return 0;
cu__for_each_type(cu, id, pos) {
- if (alias_filter(pos, cu, target_type_id)) {
- const char *alias_name = class__name(tag__class(pos), cu);
+ if (alias_filter(pos, target_type_id)) {
+ const char *alias_name = class__name(tag__class(pos));
structures__add(&aliases, pos, cu);
@@ -607,7 +602,7 @@ static void class__find_aliases(const char *class_name)
cus__for_each_cu(methods_cus, cu_find_aliases_iterator, (void *)class_name, cu_filter);
}
-static void emit_list_of_types(struct list_head *list, const struct cu *cu)
+static void emit_list_of_types(struct list_head *list)
{
struct structure *pos;
@@ -617,8 +612,7 @@ static void emit_list_of_types(struct list_head *list, const struct cu *cu)
* Lets look at the other CUs, perhaps we have already
* emmited this one
*/
- if (type_emissions__find_definition(&emissions, cu,
- structure__name(pos))) {
+ if (type_emissions__find_definition(&emissions, structure__name(pos))) {
type->definition_emitted = 1;
continue;
}
@@ -638,7 +632,7 @@ static int class__emit_classes(struct tag *tag, struct cu *cu)
char mini_class_name[128];
snprintf(mini_class_name, sizeof(mini_class_name), "ctracer__mini_%s",
- class__name(class, cu));
+ class__name(class));
mini_class = class__clone_base_types(tag, cu, mini_class_name);
if (mini_class == NULL)
@@ -649,15 +643,15 @@ static int class__emit_classes(struct tag *tag, struct cu *cu)
type__emit(tag, cu, NULL, NULL, fp_classes);
fputs("\n/* class aliases */\n\n", fp_classes);
- emit_list_of_types(&aliases, cu);
+ emit_list_of_types(&aliases);
fputs("\n/* class with pointers */\n\n", fp_classes);
- emit_list_of_types(&pointers, cu);
+ emit_list_of_types(&pointers);
class__fprintf(mini_class, cu, fp_classes);
fputs(";\n\n", fp_classes);
- class__emit_class_state_collector(class, cu, mini_class);
+ class__emit_class_state_collector(class, mini_class);
err = 0;
out:
return err;
@@ -676,7 +670,7 @@ static int function__emit_probes(struct function *func, uint32_t function_id,
const char *member)
{
struct parameter *pos;
- const char *name = function__name(func, cu);
+ const char *name = function__name(func);
fprintf(fp_methods, "probe %s%s = kernel.function(\"%s@%s\")%s\n"
"{\n"
@@ -698,14 +692,13 @@ static int function__emit_probes(struct function *func, uint32_t function_id,
continue;
if (member != NULL)
- fprintf(fp_methods, "\tif ($%s)\n\t",
- parameter__name(pos, cu));
+ fprintf(fp_methods, "\tif ($%s)\n\t", parameter__name(pos));
fprintf(fp_methods,
"\tctracer__method_hook(%d, %d, $%s%s%s, %d);\n",
probe_type,
function_id,
- parameter__name(pos, cu),
+ parameter__name(pos),
member ? "->" : "", member ?: "",
class__size(mini_class));
break;
@@ -734,7 +727,7 @@ static int cu_emit_probes_iterator(struct cu *cu, void *cookie)
list_for_each_entry(pos, &cu->tool_list, tool_node) {
uint32_t function_id = (long)pos->priv;
- if (methods__add(&probes_emitted, function__name(pos, cu)) != 0)
+ if (methods__add(&probes_emitted, function__name(pos)) != 0)
continue;
function__emit_probes(pos, function_id, cu, target_type_id, 0, NULL); /* entry */
function__emit_probes(pos, function_id, cu, target_type_id, 1, NULL); /* exit */
@@ -777,13 +770,13 @@ static int cu_emit_pointer_probes_iterator(struct cu *cu, void *cookie)
list_for_each_entry(pos_tag, &cu->tool_list, tool_node) {
uint32_t function_id = (long)pos_tag->priv;
- if (methods__add(&probes_emitted, function__name(pos_tag, cu)) != 0)
+ if (methods__add(&probes_emitted, function__name(pos_tag)) != 0)
continue;
function__emit_probes(pos_tag, function_id, cu, target_type_id, 0,
- class_member__name(pos_member, cu)); /* entry */
+ class_member__name(pos_member)); /* entry */
function__emit_probes(pos_tag, function_id, cu, target_type_id, 1,
- class_member__name(pos_member, cu)); /* exit */
+ class_member__name(pos_member)); /* exit */
}
return 0;
@@ -801,8 +794,7 @@ static int cu_emit_functions_table(struct cu *cu, void *fp)
list_for_each_entry(pos, &cu->tool_list, tool_node)
if (pos->priv != NULL) {
uint32_t function_id = (long)pos->priv;
- fprintf(fp, "%d:%s\n", function_id,
- function__name(pos, cu));
+ fprintf(fp, "%d:%s\n", function_id, function__name(pos));
pos->priv = NULL;
}
@@ -830,20 +822,13 @@ static int elf__open(const char *filename)
goto out_close;
}
- GElf_Ehdr ehdr;
- if (gelf_getehdr(elf, &ehdr) == NULL) {
- fprintf(stderr, "%s: cannot get elf header.\n", __func__);
- goto out_elf_end;
- }
-
GElf_Shdr shdr;
size_t init_index;
- Elf_Scn *init = elf_section_by_name(elf, &ehdr, &shdr, ".init.text",
- &init_index);
+ Elf_Scn *init = elf_section_by_name(elf, &shdr, ".init.text", &init_index);
if (init == NULL)
goto out_elf_end;
- struct elf_symtab *symtab = elf_symtab__new(".symtab", elf, &ehdr);
+ struct elf_symtab *symtab = elf_symtab__new(".symtab", elf);
if (symtab == NULL)
goto out_elf_end;
@@ -920,7 +905,7 @@ static const char *dirname, *glob;
static int recursive;
static error_t ctracer__options_parser(int key, char *arg,
- struct argp_state *state __unused)
+ struct argp_state *state __maybe_unused)
{
switch (key) {
case 'd': src_dir = arg; break;
@@ -955,10 +940,11 @@ int main(int argc, char *argv[])
FILE *fp_functions;
int rc = EXIT_FAILURE;
- if (dwarves__init(0)) {
+ if (dwarves__init()) {
fputs("ctracer: insufficient memory\n", stderr);
goto out;
}
+ dwarves__resolve_cacheline_size(NULL, 0);
if (argp_parse(&ctracer__argp, argc, argv, 0, &remaining, NULL) ||
remaining < argc) {
@@ -1028,7 +1014,7 @@ failure:
}
snprintf(functions_filename, sizeof(functions_filename),
- "%s/%s.functions", src_dir, class__name(tag__class(class), cu));
+ "%s/%s.functions", src_dir, class__name(tag__class(class)));
fp_functions = fopen(functions_filename, "w");
if (fp_functions == NULL) {
fprintf(stderr, "ctracer: couldn't create %s\n",
@@ -1081,7 +1067,7 @@ failure:
class__emit_classes(class, cu);
fputc('\n', fp_collector);
- class__emit_ostra_converter(class, cu);
+ class__emit_ostra_converter(class);
cu_blacklist = strlist__new(true);
if (cu_blacklist != NULL)
diff --git a/dtagnames.c b/dtagnames.c
index 0ffcbf7..343f055 100644
--- a/dtagnames.c
+++ b/dtagnames.c
@@ -7,26 +7,18 @@
#include <stdio.h>
#include <stdlib.h>
-#include <malloc.h>
#include "dwarves.h"
#include "dutil.h"
-static void print_malloc_stats(void)
-{
- struct mallinfo m = mallinfo();
-
- fprintf(stderr, "size: %u\n", m.uordblks);
-}
-
-static int class__tag_name(struct tag *tag, struct cu *cu __unused,
- void *cookie __unused)
+static int class__tag_name(struct tag *tag, struct cu *cu __maybe_unused,
+ void *cookie __maybe_unused)
{
puts(dwarf_tag_name(tag->tag));
return 0;
}
-static int cu__dump_class_tag_names(struct cu *cu, void *cookie __unused)
+static int cu__dump_class_tag_names(struct cu *cu, void *cookie __maybe_unused)
{
cu__for_all_tags(cu, class__tag_name, NULL);
return 0;
@@ -37,15 +29,16 @@ static void cus__dump_class_tag_names(struct cus *cus)
cus__for_each_cu(cus, cu__dump_class_tag_names, NULL, NULL);
}
-int main(int argc __unused, char *argv[])
+int main(int argc __maybe_unused, char *argv[])
{
int err, rc = EXIT_FAILURE;
struct cus *cus = cus__new();
- if (dwarves__init(0) || cus == NULL) {
+ if (dwarves__init() || cus == NULL) {
fputs("dtagnames: insufficient memory\n", stderr);
goto out;
}
+ dwarves__resolve_cacheline_size(NULL, 0);
err = cus__load_files(cus, NULL, argv + 1);
if (err != 0) {
@@ -54,7 +47,6 @@ int main(int argc __unused, char *argv[])
}
cus__dump_class_tag_names(cus);
- print_malloc_stats();
rc = EXIT_SUCCESS;
out:
cus__delete(cus);
diff --git a/dutil.c b/dutil.c
index 7b66764..97c4474 100644
--- a/dutil.c
+++ b/dutil.c
@@ -13,12 +13,15 @@
#include <stdlib.h>
#include <string.h>
-void *zalloc(const size_t size)
+void *zalloc(size_t size)
{
- void *s = malloc(size);
- if (s != NULL)
- memset(s, 0, size);
- return s;
+ return calloc(1, size);
+}
+
+void __zfree(void **ptr)
+{
+ free(*ptr);
+ *ptr = NULL;
}
struct str_node *str_node__new(const char *s, bool dupstr)
@@ -43,8 +46,11 @@ out_delete:
static void str_node__delete(struct str_node *snode, bool dupstr)
{
+ if (snode == NULL)
+ return;
+
if (dupstr)
- free((void *)snode->s);
+ zfree(&snode->s);
free(snode);
}
@@ -174,17 +180,22 @@ bool strlist__has_entry(struct strlist *slist, const char *entry)
return false;
}
-Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
- GElf_Shdr *shp, const char *name, size_t *index)
+Elf_Scn *elf_section_by_name(Elf *elf, GElf_Shdr *shp, const char *name, size_t *index)
{
Elf_Scn *sec = NULL;
size_t cnt = 1;
+ size_t str_idx;
+
+ if (elf_getshdrstrndx(elf, &str_idx))
+ return NULL;
while ((sec = elf_nextscn(elf, sec)) != NULL) {
char *str;
gelf_getshdr(sec, shp);
- str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
+ str = elf_strptr(elf, str_idx, shp->sh_name);
+ if (!str)
+ return NULL;
if (!strcmp(name, str)) {
if (index)
*index = cnt;
diff --git a/dutil.h b/dutil.h
index 0838dff..e45bba0 100644
--- a/dutil.h
+++ b/dutil.h
@@ -10,6 +10,7 @@
*/
#include <stdbool.h>
+#include <linux/stddef.h>
#include <stddef.h>
#include <string.h>
#include <elf.h>
@@ -20,8 +21,8 @@
#define BITS_PER_LONG __BITS_PER_LONG
-#ifndef __unused
-#define __unused __attribute__ ((unused))
+#ifndef __maybe_unused
+#define __maybe_unused __attribute__((__unused__))
#endif
#ifndef __pure
@@ -30,6 +31,10 @@
#define roundup(x,y) ((((x) + ((y) - 1)) / (y)) * (y))
+#ifndef DW_TAG_LLVM_annotation
+#define DW_TAG_LLVM_annotation 0x6000
+#endif
+
static inline __attribute__((const)) bool is_power_of_2(unsigned long n)
{
return (n != 0 && ((n & (n - 1)) == 0));
@@ -321,8 +326,7 @@ static inline bool strstarts(const char *str, const char *prefix)
void *zalloc(const size_t size);
-Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
- GElf_Shdr *shp, const char *name, size_t *index);
+Elf_Scn *elf_section_by_name(Elf *elf, GElf_Shdr *shp, const char *name, size_t *index);
Elf_Scn *elf_section_by_idx(Elf *elf, GElf_Shdr *shp, int idx);
@@ -336,4 +340,8 @@ static inline int elf_getshdrstrndx(Elf *elf, size_t *dst)
char *strlwr(char *s);
+void __zfree(void **ptr);
+
+#define zfree(ptr) __zfree((void **)(ptr))
+
#endif /* _DUTIL_H_ */
diff --git a/dwarf_loader.c b/dwarf_loader.c
index 4638df7..e30b03c 100644
--- a/dwarf_loader.c
+++ b/dwarf_loader.c
@@ -12,7 +12,8 @@
#include <fcntl.h>
#include <fnmatch.h>
#include <libelf.h>
-#include <obstack.h>
+#include <limits.h>
+#include <pthread.h>
#include <search.h>
#include <stdio.h>
#include <stdlib.h>
@@ -23,11 +24,8 @@
#include "list.h"
#include "dwarves.h"
#include "dutil.h"
-#include "pahole_strings.h"
#include "hash.h"
-struct strings *strings;
-
#ifndef DW_AT_alignment
#define DW_AT_alignment 0x88
#endif
@@ -41,7 +39,28 @@ struct strings *strings;
#define DW_TAG_GNU_call_site_parameter 0x410a
#endif
-#define hashtags__fn(key) hash_64(key, HASHTAGS__BITS)
+#ifndef DW_TAG_call_site
+#define DW_TAG_call_site 0x48
+#define DW_TAG_call_site_parameter 0x49
+#endif
+
+#ifndef DW_FORM_implicit_const
+#define DW_FORM_implicit_const 0x21
+#endif
+
+#ifndef DW_OP_addrx
+#define DW_OP_addrx 0xa1
+#endif
+
+static pthread_mutex_t libdw__lock = PTHREAD_MUTEX_INITIALIZER;
+
+static uint32_t hashtags__bits = 12;
+static uint32_t max_hashtags__bits = 21;
+
+static uint32_t hashtags__fn(Dwarf_Off key)
+{
+ return hash_64(key, hashtags__bits);
+}
bool no_bitfield_type_recode = true;
@@ -79,8 +98,8 @@ struct dwarf_tag {
};
struct tag *tag;
uint32_t small_id;
- strings_t decl_file;
uint16_t decl_line;
+ const char *decl_file;
};
static dwarf_off_ref dwarf_tag__spec(struct dwarf_tag *dtag)
@@ -93,40 +112,77 @@ static void dwarf_tag__set_spec(struct dwarf_tag *dtag, dwarf_off_ref spec)
*(dwarf_off_ref *)(dtag + 1) = spec;
}
-#define HASHTAGS__BITS 15
-#define HASHTAGS__SIZE (1UL << HASHTAGS__BITS)
-
-#define obstack_chunk_alloc malloc
-#define obstack_chunk_free free
-
-static void *obstack_zalloc(struct obstack *obstack, size_t size)
-{
- void *o = obstack_alloc(obstack, size);
-
- if (o)
- memset(o, 0, size);
- return o;
-}
-
struct dwarf_cu {
- struct hlist_head hash_tags[HASHTAGS__SIZE];
- struct hlist_head hash_types[HASHTAGS__SIZE];
- struct obstack obstack;
+ struct hlist_head *hash_tags;
+ struct hlist_head *hash_types;
+ struct dwarf_tag *last_type_lookup;
struct cu *cu;
struct dwarf_cu *type_unit;
};
-static void dwarf_cu__init(struct dwarf_cu *dcu)
+static int dwarf_cu__init(struct dwarf_cu *dcu, struct cu *cu)
{
+ static struct dwarf_tag sentinel_dtag = { .id = ULLONG_MAX, };
+ uint64_t hashtags_size = 1UL << hashtags__bits;
+
+ dcu->cu = cu;
+
+ dcu->hash_tags = cu__malloc(cu, sizeof(struct hlist_head) * hashtags_size);
+ if (!dcu->hash_tags)
+ return -ENOMEM;
+
+ dcu->hash_types = cu__malloc(cu, sizeof(struct hlist_head) * hashtags_size);
+ if (!dcu->hash_types) {
+ cu__free(cu, dcu->hash_tags);
+ return -ENOMEM;
+ }
+
unsigned int i;
- for (i = 0; i < HASHTAGS__SIZE; ++i) {
+ for (i = 0; i < hashtags_size; ++i) {
INIT_HLIST_HEAD(&dcu->hash_tags[i]);
INIT_HLIST_HEAD(&dcu->hash_types[i]);
}
- obstack_init(&dcu->obstack);
dcu->type_unit = NULL;
+ // To avoid a per-lookup check against NULL in dwarf_cu__find_type_by_ref()
+ dcu->last_type_lookup = &sentinel_dtag;
+ return 0;
+}
+
+static struct dwarf_cu *dwarf_cu__new(struct cu *cu)
+{
+ struct dwarf_cu *dwarf_cu = cu__zalloc(cu, sizeof(*dwarf_cu));
+
+ if (dwarf_cu != NULL && dwarf_cu__init(dwarf_cu, cu) != 0) {
+ cu__free(cu, dwarf_cu);
+ dwarf_cu = NULL;
+ }
+
+ return dwarf_cu;
+}
+
+static void dwarf_cu__delete(struct cu *cu)
+{
+ if (cu == NULL || cu->priv == NULL)
+ return;
+
+ struct dwarf_cu *dcu = cu->priv;
+
+ // dcu->hash_tags & dcu->hash_types are on cu->obstack
+ cu__free(cu, dcu);
+ cu->priv = NULL;
+}
+
+static void __tag__print_type_not_found(struct tag *tag, const char *func)
+{
+ struct dwarf_tag *dtag = tag->priv;
+ fprintf(stderr, "%s: couldn't find %#llx type for %#llx (%s)!\n", func,
+ (unsigned long long)dtag->type.off, (unsigned long long)dtag->id,
+ dwarf_tag_name(tag->tag));
}
+#define tag__print_type_not_found(tag) \
+ __tag__print_type_not_found(tag, __func__)
+
static void hashtags__hash(struct hlist_head *hashtable,
struct dwarf_tag *dtag)
{
@@ -142,7 +198,7 @@ static struct dwarf_tag *hashtags__find(const struct hlist_head *hashtable,
struct dwarf_tag *tpos;
struct hlist_node *pos;
- uint16_t bucket = hashtags__fn(id);
+ uint32_t bucket = hashtags__fn(id);
const struct hlist_head *head = hashtable + bucket;
hlist_for_each_entry(tpos, pos, head, hash_node) {
@@ -173,7 +229,7 @@ static struct dwarf_tag *dwarf_cu__find_tag_by_ref(const struct dwarf_cu *cu,
return hashtags__find(cu->hash_tags, ref->off);
}
-static struct dwarf_tag *dwarf_cu__find_type_by_ref(const struct dwarf_cu *dcu,
+static struct dwarf_tag *dwarf_cu__find_type_by_ref(struct dwarf_cu *dcu,
const struct dwarf_off_ref *ref)
{
if (dcu == NULL)
@@ -184,14 +240,21 @@ static struct dwarf_tag *dwarf_cu__find_type_by_ref(const struct dwarf_cu *dcu,
return NULL;
}
}
- return hashtags__find(dcu->hash_types, ref->off);
-}
-extern struct strings *strings;
+ if (dcu->last_type_lookup->id == ref->off)
+ return dcu->last_type_lookup;
+
+ struct dwarf_tag *dtag = hashtags__find(dcu->hash_types, ref->off);
+
+ if (dtag)
+ dcu->last_type_lookup = dtag;
+
+ return dtag;
+}
static void *memdup(const void *src, size_t len, struct cu *cu)
{
- void *s = obstack_alloc(&cu->obstack, len);
+ void *s = cu__malloc(cu, len);
if (s != NULL)
memcpy(s, src, len);
return s;
@@ -248,6 +311,7 @@ static uint64_t attr_numeric(Dwarf_Die *die, uint32_t name)
return addr;
}
break;
+ case DW_FORM_implicit_const:
case DW_FORM_data1:
case DW_FORM_data2:
case DW_FORM_data4:
@@ -274,7 +338,12 @@ static uint64_t attr_numeric(Dwarf_Die *die, uint32_t name)
return 0;
}
-static uint64_t dwarf_expr(const uint8_t *expr, uint32_t len __unused)
+static uint64_t attr_alignment(Dwarf_Die *die, struct conf_load *conf)
+{
+ return conf->ignore_alignment_attr ? 0 : attr_numeric(die, DW_AT_alignment);
+}
+
+static uint64_t dwarf_expr(const uint8_t *expr, uint32_t len __maybe_unused)
{
/* Common case: offset from start of the class */
if (expr[0] == DW_OP_plus_uconst ||
@@ -290,15 +359,12 @@ static uint64_t dwarf_expr(const uint8_t *expr, uint32_t len __unused)
return UINT64_MAX;
}
-static Dwarf_Off attr_offset(Dwarf_Die *die, const uint32_t name)
+static Dwarf_Off __attr_offset(Dwarf_Attribute *attr)
{
- Dwarf_Attribute attr;
Dwarf_Block block;
- if (dwarf_attr(die, name, &attr) == NULL)
- return 0;
-
- switch (dwarf_whatform(&attr)) {
+ switch (dwarf_whatform(attr)) {
+ case DW_FORM_implicit_const:
case DW_FORM_data1:
case DW_FORM_data2:
case DW_FORM_data4:
@@ -306,24 +372,41 @@ static Dwarf_Off attr_offset(Dwarf_Die *die, const uint32_t name)
case DW_FORM_sdata:
case DW_FORM_udata: {
Dwarf_Word value;
- if (dwarf_formudata(&attr, &value) == 0)
+ if (dwarf_formudata(attr, &value) == 0)
return value;
break;
}
default:
- if (dwarf_formblock(&attr, &block) == 0)
+ if (dwarf_formblock(attr, &block) == 0)
return dwarf_expr(block.data, block.length);
}
return 0;
}
-static const char *attr_string(Dwarf_Die *die, uint32_t name)
+static Dwarf_Off attr_offset(Dwarf_Die *die, const uint32_t name)
{
Dwarf_Attribute attr;
- if (dwarf_attr(die, name, &attr) != NULL)
- return dwarf_formstring(&attr);
- return NULL;
+
+ if (dwarf_attr(die, name, &attr) == NULL)
+ return 0;
+
+ return __attr_offset(&attr);
+}
+
+static const char *attr_string(Dwarf_Die *die, uint32_t name, struct conf_load *conf __maybe_unused)
+{
+ const char *str = NULL;
+ Dwarf_Attribute attr;
+
+ if (dwarf_attr(die, name, &attr) != NULL) {
+ str = dwarf_formstring(&attr);
+
+ if (conf && conf->kabi_prefix && str && strncmp(str, conf->kabi_prefix, conf->kabi_prefix_len) == 0)
+ return conf->kabi_prefix;
+ }
+
+ return str;
}
static struct dwarf_off_ref attr_type(Dwarf_Die *die, uint32_t attr_name)
@@ -346,8 +429,19 @@ static int attr_location(Dwarf_Die *die, Dwarf_Op **expr, size_t *exprlen)
{
Dwarf_Attribute attr;
if (dwarf_attr(die, DW_AT_location, &attr) != NULL) {
- if (dwarf_getlocation(&attr, expr, exprlen) == 0)
+ if (dwarf_getlocation(&attr, expr, exprlen) == 0) {
+ /* DW_OP_addrx needs additional lookup for real addr. */
+ if (*exprlen != 0 && expr[0]->atom == DW_OP_addrx) {
+ Dwarf_Attribute addr_attr;
+ dwarf_getlocation_attr(&attr, expr[0], &addr_attr);
+
+ Dwarf_Addr address;
+ dwarf_formaddr (&addr_attr, &address);
+
+ expr[0]->number = address;
+ }
return 0;
+ }
}
return 1;
@@ -355,13 +449,12 @@ static int attr_location(Dwarf_Die *die, Dwarf_Op **expr, size_t *exprlen)
static void *__tag__alloc(struct dwarf_cu *dcu, size_t size, bool spec)
{
- struct dwarf_tag *dtag = obstack_zalloc(&dcu->obstack,
- (sizeof(*dtag) +
- (spec ? sizeof(dwarf_off_ref) : 0)));
+ struct dwarf_tag *dtag = cu__zalloc(dcu->cu, (sizeof(*dtag) + (spec ? sizeof(dwarf_off_ref) : 0)));
+
if (dtag == NULL)
return NULL;
- struct tag *tag = obstack_zalloc(&dcu->cu->obstack, size);
+ struct tag *tag = cu__zalloc(dcu->cu, size);
if (tag == NULL)
return NULL;
@@ -402,19 +495,22 @@ static void tag__init(struct tag *tag, struct cu *cu, Dwarf_Die *die)
tag->recursivity_level = 0;
if (cu->extra_dbg_info) {
+ pthread_mutex_lock(&libdw__lock);
+
int32_t decl_line;
const char *decl_file = dwarf_decl_file(die);
- static const char *last_decl_file;
- static uint32_t last_decl_file_idx;
+ static const char *last_decl_file, *last_decl_file_ptr;
- if (decl_file != last_decl_file) {
- last_decl_file_idx = strings__add(strings, decl_file);
- last_decl_file = decl_file;
+ if (decl_file != last_decl_file_ptr) {
+ last_decl_file = decl_file ? strdup(decl_file) : NULL;
+ last_decl_file_ptr = decl_file;
}
- dtag->decl_file = last_decl_file_idx;
+ dtag->decl_file = last_decl_file;
dwarf_decl_line(die, &decl_line);
dtag->decl_line = decl_line;
+
+ pthread_mutex_unlock(&libdw__lock);
}
INIT_LIST_HEAD(&tag->node);
@@ -444,19 +540,30 @@ static struct ptr_to_member_type *ptr_to_member_type__new(Dwarf_Die *die,
return ptr;
}
-static struct base_type *base_type__new(Dwarf_Die *die, struct cu *cu)
+static uint8_t encoding_to_float_type(uint64_t encoding)
+{
+ switch (encoding) {
+ case DW_ATE_complex_float: return BT_FP_CMPLX;
+ case DW_ATE_float: return BT_FP_SINGLE;
+ case DW_ATE_imaginary_float: return BT_FP_IMGRY;
+ default: return 0;
+ }
+}
+
+static struct base_type *base_type__new(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
struct base_type *bt = tag__alloc(cu, sizeof(*bt));
if (bt != NULL) {
tag__init(&bt->tag, cu, die);
- bt->name = strings__add(strings, attr_string(die, DW_AT_name));
+ bt->name = attr_string(die, DW_AT_name, conf);
bt->bit_size = attr_numeric(die, DW_AT_byte_size) * 8;
uint64_t encoding = attr_numeric(die, DW_AT_encoding);
bt->is_bool = encoding == DW_ATE_boolean;
bt->is_signed = encoding == DW_ATE_signed;
bt->is_varargs = false;
bt->name_has_encoding = true;
+ bt->float_type = encoding_to_float_type(encoding);
}
return bt;
@@ -491,32 +598,32 @@ static struct string_type *string_type__new(Dwarf_Die *die, struct cu *cu)
}
static void namespace__init(struct namespace *namespace, Dwarf_Die *die,
- struct cu *cu)
+ struct cu *cu, struct conf_load *conf)
{
tag__init(&namespace->tag, cu, die);
INIT_LIST_HEAD(&namespace->tags);
- namespace->sname = 0;
- namespace->name = strings__add(strings, attr_string(die, DW_AT_name));
+ INIT_LIST_HEAD(&namespace->annots);
+ namespace->name = attr_string(die, DW_AT_name, conf);
namespace->nr_tags = 0;
namespace->shared_tags = 0;
}
-static struct namespace *namespace__new(Dwarf_Die *die, struct cu *cu)
+static struct namespace *namespace__new(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
struct namespace *namespace = tag__alloc(cu, sizeof(*namespace));
if (namespace != NULL)
- namespace__init(namespace, die, cu);
+ namespace__init(namespace, die, cu, conf);
return namespace;
}
-static void type__init(struct type *type, Dwarf_Die *die, struct cu *cu)
+static void type__init(struct type *type, Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
- namespace__init(&type->namespace, die, cu);
+ namespace__init(&type->namespace, die, cu, conf);
__type__init(type);
type->size = attr_numeric(die, DW_AT_byte_size);
- type->alignment = attr_numeric(die, DW_AT_alignment);
+ type->alignment = attr_alignment(die, conf);
type->declaration = attr_numeric(die, DW_AT_declaration);
dwarf_tag__set_spec(type->namespace.tag.priv,
attr_type(die, DW_AT_specification));
@@ -527,23 +634,23 @@ static void type__init(struct type *type, Dwarf_Die *die, struct cu *cu)
type->nr_static_members = 0;
}
-static struct type *type__new(Dwarf_Die *die, struct cu *cu)
+static struct type *type__new(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
struct type *type = tag__alloc_with_spec(cu, sizeof(*type));
if (type != NULL)
- type__init(type, die, cu);
+ type__init(type, die, cu, conf);
return type;
}
-static struct enumerator *enumerator__new(Dwarf_Die *die, struct cu *cu)
+static struct enumerator *enumerator__new(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
struct enumerator *enumerator = tag__alloc(cu, sizeof(*enumerator));
if (enumerator != NULL) {
tag__init(&enumerator->tag, cu, die);
- enumerator->name = strings__add(strings, attr_string(die, DW_AT_name));
+ enumerator->name = attr_string(die, DW_AT_name, conf);
enumerator->value = attr_numeric(die, DW_AT_const_value);
}
@@ -560,6 +667,7 @@ static enum vscope dwarf__location(Dwarf_Die *die, uint64_t *addr, struct locati
Dwarf_Op *expr = location->expr;
switch (expr->atom) {
case DW_OP_addr:
+ case DW_OP_addrx:
scope = VSCOPE_GLOBAL;
*addr = expr[0].number;
break;
@@ -592,7 +700,7 @@ const char *variable__scope_str(const struct variable *var)
return "unknown";
}
-static struct variable *variable__new(Dwarf_Die *die, struct cu *cu)
+static struct variable *variable__new(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
struct variable *var;
bool has_specification;
@@ -606,12 +714,14 @@ static struct variable *variable__new(Dwarf_Die *die, struct cu *cu)
if (var != NULL) {
tag__init(&var->ip.tag, cu, die);
- var->name = strings__add(strings, attr_string(die, DW_AT_name));
+ var->name = attr_string(die, DW_AT_name, conf);
/* variable is visible outside of its enclosing cu */
var->external = dwarf_hasattr(die, DW_AT_external);
/* non-defining declaration of an object */
var->declaration = dwarf_hasattr(die, DW_AT_declaration);
+ var->has_specification = has_specification;
var->scope = VSCOPE_UNKNOWN;
+ INIT_LIST_HEAD(&var->annots);
var->ip.addr = 0;
if (!var->declaration && cu->has_addr_info)
var->scope = dwarf__location(die, &var->ip.addr, &var->location);
@@ -630,21 +740,25 @@ static int tag__recode_dwarf_bitfield(struct tag *tag, struct cu *cu, uint16_t b
type_id_t short_id;
struct tag *recoded;
/* in all the cases the name is at the same offset */
- strings_t name = tag__namespace(tag)->name;
+ const char *name = namespace__name(tag__namespace(tag));
switch (tag->tag) {
case DW_TAG_typedef: {
const struct dwarf_tag *dtag = tag->priv;
- struct dwarf_tag *dtype = dwarf_cu__find_type_by_ref(cu->priv,
- &dtag->type);
+ struct dwarf_tag *dtype = dwarf_cu__find_type_by_ref(cu->priv, &dtag->type);
+
+ if (dtype == NULL) {
+ tag__print_type_not_found(tag);
+ return -ENOENT;
+ }
+
struct tag *type = dtype->tag;
id = tag__recode_dwarf_bitfield(type, cu, bit_size);
if (id < 0)
return id;
- struct type *new_typedef = obstack_zalloc(&cu->obstack,
- sizeof(*new_typedef));
+ struct type *new_typedef = cu__zalloc(cu, sizeof(*new_typedef));
if (new_typedef == NULL)
return -ENOMEM;
@@ -659,13 +773,19 @@ static int tag__recode_dwarf_bitfield(struct tag *tag, struct cu *cu, uint16_t b
case DW_TAG_volatile_type: {
const struct dwarf_tag *dtag = tag->priv;
struct dwarf_tag *dtype = dwarf_cu__find_type_by_ref(cu->priv, &dtag->type);
+
+ if (dtype == NULL) {
+ tag__print_type_not_found(tag);
+ return -ENOENT;
+ }
+
struct tag *type = dtype->tag;
id = tag__recode_dwarf_bitfield(type, cu, bit_size);
- if (id == tag->type)
+ if (id >= 0 && (uint32_t)id == tag->type)
return id;
- recoded = obstack_zalloc(&cu->obstack, sizeof(*recoded));
+ recoded = cu__zalloc(cu, sizeof(*recoded));
if (recoded == NULL)
return -ENOMEM;
@@ -680,19 +800,18 @@ static int tag__recode_dwarf_bitfield(struct tag *tag, struct cu *cu, uint16_t b
* the dwarf_cu as in dwarf there are no such things
* as base_types of less than 8 bits, etc.
*/
- recoded = cu__find_base_type_by_sname_and_size(cu, name, bit_size, &short_id);
+ recoded = cu__find_base_type_by_name_and_size(cu, name, bit_size, &short_id);
if (recoded != NULL)
return short_id;
- struct base_type *new_bt = obstack_zalloc(&cu->obstack,
- sizeof(*new_bt));
+ struct base_type *new_bt = cu__zalloc(cu, sizeof(*new_bt));
if (new_bt == NULL)
return -ENOMEM;
recoded = (struct tag *)new_bt;
recoded->tag = DW_TAG_base_type;
recoded->top_level = 1;
- new_bt->name = name;
+ new_bt->name = strdup(name);
new_bt->bit_size = bit_size;
break;
@@ -702,12 +821,12 @@ static int tag__recode_dwarf_bitfield(struct tag *tag, struct cu *cu, uint16_t b
* the dwarf_cu as in dwarf there are no such things
* as enumeration_types of less than 8 bits, etc.
*/
- recoded = cu__find_enumeration_by_sname_and_size(cu, name, bit_size, &short_id);
+ recoded = cu__find_enumeration_by_name_and_size(cu, name, bit_size, &short_id);
if (recoded != NULL)
return short_id;
struct type *alias = tag__type(tag);
- struct type *new_enum = obstack_zalloc(&cu->obstack, sizeof(*new_enum));
+ struct type *new_enum = cu__zalloc(cu, sizeof(*new_enum));
if (new_enum == NULL)
return -ENOMEM;
@@ -720,13 +839,13 @@ static int tag__recode_dwarf_bitfield(struct tag *tag, struct cu *cu, uint16_t b
*/
new_enum->namespace.tags.next = &alias->namespace.tags;
new_enum->namespace.shared_tags = 1;
- new_enum->namespace.name = name;
+ new_enum->namespace.name = strdup(name);
new_enum->size = bit_size;
break;
default:
fprintf(stderr, "%s: tag=%s, name=%s, bit_size=%d\n",
__func__, dwarf_tag_name(tag->tag),
- strings__ptr(strings, name), bit_size);
+ name, bit_size);
return -EINVAL;
}
@@ -734,10 +853,55 @@ static int tag__recode_dwarf_bitfield(struct tag *tag, struct cu *cu, uint16_t b
if (cu__add_tag(cu, recoded, &new_id) == 0)
return new_id;
- obstack_free(&cu->obstack, recoded);
+ free(recoded);
return -ENOMEM;
}
+static int add_llvm_annotation(Dwarf_Die *die, int component_idx, struct conf_load *conf,
+ struct list_head *head)
+{
+ struct llvm_annotation *annot;
+ const char *name;
+
+ if (conf->skip_encoding_btf_decl_tag)
+ return 0;
+
+ /* Only handle btf_decl_tag annotation for now. */
+ name = attr_string(die, DW_AT_name, conf);
+ if (strcmp(name, "btf_decl_tag") != 0)
+ return 0;
+
+ annot = zalloc(sizeof(*annot));
+ if (!annot)
+ return -ENOMEM;
+
+ annot->value = attr_string(die, DW_AT_const_value, conf);
+ annot->component_idx = component_idx;
+ list_add_tail(&annot->node, head);
+ return 0;
+}
+
+static int add_child_llvm_annotations(Dwarf_Die *die, int component_idx,
+ struct conf_load *conf, struct list_head *head)
+{
+ Dwarf_Die child;
+ int ret;
+
+ if (!dwarf_haschildren(die) || dwarf_child(die, &child) != 0)
+ return 0;
+
+ die = &child;
+ do {
+ if (dwarf_tag(die) == DW_TAG_LLVM_annotation) {
+ ret = add_llvm_annotation(die, component_idx, conf, head);
+ if (ret)
+ return ret;
+ }
+ } while (dwarf_siblingof(die, die) == 0);
+
+ return 0;
+}
+
int class_member__dwarf_recode_bitfield(struct class_member *member,
struct cu *cu)
{
@@ -757,58 +921,76 @@ int class_member__dwarf_recode_bitfield(struct class_member *member,
}
static struct class_member *class_member__new(Dwarf_Die *die, struct cu *cu,
- bool in_union)
+ bool in_union, struct conf_load *conf)
{
struct class_member *member = tag__alloc(cu, sizeof(*member));
if (member != NULL) {
tag__init(&member->tag, cu, die);
- member->name = strings__add(strings, attr_string(die, DW_AT_name));
- member->is_static = !in_union && !dwarf_hasattr(die, DW_AT_data_member_location);
- member->const_value = attr_numeric(die, DW_AT_const_value);
- member->alignment = attr_numeric(die, DW_AT_alignment);
- member->byte_offset = attr_offset(die, DW_AT_data_member_location);
- /*
- * Bit offset calculated here is valid only for byte-aligned
- * fields. For bitfields on little-endian archs we need to
- * adjust them taking into account byte size of the field,
- * which might not be yet known. So we'll re-calculate bit
- * offset later, in class_member__cache_byte_size.
- */
- member->bit_offset = member->byte_offset * 8;
+ member->name = attr_string(die, DW_AT_name, conf);
+ member->alignment = attr_alignment(die, conf);
+
+ Dwarf_Attribute attr;
+
+ member->has_bit_offset = dwarf_attr(die, DW_AT_data_bit_offset, &attr) != NULL;
+
+ if (member->has_bit_offset) {
+ member->bit_offset = __attr_offset(&attr);
+ // byte_offset and bitfield_offset will be recalculated later, when
+ // we discover the size of this bitfield base type.
+ } else {
+ if (dwarf_attr(die, DW_AT_data_member_location, &attr) != NULL) {
+ member->byte_offset = __attr_offset(&attr);
+ } else {
+ member->is_static = !in_union;
+ }
+
+ /*
+ * Bit offset calculated here is valid only for byte-aligned
+ * fields. For bitfields on little-endian archs we need to
+ * adjust them taking into account byte size of the field,
+ * which might not be yet known. So we'll re-calculate bit
+ * offset later, in class_member__cache_byte_size.
+ */
+ member->bit_offset = member->byte_offset * 8;
+ member->bitfield_offset = attr_numeric(die, DW_AT_bit_offset);
+ }
+
/*
* If DW_AT_byte_size is not present, byte size will be
* determined later in class_member__cache_byte_size using
* base integer/enum type
*/
member->byte_size = attr_numeric(die, DW_AT_byte_size);
- member->bitfield_offset = attr_numeric(die, DW_AT_bit_offset);
member->bitfield_size = attr_numeric(die, DW_AT_bit_size);
member->bit_hole = 0;
member->bitfield_end = 0;
member->visited = 0;
- member->accessibility = attr_numeric(die, DW_AT_accessibility);
- member->virtuality = attr_numeric(die, DW_AT_virtuality);
+
+ if (!cu__is_c(cu)) {
+ member->accessibility = attr_numeric(die, DW_AT_accessibility);
+ member->const_value = attr_numeric(die, DW_AT_const_value);
+ member->virtuality = attr_numeric(die, DW_AT_virtuality);
+ }
member->hole = 0;
}
return member;
}
-static struct parameter *parameter__new(Dwarf_Die *die, struct cu *cu)
+static struct parameter *parameter__new(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
struct parameter *parm = tag__alloc(cu, sizeof(*parm));
if (parm != NULL) {
tag__init(&parm->tag, cu, die);
- parm->name = strings__add(strings, attr_string(die, DW_AT_name));
+ parm->name = attr_string(die, DW_AT_name, conf);
}
return parm;
}
-static struct inline_expansion *inline_expansion__new(Dwarf_Die *die,
- struct cu *cu)
+static struct inline_expansion *inline_expansion__new(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
struct inline_expansion *exp = tag__alloc(cu, sizeof(*exp));
@@ -816,8 +998,7 @@ static struct inline_expansion *inline_expansion__new(Dwarf_Die *die,
struct dwarf_tag *dtag = exp->ip.tag.priv;
tag__init(&exp->ip.tag, cu, die);
- dtag->decl_file =
- strings__add(strings, attr_string(die, DW_AT_call_file));
+ dtag->decl_file = attr_string(die, DW_AT_call_file, conf);
dtag->decl_line = attr_numeric(die, DW_AT_call_line);
dtag->type = attr_type(die, DW_AT_abstract_origin);
exp->ip.addr = 0;
@@ -853,13 +1034,13 @@ out:
return exp;
}
-static struct label *label__new(Dwarf_Die *die, struct cu *cu)
+static struct label *label__new(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
struct label *label = tag__alloc(cu, sizeof(*label));
if (label != NULL) {
tag__init(&label->ip.tag, cu, die);
- label->name = strings__add(strings, attr_string(die, DW_AT_name));
+ label->name = attr_string(die, DW_AT_name, conf);
if (!cu->has_addr_info || dwarf_lowpc(die, &label->ip.addr))
label->ip.addr = 0;
}
@@ -867,12 +1048,12 @@ static struct label *label__new(Dwarf_Die *die, struct cu *cu)
return label;
}
-static struct class *class__new(Dwarf_Die *die, struct cu *cu)
+static struct class *class__new(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
struct class *class = tag__alloc_with_spec(cu, sizeof(*class));
if (class != NULL) {
- type__init(&class->type, die, cu);
+ type__init(&class->type, die, cu, conf);
INIT_LIST_HEAD(&class->vtable);
class->nr_vtable_entries =
class->nr_holes =
@@ -921,9 +1102,10 @@ static struct lexblock *lexblock__new(Dwarf_Die *die, struct cu *cu)
static void ftype__init(struct ftype *ftype, Dwarf_Die *die, struct cu *cu)
{
+#ifndef NDEBUG
const uint16_t tag = dwarf_tag(die);
assert(tag == DW_TAG_subprogram || tag == DW_TAG_subroutine_type);
-
+#endif
tag__init(&ftype->tag, cu, die);
INIT_LIST_HEAD(&ftype->parms);
ftype->nr_parms = 0;
@@ -940,15 +1122,15 @@ static struct ftype *ftype__new(Dwarf_Die *die, struct cu *cu)
return ftype;
}
-static struct function *function__new(Dwarf_Die *die, struct cu *cu)
+static struct function *function__new(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
struct function *func = tag__alloc_with_spec(cu, sizeof(*func));
if (func != NULL) {
ftype__init(&func->proto, die, cu);
lexblock__init(&func->lexblock, cu, die);
- func->name = strings__add(strings, attr_string(die, DW_AT_name));
- func->linkage_name = strings__add(strings, attr_string(die, DW_AT_MIPS_linkage_name));
+ func->name = attr_string(die, DW_AT_name, conf);
+ func->linkage_name = attr_string(die, DW_AT_MIPS_linkage_name, conf);
func->inlined = attr_numeric(die, DW_AT_inline);
func->declaration = dwarf_hasattr(die, DW_AT_declaration);
func->external = dwarf_hasattr(die, DW_AT_external);
@@ -958,6 +1140,7 @@ static struct function *function__new(Dwarf_Die *die, struct cu *cu)
func->accessibility = attr_numeric(die, DW_AT_accessibility);
func->virtuality = attr_numeric(die, DW_AT_virtuality);
INIT_LIST_HEAD(&func->vtable_node);
+ INIT_LIST_HEAD(&func->annots);
INIT_LIST_HEAD(&func->tool_node);
func->vtable_entry = -1;
if (dwarf_hasattr(die, DW_AT_vtable_elem_location))
@@ -1005,10 +1188,10 @@ static struct tag unsupported_tag;
#define cu__tag_not_handled(die) __cu__tag_not_handled(die, __FUNCTION__)
static struct tag *__die__process_tag(Dwarf_Die *die, struct cu *cu,
- int toplevel, const char *fn);
+ int toplevel, const char *fn, struct conf_load *conf);
-#define die__process_tag(die, cu, toplevel) \
- __die__process_tag(die, cu, toplevel, __FUNCTION__)
+#define die__process_tag(die, cu, toplevel, conf_load) \
+ __die__process_tag(die, cu, toplevel, __FUNCTION__, conf_load)
static struct tag *die__create_new_tag(Dwarf_Die *die, struct cu *cu)
{
@@ -1023,6 +1206,89 @@ static struct tag *die__create_new_tag(Dwarf_Die *die, struct cu *cu)
return tag;
}
+static struct btf_type_tag_ptr_type *die__create_new_btf_type_tag_ptr_type(Dwarf_Die *die, struct cu *cu)
+{
+ struct btf_type_tag_ptr_type *tag;
+
+ tag = tag__alloc_with_spec(cu, sizeof(struct btf_type_tag_ptr_type));
+ if (tag == NULL)
+ return NULL;
+
+ tag__init(&tag->tag, cu, die);
+ tag->tag.has_btf_type_tag = true;
+ INIT_LIST_HEAD(&tag->tags);
+ return tag;
+}
+
+static struct btf_type_tag_type *die__create_new_btf_type_tag_type(Dwarf_Die *die, struct cu *cu,
+ struct conf_load *conf)
+{
+ struct btf_type_tag_type *tag;
+
+ tag = tag__alloc_with_spec(cu, sizeof(struct btf_type_tag_type));
+ if (tag == NULL)
+ return NULL;
+
+ tag__init(&tag->tag, cu, die);
+ tag->value = attr_string(die, DW_AT_const_value, conf);
+ return tag;
+}
+
+static struct tag *die__create_new_pointer_tag(Dwarf_Die *die, struct cu *cu,
+ struct conf_load *conf)
+{
+ struct btf_type_tag_ptr_type *tag = NULL;
+ struct btf_type_tag_type *annot;
+ Dwarf_Die *cdie, child;
+ const char *name;
+ uint32_t id;
+
+ /* If no child tags or skipping btf_type_tag encoding, just create a new tag
+ * and return
+ */
+ if (!dwarf_haschildren(die) || dwarf_child(die, &child) != 0 ||
+ conf->skip_encoding_btf_type_tag)
+ return tag__new(die, cu);
+
+ /* Otherwise, check DW_TAG_LLVM_annotation child tags */
+ cdie = &child;
+ do {
+ if (dwarf_tag(cdie) != DW_TAG_LLVM_annotation)
+ continue;
+
+ /* Only check btf_type_tag annotations */
+ name = attr_string(cdie, DW_AT_name, conf);
+ if (strcmp(name, "btf_type_tag") != 0)
+ continue;
+
+ if (tag == NULL) {
+ /* Create a btf_type_tag_ptr type. */
+ tag = die__create_new_btf_type_tag_ptr_type(die, cu);
+ if (!tag)
+ return NULL;
+ }
+
+ /* Create a btf_type_tag type for this annotation. */
+ annot = die__create_new_btf_type_tag_type(cdie, cu, conf);
+ if (annot == NULL)
+ return NULL;
+
+ if (cu__table_add_tag(cu, &annot->tag, &id) < 0)
+ return NULL;
+
+ struct dwarf_tag *dtag = annot->tag.priv;
+ dtag->small_id = id;
+ cu__hash(cu, &annot->tag);
+
+ /* For a list of DW_TAG_LLVM_annotation like tag1 -> tag2 -> tag3,
+ * the tag->tags contains tag3 -> tag2 -> tag1.
+ */
+ list_add(&annot->node, &tag->tags);
+ } while (dwarf_siblingof(cdie, cdie) == 0);
+
+ return tag ? &tag->tag : tag__new(die, cu);
+}
+
static struct tag *die__create_new_ptr_to_member_type(Dwarf_Die *die,
struct cu *cu)
{
@@ -1032,18 +1298,18 @@ static struct tag *die__create_new_ptr_to_member_type(Dwarf_Die *die,
}
static int die__process_class(Dwarf_Die *die,
- struct type *class, struct cu *cu);
+ struct type *class, struct cu *cu, struct conf_load *conf);
-static struct tag *die__create_new_class(Dwarf_Die *die, struct cu *cu)
+static struct tag *die__create_new_class(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
Dwarf_Die child;
- struct class *class = class__new(die, cu);
+ struct class *class = class__new(die, cu, conf);
if (class != NULL &&
dwarf_haschildren(die) != 0 &&
dwarf_child(die, &child) == 0) {
- if (die__process_class(&child, &class->type, cu) != 0) {
- class__delete(class, cu);
+ if (die__process_class(&child, &class->type, cu, conf) != 0) {
+ class__delete(class);
class = NULL;
}
}
@@ -1052,18 +1318,18 @@ static struct tag *die__create_new_class(Dwarf_Die *die, struct cu *cu)
}
static int die__process_namespace(Dwarf_Die *die, struct namespace *namespace,
- struct cu *cu);
+ struct cu *cu, struct conf_load *conf);
-static struct tag *die__create_new_namespace(Dwarf_Die *die, struct cu *cu)
+static struct tag *die__create_new_namespace(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
Dwarf_Die child;
- struct namespace *namespace = namespace__new(die, cu);
+ struct namespace *namespace = namespace__new(die, cu, conf);
if (namespace != NULL &&
dwarf_haschildren(die) != 0 &&
dwarf_child(die, &child) == 0) {
- if (die__process_namespace(&child, namespace, cu) != 0) {
- namespace__delete(namespace, cu);
+ if (die__process_namespace(&child, namespace, cu, conf) != 0) {
+ namespace__delete(namespace);
namespace = NULL;
}
}
@@ -1071,16 +1337,16 @@ static struct tag *die__create_new_namespace(Dwarf_Die *die, struct cu *cu)
return namespace ? &namespace->tag : NULL;
}
-static struct tag *die__create_new_union(Dwarf_Die *die, struct cu *cu)
+static struct tag *die__create_new_union(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
Dwarf_Die child;
- struct type *utype = type__new(die, cu);
+ struct type *utype = type__new(die, cu, conf);
if (utype != NULL &&
dwarf_haschildren(die) != 0 &&
dwarf_child(die, &child) == 0) {
- if (die__process_class(&child, utype, cu) != 0) {
- type__delete(utype, cu);
+ if (die__process_class(&child, utype, cu, conf) != 0) {
+ type__delete(utype);
utype = NULL;
}
}
@@ -1088,9 +1354,9 @@ static struct tag *die__create_new_union(Dwarf_Die *die, struct cu *cu)
return utype ? &utype->namespace.tag : NULL;
}
-static struct tag *die__create_new_base_type(Dwarf_Die *die, struct cu *cu)
+static struct tag *die__create_new_base_type(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
- struct base_type *base = base_type__new(die, cu);
+ struct base_type *base = base_type__new(die, cu, conf);
if (base == NULL)
return NULL;
@@ -1102,18 +1368,15 @@ static struct tag *die__create_new_base_type(Dwarf_Die *die, struct cu *cu)
return &base->tag;
}
-static struct tag *die__create_new_typedef(Dwarf_Die *die, struct cu *cu)
+static struct tag *die__create_new_typedef(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
- struct type *tdef = type__new(die, cu);
+ struct type *tdef = type__new(die, cu, conf);
if (tdef == NULL)
return NULL;
- if (dwarf_haschildren(die)) {
- struct dwarf_tag *dtag = tdef->namespace.tag.priv;
- fprintf(stderr, "%s: DW_TAG_typedef %llx WITH children!\n",
- __func__, (unsigned long long)dtag->id);
- }
+ if (add_child_llvm_annotations(die, -1, conf, &tdef->namespace.annots))
+ return NULL;
return &tdef->namespace.tag;
}
@@ -1153,7 +1416,7 @@ static struct tag *die__create_new_array(Dwarf_Die *die, struct cu *cu)
return &array->tag;
out_free:
- obstack_free(&cu->obstack, array);
+ free(array);
return NULL;
}
@@ -1170,16 +1433,21 @@ static struct tag *die__create_new_string_type(Dwarf_Die *die, struct cu *cu)
static struct tag *die__create_new_parameter(Dwarf_Die *die,
struct ftype *ftype,
struct lexblock *lexblock,
- struct cu *cu)
+ struct cu *cu, struct conf_load *conf,
+ int param_idx)
{
- struct parameter *parm = parameter__new(die, cu);
+ struct parameter *parm = parameter__new(die, cu, conf);
if (parm == NULL)
return NULL;
- if (ftype != NULL)
+ if (ftype != NULL) {
ftype__add_parameter(ftype, parm);
- else {
+ if (param_idx >= 0) {
+ if (add_child_llvm_annotations(die, param_idx, conf, &(tag__function(&ftype->tag)->annots)))
+ return NULL;
+ }
+ } else {
/*
* DW_TAG_formal_parameters on a non DW_TAG_subprogram nor
* DW_TAG_subroutine_type tag happens sometimes, likely due to
@@ -1197,9 +1465,9 @@ static struct tag *die__create_new_parameter(Dwarf_Die *die,
static struct tag *die__create_new_label(Dwarf_Die *die,
struct lexblock *lexblock,
- struct cu *cu)
+ struct cu *cu, struct conf_load *conf)
{
- struct label *label = label__new(die, cu);
+ struct label *label = label__new(die, cu, conf);
if (label == NULL)
return NULL;
@@ -1208,15 +1476,18 @@ static struct tag *die__create_new_label(Dwarf_Die *die,
return &label->ip.tag;
}
-static struct tag *die__create_new_variable(Dwarf_Die *die, struct cu *cu)
+static struct tag *die__create_new_variable(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
- struct variable *var = variable__new(die, cu);
+ struct variable *var = variable__new(die, cu, conf);
+
+ if (var == NULL || add_child_llvm_annotations(die, -1, conf, &var->annots))
+ return NULL;
- return var ? &var->ip.tag : NULL;
+ return &var->ip.tag;
}
static struct tag *die__create_new_subroutine_type(Dwarf_Die *die,
- struct cu *cu)
+ struct cu *cu, struct conf_load *conf)
{
Dwarf_Die child;
struct ftype *ftype = ftype__new(die, cu);
@@ -1237,13 +1508,13 @@ static struct tag *die__create_new_subroutine_type(Dwarf_Die *die,
tag__print_not_supported(dwarf_tag(die));
continue;
case DW_TAG_formal_parameter:
- tag = die__create_new_parameter(die, ftype, NULL, cu);
+ tag = die__create_new_parameter(die, ftype, NULL, cu, conf, -1);
break;
case DW_TAG_unspecified_parameters:
ftype->unspec_parms = 1;
continue;
default:
- tag = die__process_tag(die, cu, 0);
+ tag = die__process_tag(die, cu, 0, conf);
if (tag == NULL)
goto out_delete;
@@ -1271,16 +1542,16 @@ hash:
out:
return &ftype->tag;
out_delete_tag:
- tag__delete(tag, cu);
+ tag__delete(tag);
out_delete:
- ftype__delete(ftype, cu);
+ ftype__delete(ftype);
return NULL;
}
-static struct tag *die__create_new_enumeration(Dwarf_Die *die, struct cu *cu)
+static struct tag *die__create_new_enumeration(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
Dwarf_Die child;
- struct type *enumeration = type__new(die, cu);
+ struct type *enumeration = type__new(die, cu, conf);
if (enumeration == NULL)
return NULL;
@@ -1304,7 +1575,7 @@ static struct tag *die__create_new_enumeration(Dwarf_Die *die, struct cu *cu)
cu__tag_not_handled(die);
continue;
}
- enumerator = enumerator__new(die, cu);
+ enumerator = enumerator__new(die, cu, conf);
if (enumerator == NULL)
goto out_delete;
@@ -1313,14 +1584,15 @@ static struct tag *die__create_new_enumeration(Dwarf_Die *die, struct cu *cu)
out:
return &enumeration->namespace.tag;
out_delete:
- enumeration__delete(enumeration, cu);
+ enumeration__delete(enumeration);
return NULL;
}
static int die__process_class(Dwarf_Die *die, struct type *class,
- struct cu *cu)
+ struct cu *cu, struct conf_load *conf)
{
const bool is_union = tag__is_union(&class->namespace.tag);
+ int member_idx = 0;
do {
switch (dwarf_tag(die)) {
@@ -1344,7 +1616,7 @@ static int die__process_class(Dwarf_Die *die, struct type *class,
continue;
case DW_TAG_inheritance:
case DW_TAG_member: {
- struct class_member *member = class_member__new(die, cu, is_union);
+ struct class_member *member = class_member__new(die, cu, is_union, conf);
if (member == NULL)
return -ENOMEM;
@@ -1353,7 +1625,7 @@ static int die__process_class(Dwarf_Die *die, struct type *class,
uint32_t id;
if (cu__table_add_tag(cu, &member->tag, &id) < 0) {
- class_member__delete(member, cu);
+ class_member__delete(member);
return -ENOMEM;
}
@@ -1363,10 +1635,17 @@ static int die__process_class(Dwarf_Die *die, struct type *class,
type__add_member(class, member);
cu__hash(cu, &member->tag);
+ if (add_child_llvm_annotations(die, member_idx, conf, &class->namespace.annots))
+ return -ENOMEM;
+ member_idx++;
}
continue;
+ case DW_TAG_LLVM_annotation:
+ if (add_llvm_annotation(die, -1, conf, &class->namespace.annots))
+ return -ENOMEM;
+ continue;
default: {
- struct tag *tag = die__process_tag(die, cu, 0);
+ struct tag *tag = die__process_tag(die, cu, 0, conf);
if (tag == NULL)
return -ENOMEM;
@@ -1379,7 +1658,7 @@ static int die__process_class(Dwarf_Die *die, struct type *class,
uint32_t id;
if (cu__table_add_tag(cu, tag, &id) < 0) {
- tag__delete(tag, cu);
+ tag__delete(tag);
return -ENOMEM;
}
@@ -1403,11 +1682,11 @@ static int die__process_class(Dwarf_Die *die, struct type *class,
}
static int die__process_namespace(Dwarf_Die *die, struct namespace *namespace,
- struct cu *cu)
+ struct cu *cu, struct conf_load *conf)
{
struct tag *tag;
do {
- tag = die__process_tag(die, cu, 0);
+ tag = die__process_tag(die, cu, 0, conf);
if (tag == NULL)
goto out_enomem;
@@ -1429,36 +1708,36 @@ static int die__process_namespace(Dwarf_Die *die, struct namespace *namespace,
return 0;
out_delete_tag:
- tag__delete(tag, cu);
+ tag__delete(tag);
out_enomem:
return -ENOMEM;
}
static int die__process_function(Dwarf_Die *die, struct ftype *ftype,
- struct lexblock *lexblock, struct cu *cu);
+ struct lexblock *lexblock, struct cu *cu, struct conf_load *conf);
static int die__create_new_lexblock(Dwarf_Die *die,
- struct cu *cu, struct lexblock *father)
+ struct cu *cu, struct lexblock *father, struct conf_load *conf)
{
struct lexblock *lexblock = lexblock__new(die, cu);
if (lexblock != NULL) {
- if (die__process_function(die, NULL, lexblock, cu) != 0)
+ if (die__process_function(die, NULL, lexblock, cu, conf) != 0)
goto out_delete;
}
if (father != NULL)
lexblock__add_lexblock(father, lexblock);
return 0;
out_delete:
- lexblock__delete(lexblock, cu);
+ lexblock__delete(lexblock);
return -ENOMEM;
}
static struct tag *die__create_new_inline_expansion(Dwarf_Die *die,
struct lexblock *lexblock,
- struct cu *cu);
+ struct cu *cu, struct conf_load *conf);
-static int die__process_inline_expansion(Dwarf_Die *die, struct lexblock *lexblock, struct cu *cu)
+static int die__process_inline_expansion(Dwarf_Die *die, struct lexblock *lexblock, struct cu *cu, struct conf_load *conf)
{
Dwarf_Die child;
struct tag *tag;
@@ -1471,6 +1750,8 @@ static int die__process_inline_expansion(Dwarf_Die *die, struct lexblock *lexblo
uint32_t id;
switch (dwarf_tag(die)) {
+ case DW_TAG_call_site:
+ case DW_TAG_call_site_parameter:
case DW_TAG_GNU_call_site:
case DW_TAG_GNU_call_site_parameter:
/*
@@ -1484,7 +1765,7 @@ static int die__process_inline_expansion(Dwarf_Die *die, struct lexblock *lexblo
*/
continue;
case DW_TAG_lexical_block:
- if (die__create_new_lexblock(die, cu, lexblock) != 0)
+ if (die__create_new_lexblock(die, cu, lexblock, conf) != 0)
goto out_enomem;
continue;
case DW_TAG_formal_parameter:
@@ -1501,13 +1782,15 @@ static int die__process_inline_expansion(Dwarf_Die *die, struct lexblock *lexblo
*/
continue;
case DW_TAG_inlined_subroutine:
- tag = die__create_new_inline_expansion(die, lexblock, cu);
+ tag = die__create_new_inline_expansion(die, lexblock, cu, conf);
break;
case DW_TAG_label:
- tag = die__create_new_label(die, lexblock, cu);
+ if (conf->ignore_labels)
+ continue;
+ tag = die__create_new_label(die, lexblock, cu, conf);
break;
default:
- tag = die__process_tag(die, cu, 0);
+ tag = die__process_tag(die, cu, 0, conf);
if (tag == NULL)
goto out_enomem;
@@ -1534,22 +1817,22 @@ hash:
return 0;
out_delete_tag:
- tag__delete(tag, cu);
+ tag__delete(tag);
out_enomem:
return -ENOMEM;
}
static struct tag *die__create_new_inline_expansion(Dwarf_Die *die,
struct lexblock *lexblock,
- struct cu *cu)
+ struct cu *cu, struct conf_load *conf)
{
- struct inline_expansion *exp = inline_expansion__new(die, cu);
+ struct inline_expansion *exp = inline_expansion__new(die, cu, conf);
if (exp == NULL)
return NULL;
- if (die__process_inline_expansion(die, lexblock, cu) != 0) {
- obstack_free(&cu->obstack, exp);
+ if (die__process_inline_expansion(die, lexblock, cu, conf) != 0) {
+ free(exp);
return NULL;
}
@@ -1559,8 +1842,9 @@ static struct tag *die__create_new_inline_expansion(Dwarf_Die *die,
}
static int die__process_function(Dwarf_Die *die, struct ftype *ftype,
- struct lexblock *lexblock, struct cu *cu)
+ struct lexblock *lexblock, struct cu *cu, struct conf_load *conf)
{
+ int param_idx = 0;
Dwarf_Die child;
struct tag *tag;
@@ -1572,6 +1856,8 @@ static int die__process_function(Dwarf_Die *die, struct ftype *ftype,
uint32_t id;
switch (dwarf_tag(die)) {
+ case DW_TAG_call_site:
+ case DW_TAG_call_site_parameter:
case DW_TAG_GNU_call_site:
case DW_TAG_GNU_call_site_parameter:
/*
@@ -1602,10 +1888,10 @@ static int die__process_function(Dwarf_Die *die, struct ftype *ftype,
tag__print_not_supported(dwarf_tag(die));
continue;
case DW_TAG_formal_parameter:
- tag = die__create_new_parameter(die, ftype, lexblock, cu);
+ tag = die__create_new_parameter(die, ftype, lexblock, cu, conf, param_idx++);
break;
case DW_TAG_variable:
- tag = die__create_new_variable(die, cu);
+ tag = die__create_new_variable(die, cu, conf);
if (tag == NULL)
goto out_enomem;
lexblock__add_variable(lexblock, tag__variable(tag));
@@ -1615,17 +1901,28 @@ static int die__process_function(Dwarf_Die *die, struct ftype *ftype,
ftype->unspec_parms = 1;
continue;
case DW_TAG_label:
- tag = die__create_new_label(die, lexblock, cu);
+ if (conf->ignore_labels)
+ continue;
+ tag = die__create_new_label(die, lexblock, cu, conf);
break;
case DW_TAG_inlined_subroutine:
- tag = die__create_new_inline_expansion(die, lexblock, cu);
+ if (conf->ignore_inline_expansions)
+ continue;
+ tag = die__create_new_inline_expansion(die, lexblock, cu, conf);
break;
case DW_TAG_lexical_block:
- if (die__create_new_lexblock(die, cu, lexblock) != 0)
+ // lexblocks can contain types that are then referenced from outside.
+ // Thus we can't ignore them without more surgery, i.e. by adding code
+ // to just process types inside lexblocks, leave this for later.
+ if (die__create_new_lexblock(die, cu, lexblock, conf) != 0)
+ goto out_enomem;
+ continue;
+ case DW_TAG_LLVM_annotation:
+ if (add_llvm_annotation(die, -1, conf, &(tag__function(&ftype->tag)->annots)))
goto out_enomem;
continue;
default:
- tag = die__process_tag(die, cu, 0);
+ tag = die__process_tag(die, cu, 0, conf);
if (tag == NULL)
goto out_enomem;
@@ -1654,19 +1951,18 @@ hash:
return 0;
out_delete_tag:
- tag__delete(tag, cu);
+ tag__delete(tag);
out_enomem:
return -ENOMEM;
}
-static struct tag *die__create_new_function(Dwarf_Die *die, struct cu *cu)
+static struct tag *die__create_new_function(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
- struct function *function = function__new(die, cu);
+ struct function *function = function__new(die, cu, conf);
if (function != NULL &&
- die__process_function(die, &function->proto,
- &function->lexblock, cu) != 0) {
- function__delete(function, cu);
+ die__process_function(die, &function->proto, &function->lexblock, cu, conf) != 0) {
+ function__delete(function);
function = NULL;
}
@@ -1674,7 +1970,7 @@ static struct tag *die__create_new_function(Dwarf_Die *die, struct cu *cu)
}
static struct tag *__die__process_tag(Dwarf_Die *die, struct cu *cu,
- int top_level, const char *fn)
+ int top_level, const char *fn, struct conf_load *conf)
{
struct tag *tag;
@@ -1686,37 +1982,38 @@ static struct tag *__die__process_tag(Dwarf_Die *die, struct cu *cu,
case DW_TAG_string_type: // FORTRAN stuff, looks like an array
tag = die__create_new_string_type(die, cu); break;
case DW_TAG_base_type:
- tag = die__create_new_base_type(die, cu); break;
+ tag = die__create_new_base_type(die, cu, conf); break;
case DW_TAG_const_type:
case DW_TAG_imported_declaration:
case DW_TAG_imported_module:
- case DW_TAG_pointer_type:
case DW_TAG_reference_type:
case DW_TAG_restrict_type:
case DW_TAG_unspecified_type:
case DW_TAG_volatile_type:
tag = die__create_new_tag(die, cu); break;
+ case DW_TAG_pointer_type:
+ tag = die__create_new_pointer_tag(die, cu, conf); break;
case DW_TAG_ptr_to_member_type:
tag = die__create_new_ptr_to_member_type(die, cu); break;
case DW_TAG_enumeration_type:
- tag = die__create_new_enumeration(die, cu); break;
+ tag = die__create_new_enumeration(die, cu, conf); break;
case DW_TAG_namespace:
- tag = die__create_new_namespace(die, cu); break;
+ tag = die__create_new_namespace(die, cu, conf); break;
case DW_TAG_class_type:
case DW_TAG_interface_type:
case DW_TAG_structure_type:
- tag = die__create_new_class(die, cu); break;
+ tag = die__create_new_class(die, cu, conf); break;
case DW_TAG_subprogram:
- tag = die__create_new_function(die, cu); break;
+ tag = die__create_new_function(die, cu, conf); break;
case DW_TAG_subroutine_type:
- tag = die__create_new_subroutine_type(die, cu); break;
+ tag = die__create_new_subroutine_type(die, cu, conf); break;
case DW_TAG_rvalue_reference_type:
case DW_TAG_typedef:
- tag = die__create_new_typedef(die, cu); break;
+ tag = die__create_new_typedef(die, cu, conf); break;
case DW_TAG_union_type:
- tag = die__create_new_union(die, cu); break;
+ tag = die__create_new_union(die, cu, conf); break;
case DW_TAG_variable:
- tag = die__create_new_variable(die, cu); break;
+ tag = die__create_new_variable(die, cu, conf); break;
default:
__cu__tag_not_handled(die, fn);
/* fall thru */
@@ -1734,10 +2031,10 @@ static struct tag *__die__process_tag(Dwarf_Die *die, struct cu *cu,
return tag;
}
-static int die__process_unit(Dwarf_Die *die, struct cu *cu)
+static int die__process_unit(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
do {
- struct tag *tag = die__process_tag(die, cu, 1);
+ struct tag *tag = die__process_tag(die, cu, 1, conf);
if (tag == NULL)
return -ENOMEM;
@@ -1759,17 +2056,6 @@ static int die__process_unit(Dwarf_Die *die, struct cu *cu)
return 0;
}
-static void __tag__print_type_not_found(struct tag *tag, const char *func)
-{
- struct dwarf_tag *dtag = tag->priv;
- fprintf(stderr, "%s: couldn't find %#llx type for %#llx (%s)!\n", func,
- (unsigned long long)dtag->type.off, (unsigned long long)dtag->id,
- dwarf_tag_name(tag->tag));
-}
-
-#define tag__print_type_not_found(tag) \
- __tag__print_type_not_found(tag, __func__)
-
static void ftype__recode_dwarf_types(struct tag *tag, struct cu *cu);
static int namespace__recode_dwarf_types(struct tag *tag, struct cu *cu)
@@ -1990,6 +2276,45 @@ static void lexblock__recode_dwarf_types(struct lexblock *tag, struct cu *cu)
}
}
+static void dwarf_cu__recode_btf_type_tag_ptr(struct btf_type_tag_ptr_type *tag,
+ uint32_t pointee_type)
+{
+ struct btf_type_tag_type *annot;
+ struct dwarf_tag *annot_dtag;
+ struct tag *prev_tag;
+
+ /* Given source like
+ * int tag1 tag2 tag3 *p;
+ * the tag->tags contains tag3 -> tag2 -> tag1, the final type chain looks like:
+ * pointer -> tag3 -> tag2 -> tag1 -> pointee
+ *
+ * Basically it means
+ * - '*' applies to "int tag1 tag2 tag3"
+ * - tag3 applies to "int tag1 tag2"
+ * - tag2 applies to "int tag1"
+ * - tag1 applies to "int"
+ *
+ * This also makes final source code (format c) easier as we can do
+ * emit for "tag3 -> tag2 -> tag1 -> int"
+ * emit '*'
+ *
+ * For 'tag3 -> tag2 -> tag1 -> int":
+ * emit for "tag2 -> tag1 -> int"
+ * emit tag3
+ *
+ * Eventually we can get the source code like
+ * int tag1 tag2 tag3 *p;
+ * and this matches the user/kernel code.
+ */
+ prev_tag = &tag->tag;
+ list_for_each_entry(annot, &tag->tags, node) {
+ annot_dtag = annot->tag.priv;
+ prev_tag->type = annot_dtag->small_id;
+ prev_tag = &annot->tag;
+ }
+ prev_tag->type = pointee_type;
+}
+
static int tag__recode_dwarf_type(struct tag *tag, struct cu *cu)
{
struct dwarf_tag *dtag = tag->priv;
@@ -2083,19 +2408,26 @@ static int tag__recode_dwarf_type(struct tag *tag, struct cu *cu)
goto find_type;
case DW_TAG_variable: {
struct variable *var = tag__variable(tag);
- dwarf_off_ref specification = dwarf_tag__spec(dtag);
- if (specification.off) {
- dtype = dwarf_cu__find_tag_by_ref(cu->priv, &specification);
- if (dtype)
- var->spec = tag__variable(dtype->tag);
+ if (var->has_specification) {
+ dwarf_off_ref specification = dwarf_tag__spec(dtag);
+
+ if (specification.off) {
+ dtype = dwarf_cu__find_tag_by_ref(cu->priv,
+ &specification);
+ if (dtype)
+ var->spec = tag__variable(dtype->tag);
+ }
}
}
}
if (dtag->type.off == 0) {
- tag->type = 0; /* void */
+ if (tag->tag != DW_TAG_pointer_type || !tag->has_btf_type_tag)
+ tag->type = 0; /* void */
+ else
+ dwarf_cu__recode_btf_type_tag_ptr(tag__btf_type_tag_ptr(tag), 0);
return 0;
}
@@ -2107,7 +2439,39 @@ check_type:
return 0;
}
out:
- tag->type = dtype->small_id;
+ if (tag->tag != DW_TAG_pointer_type || !tag->has_btf_type_tag)
+ tag->type = dtype->small_id;
+ else
+ dwarf_cu__recode_btf_type_tag_ptr(tag__btf_type_tag_ptr(tag), dtype->small_id);
+
+ return 0;
+}
+
+static int cu__resolve_func_ret_types(struct cu *cu)
+{
+ struct ptr_table *pt = &cu->functions_table;
+ uint32_t i;
+
+ for (i = 0; i < pt->nr_entries; ++i) {
+ struct tag *tag = pt->entries[i];
+
+ if (tag == NULL || tag->type != 0)
+ continue;
+
+ struct function *fn = tag__function(tag);
+ if (!fn->abstract_origin)
+ continue;
+
+ struct dwarf_tag *dtag = tag->priv;
+ struct dwarf_tag *dfunc;
+ dfunc = dwarf_cu__find_tag_by_ref(cu->priv, &dtag->abstract_origin);
+ if (dfunc == NULL) {
+ tag__print_abstract_origin_not_found(tag);
+ return -1;
+ }
+
+ tag->type = dfunc->tag->type;
+ }
return 0;
}
@@ -2138,8 +2502,7 @@ static const char *dwarf_tag__decl_file(const struct tag *tag,
const struct cu *cu)
{
struct dwarf_tag *dtag = tag->priv;
- return cu->extra_dbg_info ?
- strings__ptr(strings, dtag->decl_file) : NULL;
+ return cu->extra_dbg_info ? dtag->decl_file : NULL;
}
static uint32_t dwarf_tag__decl_line(const struct tag *tag,
@@ -2156,19 +2519,24 @@ static unsigned long long dwarf_tag__orig_id(const struct tag *tag,
return cu->extra_dbg_info ? dtag->id : 0;
}
-static const char *dwarf__strings_ptr(const struct cu *cu __unused,
- strings_t s)
-{
- return s ? strings__ptr(strings, s) : NULL;
-}
-
struct debug_fmt_ops dwarf__ops;
-static int die__process(Dwarf_Die *die, struct cu *cu)
+static int die__process(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
Dwarf_Die child;
const uint16_t tag = dwarf_tag(die);
+ if (tag == DW_TAG_skeleton_unit) {
+ static bool warned;
+
+ if (!warned) {
+ fprintf(stderr, "WARNING: DW_TAG_skeleton_unit used, please look for a .dwo file and use it instead.\n"
+ " A future version of pahole will support do this automagically.\n");
+ warned = true;
+ }
+ return 0; // so that other units can be processed
+ }
+
if (tag == DW_TAG_partial_unit) {
static bool warned;
@@ -2182,15 +2550,15 @@ static int die__process(Dwarf_Die *die, struct cu *cu)
}
if (tag != DW_TAG_compile_unit && tag != DW_TAG_type_unit) {
- fprintf(stderr, "%s: DW_TAG_compile_unit, DW_TAG_type_unit or DW_TAG_partial_unit expected got %s!\n",
- __FUNCTION__, dwarf_tag_name(tag));
+ fprintf(stderr, "%s: DW_TAG_compile_unit, DW_TAG_type_unit, DW_TAG_partial_unit or DW_TAG_skeleton_unit expected got %s (0x%x)!\n",
+ __FUNCTION__, dwarf_tag_name(tag), tag);
return -EINVAL;
}
cu->language = attr_numeric(die, DW_AT_language);
if (dwarf_child(die, &child) == 0) {
- int err = die__process_unit(&child, cu);
+ int err = die__process_unit(&child, cu, conf);
if (err)
return err;
}
@@ -2203,12 +2571,16 @@ static int die__process(Dwarf_Die *die, struct cu *cu)
return 0;
}
-static int die__process_and_recode(Dwarf_Die *die, struct cu *cu)
+static int die__process_and_recode(Dwarf_Die *die, struct cu *cu, struct conf_load *conf)
{
- int ret = die__process(die, cu);
+ int ret = die__process(die, cu, conf);
if (ret != 0)
return ret;
- return cu__recode_dwarf_types(cu);
+ ret = cu__recode_dwarf_types(cu);
+ if (ret != 0)
+ return ret;
+
+ return cu__resolve_func_ret_types(cu);
}
static int class_member__cache_byte_size(struct tag *tag, struct cu *cu,
@@ -2250,7 +2622,7 @@ static int class_member__cache_byte_size(struct tag *tag, struct cu *cu,
member->bit_size = member->byte_size * 8;
/*
- * XXX: after all the attemps to determine byte size, we might still
+ * XXX: after all the attempts to determine byte size, we might still
* be unsuccessful, because base_type__name_to_size doesn't know about
* the base_type name, so one has to add there when such base_type
* isn't found. pahole will put zero on the struct output so it should
@@ -2261,24 +2633,31 @@ static int class_member__cache_byte_size(struct tag *tag, struct cu *cu,
return 0;
}
- /*
- * For little-endian architectures, DWARF data emitted by gcc/clang
- * specifies bitfield offset as an offset from the highest-order bit
- * of an underlying integral type (e.g., int) to a highest-order bit
- * of a bitfield. E.g., for bitfield taking first 5 bits of int-backed
- * bitfield, bit offset will be 27 (sizeof(int) - 0 offset - 5 bit
- * size), which is very counter-intuitive and isn't a natural
- * extension of byte offset, which on little-endian points to
- * lowest-order byte. So here we re-adjust bitfield offset to be an
- * offset from lowest-order bit of underlying integral type to
- * a lowest-order bit of a bitfield. This makes bitfield offset
- * a natural extension of byte offset for bitfields and is uniform
- * with how big-endian bit offsets work.
- */
- if (cu->little_endian) {
- member->bitfield_offset = member->bit_size - member->bitfield_offset - member->bitfield_size;
+ if (!member->has_bit_offset) {
+ /*
+ * For little-endian architectures, DWARF data emitted by gcc/clang
+ * specifies bitfield offset as an offset from the highest-order bit
+ * of an underlying integral type (e.g., int) to a highest-order bit
+ * of a bitfield. E.g., for bitfield taking first 5 bits of int-backed
+ * bitfield, bit offset will be 27 (sizeof(int) - 0 offset - 5 bit
+ * size), which is very counter-intuitive and isn't a natural
+ * extension of byte offset, which on little-endian points to
+ * lowest-order byte. So here we re-adjust bitfield offset to be an
+ * offset from lowest-order bit of underlying integral type to
+ * a lowest-order bit of a bitfield. This makes bitfield offset
+ * a natural extension of byte offset for bitfields and is uniform
+ * with how big-endian bit offsets work.
+ */
+ if (cu->little_endian)
+ member->bitfield_offset = member->bit_size - member->bitfield_offset - member->bitfield_size;
+
+ member->bit_offset = member->byte_offset * 8 + member->bitfield_offset;
+ } else {
+ // DWARF5 has DW_AT_data_bit_offset, offset in bits from the
+ // start of the container type (struct, class, etc).
+ member->byte_offset = member->bit_offset / 8;
+ member->bitfield_offset = member->bit_offset - member->byte_offset * 8;
}
- member->bit_offset = member->byte_offset * 8 + member->bitfield_offset;
/* make sure bitfield offset is non-negative */
if (member->bitfield_offset < 0) {
@@ -2303,10 +2682,8 @@ static int class_member__cache_byte_size(struct tag *tag, struct cu *cu,
return 0;
}
-static int finalize_cu(struct cus *cus, struct cu *cu, struct dwarf_cu *dcu,
- struct conf_load *conf)
+static int cu__finalize(struct cu *cu, struct conf_load *conf)
{
- base_type_name_to_size_table__init(strings);
cu__for_all_tags(cu, class_member__cache_byte_size, conf);
if (conf && conf->steal) {
return conf->steal(cu, conf);
@@ -2314,11 +2691,9 @@ static int finalize_cu(struct cus *cus, struct cu *cu, struct dwarf_cu *dcu,
return LSK__KEEPIT;
}
-static int finalize_cu_immediately(struct cus *cus, struct cu *cu,
- struct dwarf_cu *dcu,
- struct conf_load *conf)
+static int cus__finalize(struct cus *cus, struct cu *cu, struct conf_load *conf)
{
- int lsk = finalize_cu(cus, cu, dcu, conf);
+ int lsk = cu__finalize(cu, conf);
switch (lsk) {
case LSK__DELETE:
cu__delete(cu);
@@ -2326,20 +2701,32 @@ static int finalize_cu_immediately(struct cus *cus, struct cu *cu,
case LSK__STOP_LOADING:
break;
case LSK__KEEPIT:
- if (!cu->extra_dbg_info)
- obstack_free(&dcu->obstack, NULL);
cus__add(cus, cu);
break;
}
return lsk;
}
-static int cus__load_debug_types(struct cus *cus, struct conf_load *conf,
- Dwfl_Module *mod, Dwarf *dw, Elf *elf,
- const char *filename,
- const unsigned char *build_id,
- int build_id_len,
- struct cu **cup, struct dwarf_cu *dcup)
+static int cu__set_common(struct cu *cu, struct conf_load *conf,
+ Dwfl_Module *mod, Elf *elf)
+{
+ cu->uses_global_strings = true;
+ cu->elf = elf;
+ cu->dwfl = mod;
+ cu->extra_dbg_info = conf ? conf->extra_dbg_info : 0;
+ cu->has_addr_info = conf ? conf->get_addr_info : 0;
+
+ GElf_Ehdr ehdr;
+ if (gelf_getehdr(elf, &ehdr) == NULL)
+ return DWARF_CB_ABORT;
+
+ cu->little_endian = ehdr.e_ident[EI_DATA] == ELFDATA2LSB;
+ return 0;
+}
+
+static int __cus__load_debug_types(struct conf_load *conf, Dwfl_Module *mod, Dwarf *dw, Elf *elf,
+ const char *filename, const unsigned char *build_id,
+ int build_id_len, struct cu **cup, struct dwarf_cu *dcup)
{
Dwarf_Off off = 0, noff, type_off;
size_t cuhl;
@@ -2356,24 +2743,14 @@ static int cus__load_debug_types(struct cus *cus, struct conf_load *conf,
struct cu *cu;
cu = cu__new("", pointer_size, build_id,
- build_id_len, filename);
- if (cu == NULL) {
+ build_id_len, filename, conf->use_obstack);
+ if (cu == NULL ||
+ cu__set_common(cu, conf, mod, elf) != 0) {
return DWARF_CB_ABORT;
}
- cu->uses_global_strings = true;
- cu->elf = elf;
- cu->dwfl = mod;
- cu->extra_dbg_info = conf ? conf->extra_dbg_info : 0;
- cu->has_addr_info = conf ? conf->get_addr_info : 0;
-
- GElf_Ehdr ehdr;
- if (gelf_getehdr(elf, &ehdr) == NULL) {
+ if (dwarf_cu__init(dcup, cu) != 0)
return DWARF_CB_ABORT;
- }
- cu->little_endian = ehdr.e_ident[EI_DATA] == ELFDATA2LSB;
-
- dwarf_cu__init(dcup);
dcup->cu = cu;
/* Funny hack. */
dcup->type_unit = dcup;
@@ -2387,7 +2764,7 @@ static int cus__load_debug_types(struct cus *cus, struct conf_load *conf,
Dwarf_Die *cu_die = dwarf_offdie_types(dw, off + cuhl,
&die_mem);
- if (die__process(cu_die, *cup) != 0)
+ if (die__process(cu_die, *cup, conf) != 0)
return DWARF_CB_ABORT;
off = noff;
@@ -2399,40 +2776,236 @@ static int cus__load_debug_types(struct cus *cus, struct conf_load *conf,
return 0;
}
-static int cus__load_module(struct cus *cus, struct conf_load *conf,
- Dwfl_Module *mod, Dwarf *dw, Elf *elf,
- const char *filename)
+/* Match the define in linux:include/linux/elfnote.h */
+#define LINUX_ELFNOTE_BUILD_LTO 0x101
+
+static bool cus__merging_cu(Dwarf *dw, Elf *elf)
{
+ Elf_Scn *section = NULL;
+ while ((section = elf_nextscn(elf, section)) != 0) {
+ GElf_Shdr header;
+ if (!gelf_getshdr(section, &header))
+ continue;
+
+ if (header.sh_type != SHT_NOTE)
+ continue;
+
+ Elf_Data *data = NULL;
+ while ((data = elf_getdata(section, data)) != 0) {
+ size_t name_off, desc_off, offset = 0;
+ GElf_Nhdr hdr;
+ while ((offset = gelf_getnote(data, offset, &hdr, &name_off, &desc_off)) != 0) {
+ if (hdr.n_type != LINUX_ELFNOTE_BUILD_LTO)
+ continue;
+
+ /* owner is Linux */
+ if (strcmp((char *)data->d_buf + name_off, "Linux") != 0)
+ continue;
+
+ return *(int *)(data->d_buf + desc_off) != 0;
+ }
+ }
+ }
+
Dwarf_Off off = 0, noff;
size_t cuhl;
- const unsigned char *build_id = NULL;
+
+ while (dwarf_nextcu (dw, off, &noff, &cuhl, NULL, NULL, NULL) == 0) {
+ Dwarf_Die die_mem;
+ Dwarf_Die *cu_die = dwarf_offdie(dw, off + cuhl, &die_mem);
+
+ if (cu_die == NULL)
+ break;
+
+ Dwarf_Off offset = 0;
+ while (true) {
+ size_t length;
+ Dwarf_Abbrev *abbrev = dwarf_getabbrev (cu_die, offset, &length);
+ if (abbrev == NULL || abbrev == DWARF_END_ABBREV)
+ break;
+
+ size_t attrcnt;
+ if (dwarf_getattrcnt (abbrev, &attrcnt) != 0)
+ return false;
+
+ unsigned int attr_num, attr_form;
+ Dwarf_Off aboffset;
+ size_t j;
+ for (j = 0; j < attrcnt; ++j) {
+ if (dwarf_getabbrevattr (abbrev, j, &attr_num, &attr_form,
+ &aboffset))
+ return false;
+ if (attr_form == DW_FORM_ref_addr)
+ return true;
+ }
+
+ offset += length;
+ }
+
+ off = noff;
+ }
+
+ return false;
+}
+
+struct dwarf_cus {
+ struct cus *cus;
+ struct conf_load *conf;
+ Dwfl_Module *mod;
+ Dwarf *dw;
+ Elf *elf;
+ const char *filename;
+ Dwarf_Off off;
+ const unsigned char *build_id;
+ int build_id_len;
+ int error;
+ struct dwarf_cu *type_dcu;
+};
+
+static int dwarf_cus__create_and_process_cu(struct dwarf_cus *dcus, Dwarf_Die *cu_die, uint8_t pointer_size)
+{
+ /*
+ * DW_AT_name in DW_TAG_compile_unit can be NULL, first seen in:
+ *
+ * /usr/libexec/gcc/x86_64-redhat-linux/4.3.2/ecj1.debug
+ */
+ const char *name = attr_string(cu_die, DW_AT_name, dcus->conf);
+ struct cu *cu = cu__new(name ?: "", pointer_size, dcus->build_id, dcus->build_id_len, dcus->filename, dcus->conf->use_obstack);
+ if (cu == NULL || cu__set_common(cu, dcus->conf, dcus->mod, dcus->elf) != 0)
+ return DWARF_CB_ABORT;
+
+ struct dwarf_cu *dcu = dwarf_cu__new(cu);
+
+ if (dcu == NULL)
+ return DWARF_CB_ABORT;
+
+ dcu->type_unit = dcus->type_dcu;
+ cu->priv = dcu;
+ cu->dfops = &dwarf__ops;
+
+ if (die__process_and_recode(cu_die, cu, dcus->conf) != 0 ||
+ cus__finalize(dcus->cus, cu, dcus->conf) == LSK__STOP_LOADING)
+ return DWARF_CB_ABORT;
+
+ return DWARF_CB_OK;
+}
+
+static int dwarf_cus__nextcu(struct dwarf_cus *dcus, Dwarf_Die *die_mem, Dwarf_Die **cu_die, uint8_t *pointer_size, uint8_t *offset_size)
+{
+ Dwarf_Off noff;
+ size_t cuhl;
+ int ret;
+
+ cus__lock(dcus->cus);
+
+ if (dcus->error) {
+ ret = dcus->error;
+ goto out_unlock;
+ }
+
+ ret = dwarf_nextcu(dcus->dw, dcus->off, &noff, &cuhl, NULL, pointer_size, offset_size);
+ if (ret == 0) {
+ *cu_die = dwarf_offdie(dcus->dw, dcus->off + cuhl, die_mem);
+ if (*cu_die != NULL)
+ dcus->off = noff;
+ }
+
+out_unlock:
+ cus__unlock(dcus->cus);
+
+ return ret;
+}
+
+static void *dwarf_cus__process_cu_thread(void *arg)
+{
+ struct dwarf_cus *dcus = arg;
uint8_t pointer_size, offset_size;
+ Dwarf_Die die_mem, *cu_die;
-#ifdef HAVE_DWFL_MODULE_BUILD_ID
- GElf_Addr vaddr;
- int build_id_len = dwfl_module_build_id(mod, &build_id, &vaddr);
-#else
- int build_id_len = 0;
-#endif
+ while (dwarf_cus__nextcu(dcus, &die_mem, &cu_die, &pointer_size, &offset_size) == 0) {
+ if (cu_die == NULL)
+ break;
- struct cu *type_cu;
- struct dwarf_cu type_dcu;
- int type_lsk = LSK__KEEPIT;
+ if (dwarf_cus__create_and_process_cu(dcus, cu_die, pointer_size) == DWARF_CB_ABORT)
+ goto out_abort;
+ }
- int res = cus__load_debug_types(cus, conf, mod, dw, elf, filename,
- build_id, build_id_len,
- &type_cu, &type_dcu);
- if (res != 0) {
- return res;
+ if (dcus->conf->thread_exit && dcus->conf->thread_exit() != 0)
+ goto out_abort;
+
+ return (void *)DWARF_CB_OK;
+out_abort:
+ return (void *)DWARF_CB_ABORT;
+}
+
+static int dwarf_cus__threaded_process_cus(struct dwarf_cus *dcus)
+{
+ pthread_t threads[dcus->conf->nr_jobs];
+ int i;
+
+ for (i = 0; i < dcus->conf->nr_jobs; ++i) {
+ dcus->error = pthread_create(&threads[i], NULL, dwarf_cus__process_cu_thread, dcus);
+ if (dcus->error)
+ goto out_join;
}
- if (type_cu != NULL) {
- type_lsk = finalize_cu(cus, type_cu, &type_dcu, conf);
- if (type_lsk == LSK__KEEPIT) {
- cus__add(cus, type_cu);
- }
+ dcus->error = 0;
+
+out_join:
+ while (--i >= 0) {
+ void *res;
+ int err = pthread_join(threads[i], &res);
+
+ if (err == 0 && res != NULL)
+ dcus->error = (long)res;
+ }
+
+ return dcus->error;
+}
+
+static int __dwarf_cus__process_cus(struct dwarf_cus *dcus)
+{
+ uint8_t pointer_size, offset_size;
+ Dwarf_Off noff;
+ size_t cuhl;
+
+ while (dwarf_nextcu(dcus->dw, dcus->off, &noff, &cuhl, NULL, &pointer_size, &offset_size) == 0) {
+ Dwarf_Die die_mem;
+ Dwarf_Die *cu_die = dwarf_offdie(dcus->dw, dcus->off + cuhl, &die_mem);
+
+ if (cu_die == NULL)
+ break;
+
+ if (dwarf_cus__create_and_process_cu(dcus, cu_die, pointer_size) == DWARF_CB_ABORT)
+ return DWARF_CB_ABORT;
+
+ dcus->off = noff;
}
+ return 0;
+}
+
+static int dwarf_cus__process_cus(struct dwarf_cus *dcus)
+{
+ if (dcus->conf->nr_jobs > 1)
+ return dwarf_cus__threaded_process_cus(dcus);
+
+ return __dwarf_cus__process_cus(dcus);
+}
+
+static int cus__merge_and_process_cu(struct cus *cus, struct conf_load *conf,
+ Dwfl_Module *mod, Dwarf *dw, Elf *elf,
+ const char *filename,
+ const unsigned char *build_id,
+ int build_id_len,
+ struct dwarf_cu *type_dcu)
+{
+ uint8_t pointer_size, offset_size;
+ struct dwarf_cu *dcu = NULL;
+ Dwarf_Off off = 0, noff;
+ struct cu *cu = NULL;
+ size_t cuhl;
+
while (dwarf_nextcu(dw, off, &noff, &cuhl, NULL, &pointer_size,
&offset_size) == 0) {
Dwarf_Die die_mem;
@@ -2441,46 +3014,123 @@ static int cus__load_module(struct cus *cus, struct conf_load *conf,
if (cu_die == NULL)
break;
- /*
- * DW_AT_name in DW_TAG_compile_unit can be NULL, first
- * seen in:
- * /usr/libexec/gcc/x86_64-redhat-linux/4.3.2/ecj1.debug
- */
- const char *name = attr_string(cu_die, DW_AT_name);
- struct cu *cu = cu__new(name ?: "", pointer_size,
- build_id, build_id_len, filename);
- if (cu == NULL)
- return DWARF_CB_ABORT;
- cu->uses_global_strings = true;
- cu->elf = elf;
- cu->dwfl = mod;
- cu->extra_dbg_info = conf ? conf->extra_dbg_info : 0;
- cu->has_addr_info = conf ? conf->get_addr_info : 0;
-
- GElf_Ehdr ehdr;
- if (gelf_getehdr(elf, &ehdr) == NULL) {
- return DWARF_CB_ABORT;
- }
- cu->little_endian = ehdr.e_ident[EI_DATA] == ELFDATA2LSB;
+ if (cu == NULL) {
+ cu = cu__new("", pointer_size, build_id, build_id_len,
+ filename, conf->use_obstack);
+ if (cu == NULL || cu__set_common(cu, conf, mod, elf) != 0)
+ goto out_abort;
- struct dwarf_cu dcu;
+ dcu = zalloc(sizeof(*dcu));
+ if (dcu == NULL)
+ goto out_abort;
- dwarf_cu__init(&dcu);
- dcu.cu = cu;
- dcu.type_unit = type_cu ? &type_dcu : NULL;
- cu->priv = &dcu;
- cu->dfops = &dwarf__ops;
+ /* Merged cu tends to need a lot more memory.
+ * Let us start with max_hashtags__bits and
+ * go down to find a proper hashtag bit value.
+ */
+ uint32_t default_hbits = hashtags__bits;
+ for (hashtags__bits = max_hashtags__bits;
+ hashtags__bits >= default_hbits;
+ hashtags__bits--) {
+ if (dwarf_cu__init(dcu, cu) == 0)
+ break;
+ }
+ if (hashtags__bits < default_hbits)
+ goto out_abort;
- if (die__process_and_recode(cu_die, cu) != 0)
- return DWARF_CB_ABORT;
+ dcu->cu = cu;
+ dcu->type_unit = type_dcu;
+ cu->priv = dcu;
+ cu->dfops = &dwarf__ops;
+ cu->language = attr_numeric(cu_die, DW_AT_language);
+ }
- if (finalize_cu_immediately(cus, cu, &dcu, conf)
- == LSK__STOP_LOADING)
- return DWARF_CB_ABORT;
+ Dwarf_Die child;
+ if (dwarf_child(cu_die, &child) == 0) {
+ if (die__process_unit(&child, cu, conf) != 0)
+ goto out_abort;
+ }
off = noff;
}
+ if (cu == NULL)
+ return 0;
+
+ /* process merged cu */
+ if (cu__recode_dwarf_types(cu) != LSK__KEEPIT)
+ goto out_abort;
+
+ /*
+ * for lto build, the function return type may not be
+ * resolved due to the return type of a subprogram is
+ * encoded in another subprogram through abstract_origin
+ * tag. Let us visit all subprograms again to resolve this.
+ */
+ if (cu__resolve_func_ret_types(cu) != LSK__KEEPIT)
+ goto out_abort;
+
+ if (cus__finalize(cus, cu, conf) == LSK__STOP_LOADING)
+ goto out_abort;
+
+ return 0;
+
+out_abort:
+ dwarf_cu__delete(cu);
+ cu__delete(cu);
+ return DWARF_CB_ABORT;
+}
+
+static int cus__load_module(struct cus *cus, struct conf_load *conf,
+ Dwfl_Module *mod, Dwarf *dw, Elf *elf,
+ const char *filename)
+{
+ const unsigned char *build_id = NULL;
+#ifdef HAVE_DWFL_MODULE_BUILD_ID
+ GElf_Addr vaddr;
+ int build_id_len = dwfl_module_build_id(mod, &build_id, &vaddr);
+#else
+ int build_id_len = 0;
+#endif
+ struct cu *type_cu;
+ struct dwarf_cu type_dcu;
+ int type_lsk = LSK__KEEPIT;
+
+ int res = __cus__load_debug_types(conf, mod, dw, elf, filename, build_id, build_id_len, &type_cu, &type_dcu);
+ if (res != 0) {
+ return res;
+ }
+
+ if (type_cu != NULL) {
+ type_lsk = cu__finalize(type_cu, conf);
+ if (type_lsk == LSK__KEEPIT) {
+ cus__add(cus, type_cu);
+ }
+ }
+
+ if (cus__merging_cu(dw, elf)) {
+ res = cus__merge_and_process_cu(cus, conf, mod, dw, elf, filename,
+ build_id, build_id_len,
+ type_cu ? &type_dcu : NULL);
+ } else {
+ struct dwarf_cus dcus = {
+ .off = 0,
+ .cus = cus,
+ .conf = conf,
+ .mod = mod,
+ .dw = dw,
+ .elf = elf,
+ .filename = filename,
+ .type_dcu = type_cu ? &type_dcu : NULL,
+ .build_id = build_id,
+ .build_id_len = build_id_len,
+ };
+ res = dwarf_cus__process_cus(&dcus);
+ }
+
+ if (res)
+ return res;
+
if (type_lsk == LSK__DELETE)
cu__delete(type_cu);
@@ -2495,9 +3145,9 @@ struct process_dwflmod_parms {
};
static int cus__process_dwflmod(Dwfl_Module *dwflmod,
- void **userdata __unused,
- const char *name __unused,
- Dwarf_Addr base __unused,
+ void **userdata __maybe_unused,
+ const char *name __maybe_unused,
+ Dwarf_Addr base __maybe_unused,
void *arg)
{
struct process_dwflmod_parms *parms = arg;
@@ -2535,6 +3185,16 @@ static int cus__process_dwflmod(Dwfl_Module *dwflmod,
return err;
}
+static void dwarf_loader__exit(struct cus *cus)
+{
+ Dwfl *dwfl = cus__priv(cus);
+
+ if (dwfl) {
+ dwfl_end(dwfl);
+ cus__set_priv(cus, NULL);
+ }
+}
+
static int cus__process_file(struct cus *cus, struct conf_load *conf, int fd,
const char *filename)
{
@@ -2559,6 +3219,9 @@ static int cus__process_file(struct cus *cus, struct conf_load *conf, int fd,
Dwfl *dwfl = dwfl_begin(&callbacks);
+ cus__set_priv(cus, dwfl);
+ cus__set_loader_exit(cus, dwarf_loader__exit);
+
if (dwfl_report_offline(dwfl, filename, filename, dwfl_fd) == NULL)
return -1;
@@ -2573,7 +3236,10 @@ static int cus__process_file(struct cus *cus, struct conf_load *conf, int fd,
/* Process the one or more modules gleaned from this file. */
dwfl_getmodules(dwfl, cus__process_dwflmod, &parms, 0);
- dwfl_end(dwfl);
+
+ // We can't call dwfl_end(dwfl) here, as we keep pointers to strings
+ // allocated by libdw that will be freed at dwfl_end(), so leave this for
+ // cus__delete().
return parms.nr_dwarf_sections_found ? 0 : -1;
}
@@ -2582,6 +3248,21 @@ static int dwarf__load_file(struct cus *cus, struct conf_load *conf,
{
int fd, err;
+ if (conf->max_hashtable_bits != 0) {
+ if (conf->max_hashtable_bits > 31)
+ return -E2BIG;
+
+ max_hashtags__bits = conf->max_hashtable_bits;
+ }
+
+ if (conf->hashtable_bits != 0) {
+ if (conf->hashtable_bits > max_hashtags__bits)
+ return -E2BIG;
+
+ hashtags__bits = conf->hashtable_bits;
+ } else if (hashtags__bits > max_hashtags__bits)
+ return -EINVAL;
+
elf_version(EV_CURRENT);
fd = open(filename, O_RDONLY);
@@ -2595,26 +3276,12 @@ static int dwarf__load_file(struct cus *cus, struct conf_load *conf,
return err;
}
-static int dwarf__init(void)
-{
- strings = strings__new();
- return strings != NULL ? 0 : -ENOMEM;
-}
-
-static void dwarf__exit(void)
-{
- strings__delete(strings);
- strings = NULL;
-}
-
struct debug_fmt_ops dwarf__ops = {
.name = "dwarf",
- .init = dwarf__init,
- .exit = dwarf__exit,
.load_file = dwarf__load_file,
- .strings__ptr = dwarf__strings_ptr,
.tag__decl_file = dwarf_tag__decl_file,
.tag__decl_line = dwarf_tag__decl_line,
.tag__orig_id = dwarf_tag__orig_id,
+ .cu__delete = dwarf_cu__delete,
.has_alignment_info = true,
};
diff --git a/dwarves.c b/dwarves.c
index a2d871a..81fa47b 100644
--- a/dwarves.c
+++ b/dwarves.c
@@ -14,6 +14,8 @@
#include <fcntl.h>
#include <fnmatch.h>
#include <libelf.h>
+#include <limits.h>
+#include <pthread.h>
#include <search.h>
#include <stdio.h>
#include <stdarg.h>
@@ -27,13 +29,44 @@
#include "list.h"
#include "dwarves.h"
#include "dutil.h"
-#include "pahole_strings.h"
-#include <obstack.h>
+
+#define min(x, y) ((x) < (y) ? (x) : (y))
#define obstack_chunk_alloc malloc
#define obstack_chunk_free free
-#define min(x, y) ((x) < (y) ? (x) : (y))
+static void *obstack_zalloc(struct obstack *obstack, size_t size)
+{
+ void *o = obstack_alloc(obstack, size);
+
+ if (o)
+ memset(o, 0, size);
+ return o;
+}
+
+void *cu__zalloc(struct cu *cu, size_t size)
+{
+ if (cu->use_obstack)
+ return obstack_zalloc(&cu->obstack, size);
+
+ return zalloc(size);
+}
+
+void *cu__malloc(struct cu *cu, size_t size)
+{
+ if (cu->use_obstack)
+ return obstack_alloc(&cu->obstack, size);
+
+ return malloc(size);
+}
+
+void cu__free(struct cu *cu, void *ptr)
+{
+ if (!cu->use_obstack)
+ free(ptr);
+
+ // When using an obstack we'll free everything in cu__delete()
+}
int tag__is_base_type(const struct tag *tag, const struct cu *cu)
{
@@ -70,18 +103,6 @@ bool tag__is_array(const struct tag *tag, const struct cu *cu)
return 0;
}
-const char *cu__string(const struct cu *cu, strings_t s)
-{
- if (cu->dfops && cu->dfops->strings__ptr)
- return cu->dfops->strings__ptr(cu, s);
- return NULL;
-}
-
-static inline const char *s(const struct cu *cu, strings_t i)
-{
- return cu__string(cu, i);
-}
-
int __tag__has_type_loop(const struct tag *tag, const struct tag *type,
char *bf, size_t len, FILE *fp,
const char *fn, int line)
@@ -108,43 +129,49 @@ int __tag__has_type_loop(const struct tag *tag, const struct tag *type,
return 0;
}
-static void lexblock__delete_tags(struct tag *tag, struct cu *cu)
+static void lexblock__delete_tags(struct tag *tag)
{
struct lexblock *block = tag__lexblock(tag);
struct tag *pos, *n;
list_for_each_entry_safe_reverse(pos, n, &block->tags, node) {
list_del_init(&pos->node);
- tag__delete(pos, cu);
+ tag__delete(pos);
}
}
-void lexblock__delete(struct lexblock *block, struct cu *cu)
+void lexblock__delete(struct lexblock *block)
{
- lexblock__delete_tags(&block->ip.tag, cu);
- obstack_free(&cu->obstack, block);
+ if (block == NULL)
+ return;
+
+ lexblock__delete_tags(&block->ip.tag);
+ free(block);
}
-void tag__delete(struct tag *tag, struct cu *cu)
+void tag__delete(struct tag *tag)
{
+ if (tag == NULL)
+ return;
+
assert(list_empty(&tag->node));
switch (tag->tag) {
case DW_TAG_union_type:
- type__delete(tag__type(tag), cu); break;
+ type__delete(tag__type(tag)); break;
case DW_TAG_class_type:
case DW_TAG_structure_type:
- class__delete(tag__class(tag), cu); break;
+ class__delete(tag__class(tag)); break;
case DW_TAG_enumeration_type:
- enumeration__delete(tag__type(tag), cu); break;
+ enumeration__delete(tag__type(tag)); break;
case DW_TAG_subroutine_type:
- ftype__delete(tag__ftype(tag), cu); break;
+ ftype__delete(tag__ftype(tag)); break;
case DW_TAG_subprogram:
- function__delete(tag__function(tag), cu); break;
+ function__delete(tag__function(tag)); break;
case DW_TAG_lexical_block:
- lexblock__delete(tag__lexblock(tag), cu); break;
+ lexblock__delete(tag__lexblock(tag)); break;
default:
- obstack_free(&cu->obstack, tag);
+ free(tag);
}
}
@@ -181,9 +208,8 @@ size_t __tag__id_not_found_fprintf(FILE *fp, type_id_t id,
return fprintf(fp, "<ERROR(%s:%d): %d not found!>\n", fn, line, id);
}
-static struct base_type_name_to_size {
+static struct ase_type_name_to_size {
const char *name;
- strings_t sname;
size_t size;
} base_type_name_to_size_table[] = {
{ .name = "unsigned", .size = 32, },
@@ -224,19 +250,6 @@ static struct base_type_name_to_size {
{ .name = NULL },
};
-void base_type_name_to_size_table__init(struct strings *strings)
-{
- int i = 0;
-
- while (base_type_name_to_size_table[i].name != NULL) {
- if (base_type_name_to_size_table[i].sname == 0)
- base_type_name_to_size_table[i].sname =
- strings__find(strings,
- base_type_name_to_size_table[i].name);
- ++i;
- }
-}
-
size_t base_type__name_to_size(struct base_type *bt, struct cu *cu)
{
int i = 0;
@@ -244,22 +257,21 @@ size_t base_type__name_to_size(struct base_type *bt, struct cu *cu)
const char *name, *orig_name;
if (bt->name_has_encoding)
- name = s(cu, bt->name);
+ name = bt->name;
else
- name = base_type__name(bt, cu, bf, sizeof(bf));
+ name = base_type__name(bt, bf, sizeof(bf));
orig_name = name;
try_again:
while (base_type_name_to_size_table[i].name != NULL) {
if (bt->name_has_encoding) {
- if (base_type_name_to_size_table[i].sname == bt->name) {
+ if (strcmp(base_type_name_to_size_table[i].name, bt->name) == 0) {
size_t size;
found:
size = base_type_name_to_size_table[i].size;
return size ?: ((size_t)cu->addr_size * 8);
}
- } else if (strcmp(base_type_name_to_size_table[i].name,
- name) == 0)
+ } else if (strcmp(base_type_name_to_size_table[i].name, name) == 0)
goto found;
++i;
}
@@ -290,38 +302,40 @@ static const char *base_type_fp_type_str[] = {
[BT_FP_IMGRY_LDBL] = "imaginary long double",
};
-const char *base_type__name(const struct base_type *bt, const struct cu *cu,
- char *bf, size_t len)
+const char *__base_type__name(const struct base_type *bt)
+{
+ return bt->name;
+}
+
+const char *base_type__name(const struct base_type *bt, char *bf, size_t len)
{
if (bt->name_has_encoding)
- return s(cu, bt->name);
+ return __base_type__name(bt);
if (bt->float_type)
- snprintf(bf, len, "%s %s",
- base_type_fp_type_str[bt->float_type],
- s(cu, bt->name));
+ snprintf(bf, len, "%s %s", base_type_fp_type_str[bt->float_type], bt->name);
else
- snprintf(bf, len, "%s%s%s",
- bt->is_bool ? "bool " : "",
- bt->is_varargs ? "... " : "",
- s(cu, bt->name));
+ snprintf(bf, len, "%s%s%s", bt->is_bool ? "bool " : "", bt->is_varargs ? "... " : "", bt->name);
return bf;
}
-void namespace__delete(struct namespace *space, struct cu *cu)
+void namespace__delete(struct namespace *space)
{
struct tag *pos, *n;
+ if (space == NULL)
+ return;
+
namespace__for_each_tag_safe_reverse(space, pos, n) {
list_del_init(&pos->node);
/* Look for nested namespaces */
if (tag__has_namespace(pos))
- namespace__delete(tag__namespace(pos), cu);
- tag__delete(pos, cu);
+ namespace__delete(tag__namespace(pos));
+ tag__delete(pos);
}
- tag__delete(&space->tag, cu);
+ tag__delete(&space->tag);
}
void __type__init(struct type *type)
@@ -412,10 +426,43 @@ static void cu__find_class_holes(struct cu *cu)
class__find_holes(pos);
}
+struct cus {
+ uint32_t nr_entries;
+ struct list_head cus;
+ pthread_mutex_t mutex;
+ void (*loader_exit)(struct cus *cus);
+ void *priv; // Used in dwarf_loader__exit()
+};
+
+void cus__lock(struct cus *cus)
+{
+ pthread_mutex_lock(&cus->mutex);
+}
+
+void cus__unlock(struct cus *cus)
+{
+ pthread_mutex_unlock(&cus->mutex);
+}
+
+bool cus__empty(const struct cus *cus)
+{
+ return list_empty(&cus->cus);
+}
+
+uint32_t cus__nr_entries(const struct cus *cus)
+{
+ return cus->nr_entries;
+}
+
void cus__add(struct cus *cus, struct cu *cu)
{
+ cus__lock(cus);
+
cus->nr_entries++;
list_add_tail(&cu->node, &cus->cus);
+
+ cus__unlock(cus);
+
cu__find_class_holes(cu);
}
@@ -427,8 +474,7 @@ static void ptr_table__init(struct ptr_table *pt)
static void ptr_table__exit(struct ptr_table *pt)
{
- free(pt->entries);
- pt->entries = NULL;
+ zfree(&pt->entries);
}
static int ptr_table__add(struct ptr_table *pt, void *ptr, uint32_t *idxp)
@@ -437,12 +483,16 @@ static int ptr_table__add(struct ptr_table *pt, void *ptr, uint32_t *idxp)
const uint32_t rc = pt->nr_entries;
if (nr_entries > pt->allocated_entries) {
- uint32_t allocated_entries = pt->allocated_entries + 256;
+ uint32_t allocated_entries = pt->allocated_entries + 2048;
void *entries = realloc(pt->entries,
sizeof(void *) * allocated_entries);
if (entries == NULL)
return -ENOMEM;
+ /* Zero out the new range */
+ memset(entries + pt->allocated_entries * sizeof(void *), 0,
+ (allocated_entries - pt->allocated_entries) * sizeof(void *));
+
pt->allocated_entries = allocated_entries;
pt->entries = entries;
}
@@ -458,7 +508,7 @@ static int ptr_table__add_with_id(struct ptr_table *pt, void *ptr,
{
/* Assume we won't be fed with the same id more than once */
if (id >= pt->allocated_entries) {
- uint32_t allocated_entries = roundup(id + 1, 256);
+ uint32_t allocated_entries = roundup(id + 1, 2048);
void *entries = realloc(pt->entries,
sizeof(void *) * allocated_entries);
if (entries == NULL)
@@ -555,21 +605,42 @@ int cu__add_tag_with_id(struct cu *cu, struct tag *tag, uint32_t id)
return err;
}
+int cus__fprintf_ptr_table_stats_csv_header(FILE *fp)
+{
+ return fprintf(fp, "# cu,tags,allocated_tags,types,allocated_types,functions,allocated_functions\n");
+}
+
+int cu__fprintf_ptr_table_stats_csv(struct cu *cu, FILE *fp)
+{
+ int printed = fprintf(fp, "%s,%u,%u,%u,%u,%u,%u\n", cu->name,
+ cu->tags_table.nr_entries, cu->tags_table.allocated_entries,
+ cu->types_table.nr_entries, cu->types_table.allocated_entries,
+ cu->functions_table.nr_entries, cu->functions_table.allocated_entries);
+
+ return printed;
+}
+
struct cu *cu__new(const char *name, uint8_t addr_size,
const unsigned char *build_id, int build_id_len,
- const char *filename)
+ const char *filename, bool use_obstack)
{
struct cu *cu = malloc(sizeof(*cu) + build_id_len);
if (cu != NULL) {
uint32_t void_id;
+ cu->use_obstack = use_obstack;
+ if (cu->use_obstack)
+ obstack_init(&cu->obstack);
+
cu->name = strdup(name);
- cu->filename = strdup(filename);
- if (cu->name == NULL || cu->filename == NULL)
+ if (cu->name == NULL)
goto out_free;
- obstack_init(&cu->obstack);
+ cu->filename = strdup(filename);
+ if (cu->filename == NULL)
+ goto out_free_name;
+
ptr_table__init(&cu->tags_table);
ptr_table__init(&cu->types_table);
ptr_table__init(&cu->functions_table);
@@ -578,7 +649,7 @@ struct cu *cu__new(const char *name, uint8_t addr_size,
* so make sure we don't use it
*/
if (ptr_table__add(&cu->types_table, NULL, &void_id) < 0)
- goto out_free_name;
+ goto out_free_filename;
cu->functions = RB_ROOT;
@@ -599,28 +670,36 @@ struct cu *cu__new(const char *name, uint8_t addr_size,
cu->build_id_len = build_id_len;
if (build_id_len > 0)
memcpy(cu->build_id, build_id, build_id_len);
+ cu->priv = NULL;
}
-out:
+
return cu;
+
+out_free_filename:
+ zfree(&cu->filename);
out_free_name:
- free(cu->name);
- free(cu->filename);
+ zfree(&cu->name);
out_free:
free(cu);
- cu = NULL;
- goto out;
+ return NULL;
}
void cu__delete(struct cu *cu)
{
+ if (cu == NULL)
+ return;
+
ptr_table__exit(&cu->tags_table);
ptr_table__exit(&cu->types_table);
ptr_table__exit(&cu->functions_table);
if (cu->dfops && cu->dfops->cu__delete)
cu->dfops->cu__delete(cu);
- obstack_free(&cu->obstack, NULL);
- free(cu->filename);
- free(cu->name);
+
+ if (cu->use_obstack)
+ obstack_free(&cu->obstack, NULL);
+
+ zfree(&cu->filename);
+ zfree(&cu->name);
free(cu);
}
@@ -677,7 +756,7 @@ struct tag *cu__find_base_type_by_name(const struct cu *cu,
const struct base_type *bt = tag__base_type(pos);
char bf[64];
- const char *bname = base_type__name(bt, cu, bf, sizeof(bf));
+ const char *bname = base_type__name(bt, bf, sizeof(bf));
if (!bname || strcmp(bname, name) != 0)
continue;
@@ -689,23 +768,22 @@ struct tag *cu__find_base_type_by_name(const struct cu *cu,
return NULL;
}
-struct tag *cu__find_base_type_by_sname_and_size(const struct cu *cu,
- strings_t sname,
- uint16_t bit_size,
- type_id_t *idp)
+struct tag *cu__find_base_type_by_name_and_size(const struct cu *cu, const char *name,
+ uint16_t bit_size, type_id_t *idp)
{
uint32_t id;
struct tag *pos;
- if (sname == 0)
+ if (name == NULL)
return NULL;
cu__for_each_type(cu, id, pos) {
if (pos->tag == DW_TAG_base_type) {
const struct base_type *bt = tag__base_type(pos);
+ char bf[64];
if (bt->bit_size == bit_size &&
- bt->name == sname) {
+ strcmp(base_type__name(bt, bf, sizeof(bf)), name) == 0) {
if (idp != NULL)
*idp = id;
return pos;
@@ -716,15 +794,13 @@ struct tag *cu__find_base_type_by_sname_and_size(const struct cu *cu,
return NULL;
}
-struct tag *cu__find_enumeration_by_sname_and_size(const struct cu *cu,
- strings_t sname,
- uint16_t bit_size,
- type_id_t *idp)
+struct tag *cu__find_enumeration_by_name_and_size(const struct cu *cu, const char *name,
+ uint16_t bit_size, type_id_t *idp)
{
uint32_t id;
struct tag *pos;
- if (sname == 0)
+ if (name == NULL)
return NULL;
cu__for_each_type(cu, id, pos) {
@@ -732,7 +808,7 @@ struct tag *cu__find_enumeration_by_sname_and_size(const struct cu *cu,
const struct type *t = tag__type(pos);
if (t->size == bit_size &&
- t->namespace.name == sname) {
+ strcmp(type__name(t), name) == 0) {
if (idp != NULL)
*idp = id;
return pos;
@@ -754,7 +830,7 @@ struct tag *cu__find_enumeration_by_name(const struct cu *cu, const char *name,
cu__for_each_type(cu, id, pos) {
if (pos->tag == DW_TAG_enumeration_type) {
const struct type *type = tag__type(pos);
- const char *tname = type__name(type, cu);
+ const char *tname = type__name(type);
if (tname && strcmp(tname, name) == 0) {
if (idp != NULL)
@@ -767,39 +843,6 @@ struct tag *cu__find_enumeration_by_name(const struct cu *cu, const char *name,
return NULL;
}
-struct tag *cu__find_struct_by_sname(const struct cu *cu, strings_t sname,
- const int include_decls, type_id_t *idp)
-{
- uint32_t id;
- struct tag *pos;
-
- if (sname == 0)
- return NULL;
-
- cu__for_each_type(cu, id, pos) {
- struct type *type;
-
- if (!tag__is_struct(pos))
- continue;
-
- type = tag__type(pos);
- if (type->namespace.name == sname) {
- if (!type->declaration)
- goto found;
-
- if (include_decls)
- goto found;
- }
- }
-
- return NULL;
-found:
- if (idp != NULL)
- *idp = id;
- return pos;
-
-}
-
struct tag *cu__find_type_by_name(const struct cu *cu, const char *name, const int include_decls, type_id_t *idp)
{
if (cu == NULL || name == NULL)
@@ -814,7 +857,7 @@ struct tag *cu__find_type_by_name(const struct cu *cu, const char *name, const i
continue;
type = tag__type(pos);
- const char *tname = type__name(type, cu);
+ const char *tname = type__name(type);
if (tname && strcmp(tname, name) == 0) {
if (!type->declaration)
goto found;
@@ -831,21 +874,26 @@ found:
return pos;
}
-struct tag *cus__find_type_by_name(const struct cus *cus, struct cu **cu, const char *name,
+struct tag *cus__find_type_by_name(struct cus *cus, struct cu **cu, const char *name,
const int include_decls, type_id_t *id)
{
struct cu *pos;
+ struct tag *tag = NULL;
+
+ cus__lock(cus);
list_for_each_entry(pos, &cus->cus, node) {
- struct tag *tag = cu__find_type_by_name(pos, name, include_decls, id);
+ tag = cu__find_type_by_name(pos, name, include_decls, id);
if (tag != NULL) {
if (cu != NULL)
*cu = pos;
- return tag;
+ break;
}
}
- return NULL;
+ cus__unlock(cus);
+
+ return tag;
}
static struct tag *__cu__find_struct_by_name(const struct cu *cu, const char *name,
@@ -863,7 +911,7 @@ static struct tag *__cu__find_struct_by_name(const struct cu *cu, const char *na
continue;
type = tag__type(pos);
- const char *tname = type__name(type, cu);
+ const char *tname = type__name(type);
if (tname && strcmp(tname, name) == 0) {
if (!type->declaration)
goto found;
@@ -892,32 +940,36 @@ struct tag *cu__find_struct_or_union_by_name(const struct cu *cu, const char *na
return __cu__find_struct_by_name(cu, name, include_decls, true, idp);
}
-static struct tag *__cus__find_struct_by_name(const struct cus *cus,
- struct cu **cu, const char *name,
+static struct tag *__cus__find_struct_by_name(struct cus *cus, struct cu **cu, const char *name,
const int include_decls, bool unions, type_id_t *id)
{
+ struct tag *tag = NULL;
struct cu *pos;
+ cus__lock(cus);
+
list_for_each_entry(pos, &cus->cus, node) {
struct tag *tag = __cu__find_struct_by_name(pos, name, include_decls, unions, id);
if (tag != NULL) {
if (cu != NULL)
*cu = pos;
- return tag;
+ break;
}
}
- return NULL;
+ cus__unlock(cus);
+
+ return tag;
}
-struct tag *cus__find_struct_by_name(const struct cus *cus, struct cu **cu, const char *name,
+struct tag *cus__find_struct_by_name(struct cus *cus, struct cu **cu, const char *name,
const int include_decls, type_id_t *idp)
{
return __cus__find_struct_by_name(cus, cu, name, include_decls, false, idp);
}
-struct tag *cus__find_struct_or_union_by_name(const struct cus *cus, struct cu **cu, const char *name,
- const int include_decls, type_id_t *idp)
+struct tag *cus__find_struct_or_union_by_name(struct cus *cus, struct cu **cu, const char *name,
+ const int include_decls, type_id_t *idp)
{
return __cus__find_struct_by_name(cus, cu, name, include_decls, true, idp);
}
@@ -947,32 +999,68 @@ struct function *cu__find_function_at_addr(const struct cu *cu,
}
-struct function *cus__find_function_at_addr(const struct cus *cus,
- uint64_t addr, struct cu **cu)
+struct function *cus__find_function_at_addr(struct cus *cus, uint64_t addr, struct cu **cu)
{
+ struct function *f = NULL;
struct cu *pos;
+ cus__lock(cus);
+
list_for_each_entry(pos, &cus->cus, node) {
- struct function *f = cu__find_function_at_addr(pos, addr);
+ f = cu__find_function_at_addr(pos, addr);
if (f != NULL) {
if (cu != NULL)
*cu = pos;
- return f;
+ break;
}
}
- return NULL;
+
+ cus__unlock(cus);
+
+ return f;
}
-struct cu *cus__find_cu_by_name(const struct cus *cus, const char *name)
+static struct cu *__cus__find_cu_by_name(struct cus *cus, const char *name)
{
struct cu *pos;
list_for_each_entry(pos, &cus->cus, node)
if (pos->name && strcmp(pos->name, name) == 0)
- return pos;
+ goto out;
- return NULL;
+ pos = NULL;
+out:
+ return pos;
+}
+
+struct cu *cus__find_cu_by_name(struct cus *cus, const char *name)
+{
+ struct cu *pos;
+
+ cus__lock(cus);
+
+ pos = __cus__find_cu_by_name(cus, name);
+
+ cus__unlock(cus);
+
+ return pos;
+}
+
+struct cu *cus__find_pair(struct cus *cus, const char *name)
+{
+ struct cu *cu;
+
+ cus__lock(cus);
+
+ if (cus->nr_entries == 1)
+ cu = list_first_entry(&cus->cus, struct cu, node);
+ else
+ cu = __cus__find_cu_by_name(cus, name);
+
+ cus__unlock(cus);
+
+ return cu;
}
struct tag *cu__find_function_by_name(const struct cu *cu, const char *name)
@@ -983,7 +1071,7 @@ struct tag *cu__find_function_by_name(const struct cu *cu, const char *name)
uint32_t id;
struct function *pos;
cu__for_each_function(cu, id, pos) {
- const char *fname = function__name(pos, cu);
+ const char *fname = function__name(pos);
if (fname && strcmp(fname, name) == 0)
return function__tag(pos);
}
@@ -1050,11 +1138,9 @@ size_t tag__size(const struct tag *tag, const struct cu *cu)
return size;
}
-const char *variable__name(const struct variable *var, const struct cu *cu)
+const char *variable__name(const struct variable *var)
{
- if (cu->dfops && cu->dfops->variable__name)
- return cu->dfops->variable__name(var, cu);
- return s(cu, var->name);
+ return var->name;
}
const char *variable__type_name(const struct variable *var,
@@ -1065,15 +1151,14 @@ const char *variable__type_name(const struct variable *var,
return tag != NULL ? tag__name(tag, cu, bf, len, NULL) : NULL;
}
-void class_member__delete(struct class_member *member, struct cu *cu)
+void class_member__delete(struct class_member *member)
{
- obstack_free(&cu->obstack, member);
+ free(member);
}
-static struct class_member *class_member__clone(const struct class_member *from,
- struct cu *cu)
+static struct class_member *class_member__clone(const struct class_member *from)
{
- struct class_member *member = obstack_alloc(&cu->obstack, sizeof(*member));
+ struct class_member *member = malloc(sizeof(*member));
if (member != NULL)
memcpy(member, from, sizeof(*member));
@@ -1081,42 +1166,52 @@ static struct class_member *class_member__clone(const struct class_member *from,
return member;
}
-static void type__delete_class_members(struct type *type, struct cu *cu)
+static void type__delete_class_members(struct type *type)
{
struct class_member *pos, *next;
type__for_each_tag_safe_reverse(type, pos, next) {
list_del_init(&pos->tag.node);
- class_member__delete(pos, cu);
+ class_member__delete(pos);
}
}
-void class__delete(struct class *class, struct cu *cu)
+void class__delete(struct class *class)
{
- if (class->type.namespace.sname != NULL)
- free(class->type.namespace.sname);
- type__delete_class_members(&class->type, cu);
- obstack_free(&cu->obstack, class);
+ if (class == NULL)
+ return;
+
+ type__delete_class_members(&class->type);
+ free(class);
}
-void type__delete(struct type *type, struct cu *cu)
+void type__delete(struct type *type)
{
- type__delete_class_members(type, cu);
- obstack_free(&cu->obstack, type);
+ if (type == NULL)
+ return;
+
+ type__delete_class_members(type);
+ free(type);
}
-static void enumerator__delete(struct enumerator *enumerator, struct cu *cu)
+static void enumerator__delete(struct enumerator *enumerator)
{
- obstack_free(&cu->obstack, enumerator);
+ free(enumerator);
}
-void enumeration__delete(struct type *type, struct cu *cu)
+void enumeration__delete(struct type *type)
{
struct enumerator *pos, *n;
+
+ if (type == NULL)
+ return;
+
type__for_each_enumerator_safe_reverse(type, pos, n) {
list_del_init(&pos->tag.node);
- enumerator__delete(pos, cu);
+ enumerator__delete(pos);
}
+
+ free(type);
}
void class__add_vtable_entry(struct class *class, struct function *vtable_entry)
@@ -1150,8 +1245,7 @@ struct class_member *type__last_member(struct type *type)
return NULL;
}
-static int type__clone_members(struct type *type, const struct type *from,
- struct cu *cu)
+static int type__clone_members(struct type *type, const struct type *from)
{
struct class_member *pos;
@@ -1159,7 +1253,7 @@ static int type__clone_members(struct type *type, const struct type *from,
INIT_LIST_HEAD(&type->namespace.tags);
type__for_each_member(from, pos) {
- struct class_member *clone = class_member__clone(pos, cu);
+ struct class_member *clone = class_member__clone(pos);
if (clone == NULL)
return -1;
@@ -1169,23 +1263,21 @@ static int type__clone_members(struct type *type, const struct type *from,
return 0;
}
-struct class *class__clone(const struct class *from,
- const char *new_class_name, struct cu *cu)
+struct class *class__clone(const struct class *from, const char *new_class_name)
{
- struct class *class = obstack_alloc(&cu->obstack, sizeof(*class));
+ struct class *class = malloc(sizeof(*class));
if (class != NULL) {
memcpy(class, from, sizeof(*class));
if (new_class_name != NULL) {
- class->type.namespace.name = 0;
- class->type.namespace.sname = strdup(new_class_name);
- if (class->type.namespace.sname == NULL) {
+ class->type.namespace.name = strdup(new_class_name);
+ if (class->type.namespace.name == NULL) {
free(class);
return NULL;
}
}
- if (type__clone_members(&class->type, &from->type, cu) != 0) {
- class__delete(class, cu);
+ if (type__clone_members(&class->type, &from->type) != 0) {
+ class__delete(class);
class = NULL;
}
}
@@ -1205,19 +1297,17 @@ void lexblock__add_lexblock(struct lexblock *block, struct lexblock *child)
list_add_tail(&child->ip.tag.node, &block->tags);
}
-const char *function__name(struct function *func, const struct cu *cu)
+const char *function__name(struct function *func)
{
- if (cu->dfops && cu->dfops->function__name)
- return cu->dfops->function__name(func, cu);
- return s(cu, func->name);
+ return func->name;
}
-static void parameter__delete(struct parameter *parm, struct cu *cu)
+static void parameter__delete(struct parameter *parm)
{
- obstack_free(&cu->obstack, parm);
+ free(parm);
}
-void ftype__delete(struct ftype *type, struct cu *cu)
+void ftype__delete(struct ftype *type)
{
struct parameter *pos, *n;
@@ -1226,15 +1316,18 @@ void ftype__delete(struct ftype *type, struct cu *cu)
ftype__for_each_parameter_safe_reverse(type, pos, n) {
list_del_init(&pos->tag.node);
- parameter__delete(pos, cu);
+ parameter__delete(pos);
}
- obstack_free(&cu->obstack, type);
+ free(type);
}
-void function__delete(struct function *func, struct cu *cu)
+void function__delete(struct function *func)
{
- lexblock__delete_tags(&func->lexblock.ip.tag, cu);
- ftype__delete(&func->proto, cu);
+ if (func == NULL)
+ return;
+
+ lexblock__delete_tags(&func->lexblock.ip.tag);
+ ftype__delete(&func->proto);
}
int ftype__has_parm_of_type(const struct ftype *ftype, const type_id_t target,
@@ -1312,10 +1405,9 @@ void class__find_holes(struct class *class)
{
const struct type *ctype = &class->type;
struct class_member *pos, *last = NULL;
- int cur_bitfield_end = ctype->size * 8, cur_bitfield_size = 0;
+ uint32_t cur_bitfield_end = ctype->size * 8, cur_bitfield_size = 0;
int bit_holes = 0, byte_holes = 0;
- int bit_start, bit_end;
- int last_seen_bit = 0;
+ uint32_t bit_start, bit_end, last_seen_bit = 0;
bool in_bitfield = false;
if (!tag__is_struct(class__tag(class)))
@@ -1355,7 +1447,7 @@ void class__find_holes(struct class *class)
last_seen_bit = bitfield_end;
}
if (pos->bitfield_size) {
- int aligned_start = pos->byte_offset * 8;
+ uint32_t aligned_start = pos->byte_offset * 8;
/* we can have some alignment byte padding left,
* but we need to be careful about bitfield spanning
* multiple aligned boundaries */
@@ -1423,7 +1515,7 @@ void class__find_holes(struct class *class)
static size_t type__natural_alignment(struct type *type, const struct cu *cu);
-static size_t tag__natural_alignment(struct tag *tag, const struct cu *cu)
+size_t tag__natural_alignment(struct tag *tag, const struct cu *cu)
{
size_t natural_alignment = 1;
@@ -1628,16 +1720,14 @@ int class__has_hole_ge(const struct class *class, const uint16_t size)
return 0;
}
-struct class_member *type__find_member_by_name(const struct type *type,
- const struct cu *cu,
- const char *name)
+struct class_member *type__find_member_by_name(const struct type *type, const char *name)
{
if (name == NULL)
return NULL;
struct class_member *pos;
type__for_each_data_member(type, pos) {
- const char *curr_name = class_member__name(pos, cu);
+ const char *curr_name = class_member__name(pos);
if (curr_name && strcmp(curr_name, name) == 0)
return pos;
}
@@ -1658,7 +1748,7 @@ static int strcommon(const char *a, const char *b)
return i;
}
-void enumeration__calc_prefix(struct type *enumeration, const struct cu *cu)
+static void enumeration__calc_prefix(struct type *enumeration)
{
if (enumeration->member_prefix)
return;
@@ -1668,7 +1758,7 @@ void enumeration__calc_prefix(struct type *enumeration, const struct cu *cu)
struct enumerator *entry;
type__for_each_enumerator(enumeration, entry) {
- const char *curr_name = enumerator__name(entry, cu);
+ const char *curr_name = enumerator__name(entry);
if (previous_name) {
int curr_common_part = strcommon(curr_name, previous_name);
@@ -1680,8 +1770,14 @@ void enumeration__calc_prefix(struct type *enumeration, const struct cu *cu)
previous_name = curr_name;
}
- enumeration->member_prefix = strndup(curr_name, common_part);
- enumeration->member_prefix_len = common_part == INT32_MAX ? 0 : common_part;
+ enumeration->member_prefix = NULL;
+ enumeration->member_prefix_len = 0;
+
+ if (common_part != INT32_MAX) {
+ enumeration->member_prefix = strndup(curr_name, common_part);
+ if (enumeration->member_prefix != NULL)
+ enumeration->member_prefix_len = common_part;
+ }
}
void enumerations__calc_prefix(struct list_head *enumerations)
@@ -1689,26 +1785,9 @@ void enumerations__calc_prefix(struct list_head *enumerations)
struct tag_cu_node *pos;
list_for_each_entry(pos, enumerations, node)
- enumeration__calc_prefix(tag__type(pos->tc.tag), pos->tc.cu);
+ enumeration__calc_prefix(tag__type(pos->tc.tag));
}
-const char *enumeration__prefix(struct type *enumeration, const struct cu *cu)
-{
- if (!enumeration->member_prefix)
- enumeration__calc_prefix(enumeration, cu);
-
- return enumeration->member_prefix;
-}
-
-uint16_t enumeration__prefix_len(struct type *enumeration, const struct cu *cu)
-{
- if (!enumeration->member_prefix)
- enumeration__calc_prefix(enumeration, cu);
-
- return enumeration->member_prefix_len;
-}
-
-
uint32_t type__nr_members_of_type(const struct type *type, const type_id_t type_id)
{
struct class_member *pos;
@@ -1828,6 +1907,8 @@ void cus__for_each_cu(struct cus *cus,
{
struct cu *pos;
+ cus__lock(cus);
+
list_for_each_entry(pos, &cus->cus, node) {
struct cu *cu = pos;
if (filter != NULL) {
@@ -1838,6 +1919,8 @@ void cus__for_each_cu(struct cus *cus,
if (iterator(cu, cookie))
break;
}
+
+ cus__unlock(cus);
}
int cus__load_dir(struct cus *cus, struct conf_load *conf,
@@ -1892,17 +1975,15 @@ out:
/*
* This should really do demand loading of DSOs, STABS anyone? 8-)
*/
-extern struct debug_fmt_ops dwarf__ops, ctf__ops, btf_elf__ops;
+extern struct debug_fmt_ops dwarf__ops, ctf__ops, btf__ops;
static struct debug_fmt_ops *debug_fmt_table[] = {
&dwarf__ops,
- &btf_elf__ops,
+ &btf__ops,
&ctf__ops,
NULL,
};
-struct debug_fmt_ops *dwarves__active_loader;
-
static int debugging_formats__loader(const char *name)
{
int i = 0;
@@ -1940,7 +2021,6 @@ int cus__load_file(struct cus *cus, struct conf_load *conf,
conf->conf_fprintf->has_alignment_info = debug_fmt_table[loader]->has_alignment_info;
err = 0;
- dwarves__active_loader = debug_fmt_table[loader];
if (debug_fmt_table[loader]->load_file(cus, conf,
filename) == 0)
break;
@@ -1952,20 +2032,17 @@ int cus__load_file(struct cus *cus, struct conf_load *conf,
fp = sep + 1;
}
free(fpath);
- dwarves__active_loader = NULL;
return err;
}
while (debug_fmt_table[i] != NULL) {
if (conf && conf->conf_fprintf)
conf->conf_fprintf->has_alignment_info = debug_fmt_table[i]->has_alignment_info;
- dwarves__active_loader = debug_fmt_table[i];
if (debug_fmt_table[i]->load_file(cus, conf, filename) == 0)
return 0;
++i;
}
- dwarves__active_loader = NULL;
return -EINVAL;
}
@@ -2080,18 +2157,15 @@ static int elf_read_build_id(Elf *elf, void *bf, size_t size)
* '.note' (VDSO specific)
*/
do {
- sec = elf_section_by_name(elf, &ehdr, &shdr,
- ".note.gnu.build-id", NULL);
+ sec = elf_section_by_name(elf, &shdr, ".note.gnu.build-id", NULL);
if (sec)
break;
- sec = elf_section_by_name(elf, &ehdr, &shdr,
- ".notes", NULL);
+ sec = elf_section_by_name(elf, &shdr, ".notes", NULL);
if (sec)
break;
- sec = elf_section_by_name(elf, &ehdr, &shdr,
- ".note", NULL);
+ sec = elf_section_by_name(elf, &shdr, ".note", NULL);
if (sec)
break;
@@ -2204,8 +2278,6 @@ static int filename__sprintf_build_id(const char *pathname, char *sbuild_id)
return build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
}
-#define zfree(ptr) ({ free(*ptr); *ptr = NULL; })
-
static int vmlinux_path__nr_entries;
static char **vmlinux_path;
@@ -2289,10 +2361,8 @@ static int cus__load_running_kernel(struct cus *cus, struct conf_load *conf)
if (conf && conf->conf_fprintf)
conf->conf_fprintf->has_alignment_info = debug_fmt_table[loader]->has_alignment_info;
- dwarves__active_loader = debug_fmt_table[loader];
if (debug_fmt_table[loader]->load_file(cus, conf, "/sys/kernel/btf/vmlinux") == 0)
return 0;
- dwarves__active_loader = NULL;
}
try_elf:
elf_version(EV_CURRENT);
@@ -2329,7 +2399,7 @@ int cus__load_files(struct cus *cus, struct conf_load *conf,
return i ? 0 : cus__load_running_kernel(cus, conf);
}
-int cus__fprintf_load_files_err(struct cus *cus, const char *tool, char *argv[], int err, FILE *output)
+int cus__fprintf_load_files_err(struct cus *cus __maybe_unused, const char *tool, char *argv[], int err, FILE *output)
{
/* errno is not properly preserved in some cases, sigh */
return fprintf(output, "%s: %s: %s\n", tool, argv[-err - 1],
@@ -2341,8 +2411,11 @@ struct cus *cus__new(void)
struct cus *cus = malloc(sizeof(*cus));
if (cus != NULL) {
- cus->nr_entries = 0;
+ cus->nr_entries = 0;
+ cus->priv = NULL;
+ cus->loader_exit = NULL;
INIT_LIST_HEAD(&cus->cus);
+ pthread_mutex_init(&cus->mutex, NULL);
}
return cus;
@@ -2355,20 +2428,38 @@ void cus__delete(struct cus *cus)
if (cus == NULL)
return;
+ cus__lock(cus);
+
list_for_each_entry_safe(pos, n, &cus->cus, node) {
list_del_init(&pos->node);
cu__delete(pos);
}
+ if (cus->loader_exit)
+ cus->loader_exit(cus);
+
+ cus__unlock(cus);
+
free(cus);
}
-void dwarves__fprintf_init(uint16_t user_cacheline_size);
+void cus__set_priv(struct cus *cus, void *priv)
+{
+ cus->priv = priv;
+}
-int dwarves__init(uint16_t user_cacheline_size)
+void *cus__priv(struct cus *cus)
{
- dwarves__fprintf_init(user_cacheline_size);
+ return cus->priv;
+}
+void cus__set_loader_exit(struct cus *cus, void (*loader_exit)(struct cus *cus))
+{
+ cus->loader_exit = loader_exit;
+}
+
+int dwarves__init(void)
+{
int i = 0;
int err = 0;
@@ -2402,7 +2493,7 @@ void dwarves__exit(void)
struct argp_state;
-void dwarves_print_version(FILE *fp, struct argp_state *state __unused)
+void dwarves_print_version(FILE *fp, struct argp_state *state __maybe_unused)
{
fprintf(fp, "v%u.%u\n", DWARVES_MAJOR_VERSION, DWARVES_MINOR_VERSION);
}
diff --git a/dwarves.h b/dwarves.h
index 24405b7..52d162d 100644
--- a/dwarves.h
+++ b/dwarves.h
@@ -18,7 +18,6 @@
#include "dutil.h"
#include "list.h"
#include "rbtree.h"
-#include "pahole_strings.h"
struct cu;
@@ -34,22 +33,42 @@ enum load_steal_kind {
*/
typedef uint32_t type_id_t;
+struct btf;
struct conf_fprintf;
/** struct conf_load - load configuration
+ * @thread_exit - called at the end of a thread, 1st user: BTF encoder dedup
* @extra_dbg_info - keep original debugging format extra info
* (e.g. DWARF's decl_{line,file}, id, etc)
* @fixup_silly_bitfields - Fixup silly things such as "int foo:32;"
* @get_addr_info - wheter to load DW_AT_location and other addr info
+ * @nr_jobs - -j argument, number of threads to use
+ * @ptr_table_stats - print developer oriented ptr_table statistics.
+ * @skip_missing - skip missing types rather than bailing out.
*/
struct conf_load {
enum load_steal_kind (*steal)(struct cu *cu,
struct conf_load *conf);
+ int (*thread_exit)(void);
void *cookie;
char *format_path;
+ int nr_jobs;
bool extra_dbg_info;
+ bool use_obstack;
bool fixup_silly_bitfields;
bool get_addr_info;
+ bool ignore_alignment_attr;
+ bool ignore_inline_expansions;
+ bool ignore_labels;
+ bool ptr_table_stats;
+ bool skip_encoding_btf_decl_tag;
+ bool skip_missing;
+ bool skip_encoding_btf_type_tag;
+ uint8_t hashtable_bits;
+ uint8_t max_hashtable_bits;
+ uint16_t kabi_prefix_len;
+ const char *kabi_prefix;
+ struct btf *base_btf;
struct conf_fprintf *conf_fprintf;
};
@@ -82,6 +101,7 @@ struct conf_fprintf {
const char *header_type;
const char *range;
uint32_t skip;
+ uint16_t cacheline_size;
uint8_t indent;
uint8_t expand_types:1;
uint8_t expand_pointers:1;
@@ -107,10 +127,7 @@ struct conf_fprintf {
uint8_t strip_inline:1;
};
-struct cus {
- uint32_t nr_entries;
- struct list_head cus;
-};
+struct cus;
struct cus *cus__new(void);
void cus__delete(struct cus *cus);
@@ -127,20 +144,30 @@ int cus__load_dir(struct cus *cus, struct conf_load *conf,
void cus__add(struct cus *cus, struct cu *cu);
void cus__print_error_msg(const char *progname, const struct cus *cus,
const char *filename, const int err);
-struct cu *cus__find_cu_by_name(const struct cus *cus, const char *name);
-struct tag *cus__find_struct_by_name(const struct cus *cus, struct cu **cu,
+struct cu *cus__find_pair(struct cus *cus, const char *name);
+struct cu *cus__find_cu_by_name(struct cus *cus, const char *name);
+struct tag *cus__find_struct_by_name(struct cus *cus, struct cu **cu,
const char *name, const int include_decls,
type_id_t *id);
-struct tag *cus__find_struct_or_union_by_name(const struct cus *cus, struct cu **cu,
+struct tag *cus__find_struct_or_union_by_name(struct cus *cus, struct cu **cu,
const char *name, const int include_decls, type_id_t *id);
struct tag *cu__find_type_by_name(const struct cu *cu, const char *name, const int include_decls, type_id_t *idp);
-struct tag *cus__find_type_by_name(const struct cus *cus, struct cu **cu, const char *name,
+struct tag *cus__find_type_by_name(struct cus *cus, struct cu **cu, const char *name,
const int include_decls, type_id_t *id);
-struct function *cus__find_function_at_addr(const struct cus *cus,
- uint64_t addr, struct cu **cu);
+struct function *cus__find_function_at_addr(struct cus *cus, uint64_t addr, struct cu **cu);
void cus__for_each_cu(struct cus *cus, int (*iterator)(struct cu *cu, void *cookie),
void *cookie,
struct cu *(*filter)(struct cu *cu));
+bool cus__empty(const struct cus *cus);
+uint32_t cus__nr_entries(const struct cus *cus);
+
+void cus__lock(struct cus *cus);
+void cus__unlock(struct cus *cus);
+
+void *cus__priv(struct cus *cus);
+void cus__set_priv(struct cus *cus, void *priv);
+
+void cus__set_loader_exit(struct cus *cus, void (*loader_exit)(struct cus *cus));
struct ptr_table {
void **entries;
@@ -178,15 +205,9 @@ enum dwarf_languages {
/** struct debug_fmt_ops - specific to the underlying debug file format
*
- * @function__name - will be called by function__name(), giving a chance to
- * formats such as CTF to get this from some other place
- * than the global strings table. CTF does this by storing
- * GElf_Sym->st_name in function->name, and by using
- * function->name as an index into the .strtab ELF section.
- * @variable__name - will be called by variable__name(), see @function_name
* cu__delete - called at cu__delete(), to give a chance to formats such as
* CTF to keep the .strstab ELF section available till the cu is
- * deleted. See @function__name
+ * deleted.
*/
struct debug_fmt_ops {
const char *name;
@@ -201,13 +222,6 @@ struct debug_fmt_ops {
const struct cu *cu);
unsigned long long (*tag__orig_id)(const struct tag *tag,
const struct cu *cu);
- void (*tag__free_orig_info)(struct tag *tag,
- struct cu *cu);
- const char *(*function__name)(struct function *tag,
- const struct cu *cu);
- const char *(*variable__name)(const struct variable *var,
- const struct cu *cu);
- const char *(*strings__ptr)(const struct cu *cu, strings_t s);
void (*cu__delete)(struct cu *cu);
bool has_alignment_info;
};
@@ -225,11 +239,12 @@ struct cu {
char *name;
char *filename;
void *priv;
- struct obstack obstack;
struct debug_fmt_ops *dfops;
Elf *elf;
Dwfl_Module *dwfl;
+ struct obstack obstack;
uint32_t cached_symtab_nr_entries;
+ bool use_obstack;
uint8_t addr_size;
uint8_t extra_dbg_info:1;
uint8_t has_addr_info:1;
@@ -249,10 +264,16 @@ struct cu {
struct cu *cu__new(const char *name, uint8_t addr_size,
const unsigned char *build_id, int build_id_len,
- const char *filename);
+ const char *filename, bool use_obstack);
void cu__delete(struct cu *cu);
-const char *cu__string(const struct cu *cu, strings_t s);
+void *cu__malloc(struct cu *cu, size_t size);
+void *cu__zalloc(struct cu *cu, size_t size);
+void cu__free(struct cu *cu, void *ptr);
+
+int cu__fprintf_ptr_table_stats_csv(struct cu *cu, FILE *fp);
+
+int cus__fprintf_ptr_table_stats_csv_header(FILE *fp);
static inline int cu__cache_symtab(struct cu *cu)
{
@@ -267,6 +288,11 @@ static inline __pure bool cu__is_c_plus_plus(const struct cu *cu)
return cu->language == LANG_C_plus_plus;
}
+static inline __pure bool cu__is_c(const struct cu *cu)
+{
+ return cu->language == LANG_C;
+}
+
/**
* cu__for_each_cached_symtab_entry - iterate thru the cached symtab entries
* @cu: struct cu instance
@@ -354,20 +380,14 @@ int cu__table_add_tag_with_id(struct cu *cu, struct tag *tag, uint32_t id);
int cu__table_nullify_type_entry(struct cu *cu, uint32_t id);
struct tag *cu__find_base_type_by_name(const struct cu *cu, const char *name,
type_id_t *id);
-struct tag *cu__find_base_type_by_sname_and_size(const struct cu *cu,
- strings_t name,
- uint16_t bit_size,
- type_id_t *idp);
+struct tag *cu__find_base_type_by_name_and_size(const struct cu *cu, const char* name,
+ uint16_t bit_size, type_id_t *idp);
struct tag *cu__find_enumeration_by_name(const struct cu *cu, const char *name, type_id_t *idp);
-struct tag *cu__find_enumeration_by_sname_and_size(const struct cu *cu,
- strings_t sname,
- uint16_t bit_size,
- type_id_t *idp);
+struct tag *cu__find_enumeration_by_name_and_size(const struct cu *cu, const char* name,
+ uint16_t bit_size, type_id_t *idp);
struct tag *cu__find_first_typedef_of_type(const struct cu *cu,
const type_id_t type);
struct tag *cu__find_function_by_name(const struct cu *cu, const char *name);
-struct tag *cu__find_struct_by_sname(const struct cu *cu, strings_t sname,
- const int include_decls, type_id_t *idp);
struct function *cu__find_function_at_addr(const struct cu *cu,
uint64_t addr);
struct tag *cu__function(const struct cu *cu, const uint32_t id);
@@ -394,6 +414,7 @@ struct tag {
uint16_t tag;
bool visited;
bool top_level;
+ bool has_btf_type_tag;
uint16_t recursivity_level;
void *priv;
};
@@ -404,7 +425,7 @@ struct tag_cu {
struct cu *cu;
};
-void tag__delete(struct tag *tag, struct cu *cu);
+void tag__delete(struct tag *tag);
static inline int tag__is_enumeration(const struct tag *tag)
{
@@ -514,7 +535,8 @@ static inline int tag__is_tag_type(const struct tag *tag)
tag->tag == DW_TAG_restrict_type ||
tag->tag == DW_TAG_subroutine_type ||
tag->tag == DW_TAG_unspecified_type ||
- tag->tag == DW_TAG_volatile_type;
+ tag->tag == DW_TAG_volatile_type ||
+ tag->tag == DW_TAG_LLVM_annotation;
}
static inline const char *tag__decl_file(const struct tag *tag,
@@ -541,12 +563,6 @@ static inline unsigned long long tag__orig_id(const struct tag *tag,
return 0;
}
-static inline void tag__free_orig_info(struct tag *tag, struct cu *cu)
-{
- if (cu->dfops && cu->dfops->tag__free_orig_info)
- cu->dfops->tag__free_orig_info(tag, cu);
-}
-
size_t tag__fprintf_decl_info(const struct tag *tag,
const struct cu *cu, FILE *fp);
size_t tag__fprintf(struct tag *tag, const struct cu *cu,
@@ -561,7 +577,7 @@ void tag__not_found_die(const char *file, int line, const char *func);
__LINE__, __func__); } while (0)
size_t tag__size(const struct tag *tag, const struct cu *cu);
-size_t tag__nr_cachelines(const struct tag *tag, const struct cu *cu);
+size_t tag__nr_cachelines(const struct conf_fprintf *conf, const struct tag *tag, const struct cu *cu);
struct tag *tag__follow_typedef(const struct tag *tag, const struct cu *cu);
struct tag *tag__strip_typedefs_and_modifiers(const struct tag *tag, const struct cu *cu);
@@ -587,19 +603,57 @@ static inline struct ptr_to_member_type *
return (struct ptr_to_member_type *)tag;
}
+struct llvm_annotation {
+ const char *value;
+ int16_t component_idx;
+ struct list_head node;
+};
+
+/** struct btf_type_tag_type - representing a btf_type_tag annotation
+ *
+ * @tag - DW_TAG_LLVM_annotation tag
+ * @value - btf_type_tag value string
+ * @node - list_head node
+ */
+struct btf_type_tag_type {
+ struct tag tag;
+ const char *value;
+ struct list_head node;
+};
+
+/** The struct btf_type_tag_ptr_type - type containing both pointer type and
+ * its btf_type_tag annotations
+ *
+ * @tag - pointer type tag
+ * @tags - btf_type_tag annotations for the pointer type
+ */
+struct btf_type_tag_ptr_type {
+ struct tag tag;
+ struct list_head tags;
+};
+
+static inline struct btf_type_tag_ptr_type *tag__btf_type_tag_ptr(struct tag *tag)
+{
+ return (struct btf_type_tag_ptr_type *)tag;
+}
+
+static inline struct btf_type_tag_type *tag__btf_type_tag(struct tag *tag)
+{
+ return (struct btf_type_tag_type *)tag;
+}
+
/** struct namespace - base class for enums, structs, unions, typedefs, etc
*
- * @sname - for clones, for instance, where we can't always add a new string
* @tags - class_member, enumerators, etc
* @shared_tags: if this bit is set, don't free the entries in @tags
*/
struct namespace {
struct tag tag;
- strings_t name;
+ const char *name;
uint16_t nr_tags;
uint8_t shared_tags;
- char * sname;
struct list_head tags;
+ struct list_head annots;
};
static inline struct namespace *tag__namespace(const struct tag *tag)
@@ -607,7 +661,7 @@ static inline struct namespace *tag__namespace(const struct tag *tag)
return (struct namespace *)tag;
}
-void namespace__delete(struct namespace *nspace, struct cu *cu);
+void namespace__delete(struct namespace *nspace);
/**
* namespace__for_each_tag - iterate thru all the tags
@@ -647,7 +701,7 @@ static inline struct inline_expansion *
struct label {
struct ip_tag ip;
- strings_t name;
+ const char *name;
};
static inline struct label *tag__label(const struct tag *tag)
@@ -655,10 +709,9 @@ static inline struct label *tag__label(const struct tag *tag)
return (struct label *)tag;
}
-static inline const char *label__name(const struct label *label,
- const struct cu *cu)
+static inline const char *label__name(const struct label *label)
{
- return cu__string(cu, label->name);
+ return label->name;
}
enum vscope {
@@ -676,12 +729,14 @@ struct location {
struct variable {
struct ip_tag ip;
- strings_t name;
+ const char *name;
uint8_t external:1;
uint8_t declaration:1;
+ uint8_t has_specification:1;
enum vscope scope;
struct location location;
struct hlist_node tool_hnode;
+ struct list_head annots;
struct variable *spec;
};
@@ -693,7 +748,7 @@ static inline struct variable *tag__variable(const struct tag *tag)
enum vscope variable__scope(const struct variable *var);
const char *variable__scope_str(const struct variable *var);
-const char *variable__name(const struct variable *var, const struct cu *cu);
+const char *variable__name(const struct variable *var);
const char *variable__type_name(const struct variable *var,
const struct cu *cu, char *bf, size_t len);
@@ -714,7 +769,7 @@ static inline struct lexblock *tag__lexblock(const struct tag *tag)
return (struct lexblock *)tag;
}
-void lexblock__delete(struct lexblock *lexblock, struct cu *cu);
+void lexblock__delete(struct lexblock *lexblock);
struct function;
@@ -729,8 +784,8 @@ size_t lexblock__fprintf(const struct lexblock *lexblock, const struct cu *cu,
const struct conf_fprintf *conf, FILE *fp);
struct parameter {
- struct tag tag;
- strings_t name;
+ struct tag tag;
+ const char *name;
};
static inline struct parameter *tag__parameter(const struct tag *tag)
@@ -738,10 +793,9 @@ static inline struct parameter *tag__parameter(const struct tag *tag)
return (struct parameter *)tag;
}
-static inline const char *parameter__name(const struct parameter *parm,
- const struct cu *cu)
+static inline const char *parameter__name(const struct parameter *parm)
{
- return cu__string(cu, parm->name);
+ return parm->name;
}
/*
@@ -759,7 +813,7 @@ static inline struct ftype *tag__ftype(const struct tag *tag)
return (struct ftype *)tag;
}
-void ftype__delete(struct ftype *ftype, struct cu *cu);
+void ftype__delete(struct ftype *ftype);
/**
* ftype__for_each_parameter - iterate thru all the parameters
@@ -802,8 +856,8 @@ struct function {
struct ftype proto;
struct lexblock lexblock;
struct rb_node rb_node;
- strings_t name;
- strings_t linkage_name;
+ const char *name;
+ const char *linkage_name;
uint32_t cu_total_size_inline_expansions;
uint16_t cu_total_nr_inline_expansions;
uint8_t inlined:2;
@@ -815,6 +869,7 @@ struct function {
uint8_t btf:1;
int32_t vtable_entry;
struct list_head vtable_node;
+ struct list_head annots;
/* fields used by tools */
union {
struct list_head tool_node;
@@ -833,7 +888,7 @@ static inline struct tag *function__tag(const struct function *func)
return (struct tag *)func;
}
-void function__delete(struct function *func, struct cu *cu);
+void function__delete(struct function *func);
static __pure inline int tag__is_function(const struct tag *tag)
{
@@ -848,12 +903,11 @@ static __pure inline int tag__is_function(const struct tag *tag)
#define function__for_each_parameter(func, cu, pos) \
ftype__for_each_parameter(func->btf ? tag__ftype(cu__type(cu, func->proto.tag.type)) : &func->proto, pos)
-const char *function__name(struct function *func, const struct cu *cu);
+const char *function__name(struct function *func);
-static inline const char *function__linkage_name(const struct function *func,
- const struct cu *cu)
+static inline const char *function__linkage_name(const struct function *func)
{
- return cu__string(cu, func->linkage_name);
+ return func->linkage_name;
}
size_t function__fprintf_stats(const struct tag *tag_func,
@@ -899,10 +953,11 @@ static inline int function__inlined(const struct function *func)
* @accessibility - DW_ACCESS_{public,protected,private}
* @virtuality - DW_VIRTUALITY_{none,virtual,pure_virtual}
* @hole - If there is a hole before the next one (or the end of the struct)
+ * @has_bit_offset: Don't recalcule this, it came from the debug info (DWARF5's DW_AT_data_bit_offset)
*/
struct class_member {
struct tag tag;
- strings_t name;
+ const char *name;
uint32_t bit_offset;
uint32_t bit_size;
uint32_t byte_offset;
@@ -915,22 +970,22 @@ struct class_member {
uint32_t alignment;
uint8_t visited:1;
uint8_t is_static:1;
+ uint8_t has_bit_offset:1;
uint8_t accessibility:2;
uint8_t virtuality:2;
uint16_t hole;
};
-void class_member__delete(struct class_member *member, struct cu *cu);
+void class_member__delete(struct class_member *member);
static inline struct class_member *tag__class_member(const struct tag *tag)
{
return (struct class_member *)tag;
}
-static inline const char *class_member__name(const struct class_member *member,
- const struct cu *cu)
+static inline const char *class_member__name(const struct class_member *member)
{
- return cu__string(cu, member->name);
+ return member->name;
}
static __pure inline int tag__is_class_member(const struct tag *tag)
@@ -951,7 +1006,8 @@ struct tag_cu_node {
/**
* struct type - base type for enumerations, structs and unions
*
- * @nnr_members: number of non static DW_TAG_member entries
+ * @node: Used in emissions->fwd_decls, i.e. only on the 'dwarves_emit.c' file
+ * @nr_members: number of non static DW_TAG_member entries
* @nr_static_members: number of static DW_TAG_member entries
* @nr_tags: number of tags
* @alignment: DW_AT_alignement, zero if not present, gcc emits since circa 7.3.1
@@ -988,6 +1044,8 @@ struct type {
void __type__init(struct type *type);
+size_t tag__natural_alignment(struct tag *tag, const struct cu *cu);
+
static inline struct class *type__class(const struct type *type)
{
return (struct class *)type;
@@ -998,7 +1056,17 @@ static inline struct tag *type__tag(const struct type *type)
return (struct tag *)type;
}
-void type__delete(struct type *type, struct cu *cu);
+void type__delete(struct type *type);
+
+static inline struct class_member *type__first_member(struct type *type)
+{
+ return list_first_entry(&type->namespace.tags, struct class_member, tag.node);
+}
+
+static inline struct class_member *class_member__next(struct class_member *member)
+{
+ return list_entry(member->tag.node.next, struct class_member, tag.node);
+}
/**
* type__for_each_tag - iterate thru all the tags
@@ -1093,17 +1161,10 @@ struct class_member *
type__find_first_biggest_size_base_type_member(struct type *type,
const struct cu *cu);
-struct class_member *type__find_member_by_name(const struct type *type,
- const struct cu *cu,
- const char *name);
+struct class_member *type__find_member_by_name(const struct type *type, const char *name);
uint32_t type__nr_members_of_type(const struct type *type, const type_id_t oftype);
struct class_member *type__last_member(struct type *type);
-void enumeration__calc_prefix(struct type *type, const struct cu *cu);
-const char *enumeration__prefix(struct type *type, const struct cu *cu);
-uint16_t enumeration__prefix_len(struct type *type, const struct cu *cu);
-int enumeration__max_entry_name_len(struct type *type, const struct cu *cu);
-
void enumerations__calc_prefix(struct list_head *enumerations);
size_t typedef__fprintf(const struct tag *tag_type, const struct cu *cu,
@@ -1139,31 +1200,27 @@ static inline struct tag *class__tag(const struct class *cls)
return (struct tag *)cls;
}
-struct class *class__clone(const struct class *from,
- const char *new_class_name, struct cu *cu);
-void class__delete(struct class *cls, struct cu *cu);
+struct class *class__clone(const struct class *from, const char *new_class_name);
+void class__delete(struct class *cls);
static inline struct list_head *class__tags(struct class *cls)
{
return &cls->type.namespace.tags;
}
-static __pure inline const char *namespace__name(const struct namespace *nspace,
- const struct cu *cu)
+static __pure inline const char *namespace__name(const struct namespace *nspace)
{
- return nspace->sname ?: cu__string(cu, nspace->name);
+ return nspace->name;
}
-static __pure inline const char *type__name(const struct type *type,
- const struct cu *cu)
+static __pure inline const char *type__name(const struct type *type)
{
- return namespace__name(&type->namespace, cu);
+ return namespace__name(&type->namespace);
}
-static __pure inline const char *class__name(struct class *cls,
- const struct cu *cu)
+static __pure inline const char *class__name(struct class *cls)
{
- return type__name(&cls->type, cu);
+ return type__name(&cls->type);
}
static inline int class__is_struct(const struct class *cls)
@@ -1184,10 +1241,9 @@ size_t class__fprintf(struct class *cls, const struct cu *cu, FILE *fp);
void class__add_vtable_entry(struct class *cls, struct function *vtable_entry);
static inline struct class_member *
- class__find_member_by_name(const struct class *cls,
- const struct cu *cu, const char *name)
+ class__find_member_by_name(const struct class *cls, const char *name)
{
- return type__find_member_by_name(&cls->type, cu, name);
+ return type__find_member_by_name(&cls->type, name);
}
static inline uint16_t class__nr_members(const struct class *cls)
@@ -1253,7 +1309,7 @@ enum base_type_float_type {
struct base_type {
struct tag tag;
- strings_t name;
+ const char *name;
uint16_t bit_size;
uint8_t name_has_encoding:1;
uint8_t is_signed:1;
@@ -1272,10 +1328,10 @@ static inline uint16_t base_type__size(const struct tag *tag)
return tag__base_type(tag)->bit_size / 8;
}
-const char *base_type__name(const struct base_type *btype, const struct cu *cu,
- char *bf, size_t len);
+const char *__base_type__name(const struct base_type *bt);
+
+const char *base_type__name(const struct base_type *btype, char *bf, size_t len);
-void base_type_name_to_size_table__init(struct strings *strings);
size_t base_type__name_to_size(struct base_type *btype, struct cu *cu);
struct array_type {
@@ -1302,24 +1358,24 @@ static inline struct string_type *tag__string_type(const struct tag *tag)
struct enumerator {
struct tag tag;
- strings_t name;
+ const char *name;
uint32_t value;
struct tag_cu type_enum; // To cache the type_enum searches
};
-static inline const char *enumerator__name(const struct enumerator *enumerator,
- const struct cu *cu)
+static inline const char *enumerator__name(const struct enumerator *enumerator)
{
- return cu__string(cu, enumerator->name);
+ return enumerator->name;
}
-void enumeration__delete(struct type *type, struct cu *cu);
+void enumeration__delete(struct type *type);
void enumeration__add(struct type *type, struct enumerator *enumerator);
-size_t enumeration__fprintf(const struct tag *tag_enum, const struct cu *cu,
+size_t enumeration__fprintf(const struct tag *tag_enum,
const struct conf_fprintf *conf, FILE *fp);
-int dwarves__init(uint16_t user_cacheline_size);
+int dwarves__init(void);
void dwarves__exit(void);
+void dwarves__resolve_cacheline_size(const struct conf_load *conf, uint16_t user_cacheline_size);
const char *dwarf_tag_name(const uint32_t tag);
@@ -1328,7 +1384,7 @@ struct argp_state;
void dwarves_print_version(FILE *fp, struct argp_state *state);
void dwarves_print_numeric_version(FILE *fp);
-extern bool print_numeric_version;;
+extern bool print_numeric_version;
extern bool no_bitfield_type_recode;
diff --git a/dwarves_emit.c b/dwarves_emit.c
index 434e339..5bf7946 100644
--- a/dwarves_emit.c
+++ b/dwarves_emit.c
@@ -37,7 +37,6 @@ static void type_emissions__add_fwd_decl(struct type_emissions *emissions,
}
struct type *type_emissions__find_definition(const struct type_emissions *emissions,
- const struct cu *cu,
const char *name)
{
struct type *pos;
@@ -46,15 +45,14 @@ struct type *type_emissions__find_definition(const struct type_emissions *emissi
return NULL;
list_for_each_entry(pos, &emissions->definitions, node)
- if (type__name(pos, cu) != NULL &&
- strcmp(type__name(pos, cu), name) == 0)
+ if (type__name(pos) != NULL &&
+ strcmp(type__name(pos), name) == 0)
return pos;
return NULL;
}
static struct type *type_emissions__find_fwd_decl(const struct type_emissions *emissions,
- const struct cu *cu,
const char *name)
{
struct type *pos;
@@ -63,7 +61,7 @@ static struct type *type_emissions__find_fwd_decl(const struct type_emissions *e
return NULL;
list_for_each_entry(pos, &emissions->fwd_decls, node) {
- const char *curr_name = type__name(pos, cu);
+ const char *curr_name = type__name(pos);
if (curr_name && strcmp(curr_name, name) == 0)
return pos;
@@ -72,7 +70,7 @@ static struct type *type_emissions__find_fwd_decl(const struct type_emissions *e
return NULL;
}
-static int enumeration__emit_definitions(struct tag *tag, struct cu *cu,
+static int enumeration__emit_definitions(struct tag *tag,
struct type_emissions *emissions,
const struct conf_fprintf *conf,
FILE *fp)
@@ -84,8 +82,7 @@ static int enumeration__emit_definitions(struct tag *tag, struct cu *cu,
return 0;
/* Ok, lets look at the previous CUs: */
- if (type_emissions__find_definition(emissions, cu,
- type__name(etype, cu)) != NULL) {
+ if (type_emissions__find_definition(emissions, type__name(etype)) != NULL) {
/*
* Yes, so lets mark it visited on this CU too,
* to speed up the lookup.
@@ -94,7 +91,7 @@ static int enumeration__emit_definitions(struct tag *tag, struct cu *cu,
return 0;
}
- enumeration__fprintf(tag, cu, conf, fp);
+ enumeration__fprintf(tag, conf, fp);
fputs(";\n", fp);
type_emissions__add_definition(emissions, etype);
return 1;
@@ -114,8 +111,7 @@ static int typedef__emit_definitions(struct tag *tdef, struct cu *cu,
return 0;
/* Ok, lets look at the previous CUs: */
- if (type_emissions__find_definition(emissions, cu,
- type__name(def, cu)) != NULL) {
+ if (type_emissions__find_definition(emissions, type__name(def)) != NULL) {
/*
* Yes, so lets mark it visited on this CU too,
* to speed up the lookup.
@@ -155,25 +151,23 @@ static int typedef__emit_definitions(struct tag *tdef, struct cu *cu,
.suffix = NULL,
};
- if (type__name(ctype, cu) == NULL) {
+ if (type__name(ctype) == NULL) {
fputs("typedef ", fp);
- conf.suffix = type__name(def, cu);
- enumeration__emit_definitions(type, cu, emissions,
- &conf, fp);
+ conf.suffix = type__name(def);
+ enumeration__emit_definitions(type, emissions, &conf, fp);
goto out;
} else
- enumeration__emit_definitions(type, cu, emissions,
- &conf, fp);
+ enumeration__emit_definitions(type, emissions, &conf, fp);
}
break;
case DW_TAG_structure_type:
case DW_TAG_union_type: {
struct type *ctype = tag__type(type);
- if (type__name(ctype, cu) == NULL) {
+ if (type__name(ctype) == NULL) {
if (type__emit_definitions(type, cu, emissions, fp))
type__emit(type, cu, "typedef",
- type__name(def, cu), fp);
+ type__name(def), fp);
goto out;
} else if (type__emit_definitions(type, cu, emissions, fp))
type__emit(type, cu, NULL, NULL, fp);
@@ -197,19 +191,18 @@ out:
return 1;
}
-int type__emit_fwd_decl(struct type *ctype, const struct cu *cu,
- struct type_emissions *emissions, FILE *fp)
+static int type__emit_fwd_decl(struct type *ctype, struct type_emissions *emissions, FILE *fp)
{
/* Have we already emitted this in this CU? */
if (ctype->fwd_decl_emitted)
return 0;
- const char *name = type__name(ctype, cu);
+ const char *name = type__name(ctype);
if (name == NULL)
return 0;
/* Ok, lets look at the previous CUs: */
- if (type_emissions__find_fwd_decl(emissions, cu, name) != NULL) {
+ if (type_emissions__find_fwd_decl(emissions, name) != NULL) {
/*
* Yes, so lets mark it visited on this CU too,
* to speed up the lookup.
@@ -220,7 +213,7 @@ int type__emit_fwd_decl(struct type *ctype, const struct cu *cu,
fprintf(fp, "%s %s;\n",
tag__is_union(&ctype->namespace.tag) ? "union" : "struct",
- type__name(ctype, cu));
+ type__name(ctype));
type_emissions__add_fwd_decl(emissions, ctype);
return 1;
}
@@ -249,12 +242,11 @@ next_indirection:
case DW_TAG_typedef:
return typedef__emit_definitions(type, cu, emissions, fp);
case DW_TAG_enumeration_type:
- if (type__name(tag__type(type), cu) != NULL) {
+ if (type__name(tag__type(type)) != NULL) {
struct conf_fprintf conf = {
.suffix = NULL,
};
- return enumeration__emit_definitions(type, cu, emissions,
- &conf, fp);
+ return enumeration__emit_definitions(type, emissions, &conf, fp);
}
break;
case DW_TAG_structure_type:
@@ -264,11 +256,10 @@ next_indirection:
* Struct defined inline, no name, need to have its
* members types emitted.
*/
- if (type__name(tag__type(type), cu) == NULL)
+ if (type__name(tag__type(type)) == NULL)
type__emit_definitions(type, cu, emissions, fp);
- return type__emit_fwd_decl(tag__type(type), cu,
- emissions, fp);
+ return type__emit_fwd_decl(tag__type(type), emissions, fp);
}
if (type__emit_definitions(type, cu, emissions, fp))
type__emit(type, cu, NULL, NULL, fp);
@@ -308,8 +299,7 @@ int type__emit_definitions(struct tag *tag, struct cu *cu,
return 0;
/* Ok, lets look at the previous CUs: */
- if (type_emissions__find_definition(emissions, cu,
- type__name(ctype, cu)) != NULL) {
+ if (type_emissions__find_definition(emissions, type__name(ctype)) != NULL) {
ctype->definition_emitted = 1;
return 0;
}
@@ -333,7 +323,7 @@ void type__emit(struct tag *tag, struct cu *cu,
{
struct type *ctype = tag__type(tag);
- if (type__name(ctype, cu) != NULL ||
+ if (type__name(ctype) != NULL ||
suffix != NULL || prefix != NULL) {
struct conf_fprintf conf = {
.prefix = prefix,
diff --git a/dwarves_emit.h b/dwarves_emit.h
index 5d8c7ab..be02acd 100644
--- a/dwarves_emit.h
+++ b/dwarves_emit.h
@@ -27,12 +27,9 @@ int ftype__emit_definitions(struct ftype *ftype, struct cu *cu,
struct type_emissions *emissions, FILE *fp);
int type__emit_definitions(struct tag *tag, struct cu *cu,
struct type_emissions *emissions, FILE *fp);
-int type__emit_fwd_decl(struct type *ctype, const struct cu *cu,
- struct type_emissions *emissions, FILE *fp);
void type__emit(struct tag *tag_type, struct cu *cu,
const char *prefix, const char *suffix, FILE *fp);
struct type *type_emissions__find_definition(const struct type_emissions *temissions,
- const struct cu *cu,
const char *name);
#endif /* _DWARVES_EMIT_H_ */
diff --git a/dwarves_fprintf.c b/dwarves_fprintf.c
index c96a6fb..c5921d7 100644
--- a/dwarves_fprintf.c
+++ b/dwarves_fprintf.c
@@ -10,10 +10,14 @@
#include <dwarf.h>
#include <errno.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <inttypes.h>
#include <elfutils/version.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
#include "config.h"
#include "dwarves.h"
@@ -80,6 +84,15 @@ static const char *dwarf_tag_names[] = {
[DW_TAG_type_unit] = "type_unit",
[DW_TAG_rvalue_reference_type] = "rvalue_reference_type",
#endif
+#if _ELFUTILS_PREREQ(0, 170)
+ [DW_TAG_coarray_type] = "coarray_type",
+ [DW_TAG_generic_subrange] = "generic_subrange",
+ [DW_TAG_dynamic_type] = "dynamic_type",
+ [DW_TAG_call_site] = "call_site",
+ [DW_TAG_call_site_parameter] = "call_site_parameter",
+ [DW_TAG_skeleton_unit] = "skeleton_unit",
+ [DW_TAG_immutable_type] = "immutable_type",
+#endif
};
static const char *dwarf_gnu_tag_names[] = {
@@ -103,11 +116,15 @@ static const char *dwarf_gnu_tag_names[] = {
const char *dwarf_tag_name(const uint32_t tag)
{
if (tag >= DW_TAG_array_type && tag <=
+#if _ELFUTILS_PREREQ(0, 170)
+ DW_TAG_immutable_type
+#else
#ifdef STB_GNU_UNIQUE
DW_TAG_rvalue_reference_type
#else
DW_TAG_shared_type
#endif
+#endif
)
return dwarf_tag_names[tag];
else if (tag >= DW_TAG_MIPS_loop && tag <=
@@ -123,7 +140,7 @@ const char *dwarf_tag_name(const uint32_t tag)
return "INVALID";
}
-static const struct conf_fprintf conf_fprintf__defaults = {
+static struct conf_fprintf conf_fprintf__defaults = {
.name_spacing = 23,
.type_spacing = 26,
.emit_stats = 1,
@@ -131,11 +148,10 @@ static const struct conf_fprintf conf_fprintf__defaults = {
const char tabs[] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
-static size_t cacheline_size;
-size_t tag__nr_cachelines(const struct tag *tag, const struct cu *cu)
+size_t tag__nr_cachelines(const struct conf_fprintf *conf, const struct tag *tag, const struct cu *cu)
{
- return (tag__size(tag, cu) + cacheline_size - 1) / cacheline_size;
+ return (tag__size(tag, cu) + conf->cacheline_size - 1) / conf->cacheline_size;
}
static const char *tag__accessibility(const struct tag *tag)
@@ -248,8 +264,7 @@ static size_t array_type__fprintf(const struct tag *tag,
return printed;
}
-static size_t string_type__fprintf(const struct tag *tag,
- const struct cu *cu, const char *name,
+static size_t string_type__fprintf(const struct tag *tag, const char *name,
const struct conf_fprintf *conf,
FILE *fp)
{
@@ -274,21 +289,19 @@ size_t typedef__fprintf(const struct tag *tag, const struct cu *cu,
* to avoid all these checks?
*/
if (tag->type == 0)
- return fprintf(fp, "typedef void %s", type__name(type, cu));
+ return fprintf(fp, "typedef void %s", type__name(type));
tag_type = cu__type(cu, tag->type);
if (tag_type == NULL) {
printed = fprintf(fp, "typedef ");
printed += tag__id_not_found_fprintf(fp, tag->type);
- return printed + fprintf(fp, " %s", type__name(type, cu));
+ return printed + fprintf(fp, " %s", type__name(type));
}
switch (tag_type->tag) {
case DW_TAG_array_type:
printed = fprintf(fp, "typedef ");
- return printed + array_type__fprintf(tag_type, cu,
- type__name(type, cu),
- pconf, fp);
+ return printed + array_type__fprintf(tag_type, cu, type__name(type), pconf, fp);
case DW_TAG_pointer_type:
if (tag_type->type == 0) /* void pointer */
break;
@@ -296,8 +309,7 @@ size_t typedef__fprintf(const struct tag *tag, const struct cu *cu,
if (ptr_type == NULL) {
printed = fprintf(fp, "typedef ");
printed += tag__id_not_found_fprintf(fp, tag_type->type);
- return printed + fprintf(fp, " *%s",
- type__name(type, cu));
+ return printed + fprintf(fp, " *%s", type__name(type));
}
if (ptr_type->tag != DW_TAG_subroutine_type)
break;
@@ -306,40 +318,35 @@ size_t typedef__fprintf(const struct tag *tag, const struct cu *cu,
/* Fall thru */
case DW_TAG_subroutine_type:
printed = fprintf(fp, "typedef ");
- return printed + ftype__fprintf(tag__ftype(tag_type), cu,
- type__name(type, cu),
- 0, is_pointer, 0,
- true, pconf, fp);
+ return printed + ftype__fprintf(tag__ftype(tag_type), cu, type__name(type),
+ 0, is_pointer, 0, true, pconf, fp);
case DW_TAG_class_type:
case DW_TAG_structure_type: {
struct type *ctype = tag__type(tag_type);
- if (type__name(ctype, cu) != NULL)
- return fprintf(fp, "typedef struct %s %s",
- type__name(ctype, cu),
- type__name(type, cu));
+ if (type__name(ctype) != NULL)
+ return fprintf(fp, "typedef struct %s %s", type__name(ctype), type__name(type));
struct conf_fprintf tconf = *pconf;
- tconf.suffix = type__name(type, cu);
+ tconf.suffix = type__name(type);
return fprintf(fp, "typedef ") + __class__fprintf(tag__class(tag_type), cu, &tconf, fp);
}
case DW_TAG_enumeration_type: {
struct type *ctype = tag__type(tag_type);
- if (type__name(ctype, cu) != NULL)
- return fprintf(fp, "typedef enum %s %s", type__name(ctype, cu), type__name(type, cu));
+ if (type__name(ctype) != NULL)
+ return fprintf(fp, "typedef enum %s %s", type__name(ctype), type__name(type));
struct conf_fprintf tconf = *pconf;
- tconf.suffix = type__name(type, cu);
- return fprintf(fp, "typedef ") + enumeration__fprintf(tag_type, cu, &tconf, fp);
+ tconf.suffix = type__name(type);
+ return fprintf(fp, "typedef ") + enumeration__fprintf(tag_type, &tconf, fp);
}
}
return fprintf(fp, "typedef %s %s",
- tag__name(tag_type, cu, bf, sizeof(bf), pconf),
- type__name(type, cu));
+ tag__name(tag_type, cu, bf, sizeof(bf), pconf), type__name(type));
}
static size_t imported_declaration__fprintf(const struct tag *tag,
@@ -365,12 +372,12 @@ static size_t imported_module__fprintf(const struct tag *tag,
const char *name = "<IMPORTED MODULE ERROR!>";
if (tag__is_namespace(module))
- name = namespace__name(tag__namespace(module), cu);
+ name = namespace__name(tag__namespace(module));
return fprintf(fp, "using namespace %s", name);
}
-int enumeration__max_entry_name_len(struct type *type, const struct cu *cu)
+static int enumeration__max_entry_name_len(struct type *type)
{
if (type->max_tag_name_len)
goto out;
@@ -378,7 +385,7 @@ int enumeration__max_entry_name_len(struct type *type, const struct cu *cu)
struct enumerator *pos;
type__for_each_enumerator(type, pos) {
- int len = strlen(enumerator__name(pos, cu));
+ int len = strlen(enumerator__name(pos));
if (type->max_tag_name_len < len)
type->max_tag_name_len = len;
@@ -387,23 +394,23 @@ out:
return type->max_tag_name_len;
}
-size_t enumeration__fprintf(const struct tag *tag, const struct cu *cu,
- const struct conf_fprintf *conf, FILE *fp)
+size_t enumeration__fprintf(const struct tag *tag, const struct conf_fprintf *conf, FILE *fp)
{
struct type *type = tag__type(tag);
struct enumerator *pos;
- int max_entry_name_len = enumeration__max_entry_name_len(type, cu);
- size_t printed = fprintf(fp, "enum%s%s {\n",
- type__name(type, cu) ? " " : "",
- type__name(type, cu) ?: "");
+ int max_entry_name_len = enumeration__max_entry_name_len(type);
+ size_t printed = fprintf(fp, "enum%s%s {\n", type__name(type) ? " " : "", type__name(type) ?: "");
int indent = conf->indent;
if (indent >= (int)sizeof(tabs))
indent = sizeof(tabs) - 1;
- type__for_each_enumerator(type, pos)
- printed += fprintf(fp, "%.*s\t%-*s = %u,\n", indent, tabs,
- max_entry_name_len, enumerator__name(pos, cu), pos->value);
+ type__for_each_enumerator(type, pos) {
+ printed += fprintf(fp, "%.*s\t%-*s = ", indent, tabs,
+ max_entry_name_len, enumerator__name(pos));
+ printed += fprintf(fp, conf->hex_fmt ? "%#x" : "%u", pos->value);
+ printed += fprintf(fp, ",\n");
+ }
printed += fprintf(fp, "%.*s}", indent, tabs);
@@ -494,14 +501,13 @@ static const char *__tag__name(const struct tag *tag, const struct cu *cu,
char bf2[64];
if (bt->name)
- name = base_type__name(tag__base_type(tag), cu,
- bf2, sizeof(bf2));
+ name = base_type__name(tag__base_type(tag), bf2, sizeof(bf2));
strncpy(bf, name, len);
}
break;
case DW_TAG_subprogram:
- strncpy(bf, function__name(tag__function(tag), cu), len);
+ strncpy(bf, function__name(tag__function(tag)), len);
break;
case DW_TAG_pointer_type:
return tag__ptr_name(tag, cu, bf, len, "*");
@@ -513,8 +519,7 @@ static const char *__tag__name(const struct tag *tag, const struct cu *cu,
type = cu__type(cu, id);
if (type != NULL)
- snprintf(suffix, sizeof(suffix), "%s::*",
- class__name(tag__class(type), cu));
+ snprintf(suffix, sizeof(suffix), "%s::*", class__name(tag__class(type)));
else {
size_t l = tag__id_not_found_snprintf(suffix,
sizeof(suffix),
@@ -564,14 +569,14 @@ static const char *__tag__name(const struct tag *tag, const struct cu *cu,
}
break;
case DW_TAG_member:
- snprintf(bf, len, "%s", class_member__name(tag__class_member(tag), cu));
+ snprintf(bf, len, "%s", class_member__name(tag__class_member(tag)));
break;
case DW_TAG_variable:
- snprintf(bf, len, "%s", variable__name(tag__variable(tag), cu));
+ snprintf(bf, len, "%s", variable__name(tag__variable(tag)));
break;
default:
snprintf(bf, len, "%s%s", tag__prefix(cu, tag->tag, pconf),
- type__name(tag__type(tag), cu) ?: "");
+ type__name(tag__type(tag)) ?: "");
break;
}
@@ -618,7 +623,7 @@ static size_t type__fprintf_stats(struct type *type, const struct cu *cu,
{
size_t printed = fprintf(fp, "\n%.*s/* size: %d, cachelines: %zd, members: %u",
conf->indent, tabs, type->size,
- tag__nr_cachelines(type__tag(type), cu), type->nr_members);
+ tag__nr_cachelines(conf, type__tag(type), cu), type->nr_members);
if (type->nr_static_members != 0)
printed += fprintf(fp, ", static members: %u */\n", type->nr_static_members);
@@ -697,11 +702,9 @@ static size_t type__fprintf(struct tag *type, const struct cu *cu,
ctype = tag__type(type);
if (typedef_expanded)
- printed += fprintf(fp, " -> %s",
- type__name(ctype, cu));
+ printed += fprintf(fp, " -> %s", type__name(ctype));
else {
- printed += fprintf(fp, "/* typedef %s",
- type__name(ctype, cu));
+ printed += fprintf(fp, "/* typedef %s", type__name(ctype));
typedef_expanded = 1;
}
type_type = cu__type(cu, type->type);
@@ -746,7 +749,7 @@ next_type:
break;
}
if ((tag__is_struct(ptype) || tag__is_union(ptype) ||
- tag__is_enumeration(ptype)) && type__name(tag__type(ptype), cu) == NULL) {
+ tag__is_enumeration(ptype)) && type__name(tag__type(ptype)) == NULL) {
if (name == namebfptr)
goto out_type_not_found;
snprintf(namebfptr, sizeof(namebfptr), "* %.*s", (int)sizeof(namebfptr) - 3, name);
@@ -785,18 +788,18 @@ print_default:
printed += array_type__fprintf(type, cu, name, &tconf, fp);
break;
case DW_TAG_string_type:
- printed += string_type__fprintf(type, cu, name, &tconf, fp);
+ printed += string_type__fprintf(type, name, &tconf, fp);
break;
case DW_TAG_class_type:
case DW_TAG_structure_type:
ctype = tag__type(type);
- if (type__name(ctype, cu) != NULL && !expand_types) {
+ if (type__name(ctype) != NULL && !expand_types) {
printed += fprintf(fp, "%s %-*s %s",
(type->tag == DW_TAG_class_type &&
!tconf.classes_as_structs) ? "class" : "struct",
tconf.type_spacing - 7,
- type__name(ctype, cu), name);
+ type__name(ctype), name ?: "");
} else {
struct class *cclass = tag__class(type);
@@ -810,10 +813,8 @@ print_default:
case DW_TAG_union_type:
ctype = tag__type(type);
- if (type__name(ctype, cu) != NULL && !expand_types) {
- printed += fprintf(fp, "union %-*s %s",
- tconf.type_spacing - 6,
- type__name(ctype, cu), name);
+ if (type__name(ctype) != NULL && !expand_types) {
+ printed += fprintf(fp, "union %-*s %s", tconf.type_spacing - 6, type__name(ctype), name ?: "");
} else {
tconf.type_spacing -= 8;
printed += union__fprintf(ctype, cu, &tconf, fp);
@@ -822,12 +823,10 @@ print_default:
case DW_TAG_enumeration_type:
ctype = tag__type(type);
- if (type__name(ctype, cu) != NULL)
- printed += fprintf(fp, "enum %-*s %s",
- tconf.type_spacing - 5,
- type__name(ctype, cu), name);
+ if (type__name(ctype) != NULL)
+ printed += fprintf(fp, "enum %-*s %s", tconf.type_spacing - 5, type__name(ctype), name ?: "");
else
- printed += enumeration__fprintf(type, cu, &tconf, fp);
+ printed += enumeration__fprintf(type, &tconf, fp);
break;
}
out:
@@ -850,10 +849,11 @@ static size_t class_member__fprintf(struct class_member *member, bool union_memb
struct conf_fprintf *conf, FILE *fp)
{
const int size = member->byte_size;
+ int member_alignment_printed = 0;
struct conf_fprintf sconf = *conf;
uint32_t offset = member->byte_offset;
size_t printed = 0, printed_cacheline = 0;
- const char *cm_name = class_member__name(member, cu),
+ const char *cm_name = class_member__name(member),
*name = cm_name;
if (!sconf.rel_offset) {
@@ -876,7 +876,21 @@ static size_t class_member__fprintf(struct class_member *member, bool union_memb
if (member->is_static)
printed += fprintf(fp, "static ");
- printed += type__fprintf(type, cu, name, &sconf, fp);
+ /* For struct-like constructs, the name of the member cannot be
+ * conflated with the name of its type, otherwise __attribute__ are
+ * printed in the wrong order.
+ */
+ if (tag__is_union(type) || tag__is_struct(type) ||
+ tag__is_enumeration(type)) {
+ printed += type__fprintf(type, cu, NULL, &sconf, fp);
+ if (name) {
+ if (!type__name(tag__type(type)))
+ printed += fprintf(fp, " ");
+ printed += fprintf(fp, "%s", name);
+ }
+ } else {
+ printed += type__fprintf(type, cu, name, &sconf, fp);
+ }
if (member->is_static) {
if (member->const_value != 0)
@@ -885,8 +899,10 @@ static size_t class_member__fprintf(struct class_member *member, bool union_memb
printed += fprintf(fp, ":%u", member->bitfield_size);
}
- if (!sconf.suppress_aligned_attribute && member->alignment != 0)
- printed += fprintf(fp, " __attribute__((__aligned__(%u)))", member->alignment);
+ if (!sconf.suppress_aligned_attribute && member->alignment != 0) {
+ member_alignment_printed = fprintf(fp, " __attribute__((__aligned__(%u)))", member->alignment);
+ printed += member_alignment_printed;
+ }
fputc(';', fp);
++printed;
@@ -894,10 +910,10 @@ static size_t class_member__fprintf(struct class_member *member, bool union_memb
if ((tag__is_union(type) || tag__is_struct(type) ||
tag__is_enumeration(type)) &&
/* Look if is a type defined inline */
- type__name(tag__type(type), cu) == NULL) {
+ type__name(tag__type(type)) == NULL) {
if (!sconf.suppress_offset_comment) {
/* Check if this is a anonymous union */
- int slen = cm_name ? (int)strlen(cm_name) : -1;
+ int slen = member_alignment_printed + (cm_name ? (int)strlen(cm_name) : -1);
int size_spacing = 5;
if (tag__is_struct(type) && tag__class(type)->is_packed && !conf->suppress_packed) {
@@ -905,12 +921,6 @@ static size_t class_member__fprintf(struct class_member *member, bool union_memb
slen += packed_len;
}
- if (tag__type(type)->alignment != 0 && !conf->suppress_aligned_attribute) {
- char bftmp[64];
- int aligned_len = snprintf(bftmp, sizeof(bftmp), " __attribute__((__aligned__(%u)))", tag__type(type)->alignment);
- slen += aligned_len;
- }
-
printed += fprintf(fp, sconf.hex_fmt ?
"%*s/* %#5x" :
"%*s/* %5u",
@@ -995,8 +1005,8 @@ static size_t union__fprintf(struct type *type, const struct cu *cu,
if (conf->prefix != NULL)
printed += fprintf(fp, "%s ", conf->prefix);
- printed += fprintf(fp, "union%s%s {\n", type__name(type, cu) ? " " : "",
- type__name(type, cu) ?: "");
+ printed += fprintf(fp, "union%s%s {\n", type__name(type) ? " " : "",
+ type__name(type) ?: "");
uconf = *conf;
uconf.indent = indent + 1;
@@ -1081,7 +1091,7 @@ size_t ftype__fprintf_parms(const struct ftype *ftype,
indent, tabs);
} else
first_parm = 0;
- name = conf->no_parm_names ? NULL : parameter__name(pos, cu);
+ name = conf->no_parm_names ? NULL : parameter__name(pos);
type = cu__type(cu, pos->tag.type);
if (type == NULL) {
snprintf(sbf, sizeof(sbf),
@@ -1155,7 +1165,7 @@ static size_t function__tag_fprintf(const struct tag *tag, const struct cu *cu,
break;
}
printed = fprintf(fp, "%.*s", indent, tabs);
- name = function__name(alias, cu);
+ name = function__name(alias);
n = fprintf(fp, "%s", name);
size_t namelen = 0;
if (name != NULL)
@@ -1167,7 +1177,7 @@ static size_t function__tag_fprintf(const struct tag *tag, const struct cu *cu,
exp->size, (unsigned long long)exp->ip.addr);
#if 0
n = fprintf(fp, "%s(); /* size=%zd, low_pc=%#llx */",
- function__name(alias, cu), exp->size,
+ function__name(alias), exp->size,
(unsigned long long)exp->ip.addr);
#endif
c = 69;
@@ -1178,7 +1188,7 @@ static size_t function__tag_fprintf(const struct tag *tag, const struct cu *cu,
printed = fprintf(fp, "%.*s", indent, tabs);
n = fprintf(fp, "%s %s; /* scope: %s */",
variable__type_name(vtag, cu, bf, sizeof(bf)),
- variable__name(vtag, cu),
+ variable__name(vtag),
variable__scope_str(vtag));
c += n;
printed += n;
@@ -1188,7 +1198,7 @@ static size_t function__tag_fprintf(const struct tag *tag, const struct cu *cu,
printed = fprintf(fp, "%.*s", indent, tabs);
fputc('\n', fp);
++printed;
- c = fprintf(fp, "%s:", label__name(label, cu));
+ c = fprintf(fp, "%s:", label__name(label));
printed += c;
}
break;
@@ -1227,7 +1237,7 @@ size_t lexblock__fprintf(const struct lexblock *block, const struct cu *cu,
(unsigned long long)block->ip.addr);
else
printed += fprintf(fp, " /* %s+%#llx */",
- function__name(function, cu),
+ function__name(function),
(unsigned long long)offset);
}
printed += fprintf(fp, "\n");
@@ -1272,7 +1282,7 @@ 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(ftype, cu, function__name(func, cu),
+ printed += ftype__fprintf(ftype, cu, function__name(func),
inlined, 0, 0, false, conf, fp);
if (func->virtuality == DW_VIRTUALITY_pure_virtual)
@@ -1306,11 +1316,11 @@ static size_t class__fprintf_cacheline_boundary(struct conf_fprintf *conf,
FILE *fp)
{
int indent = conf->indent;
- uint32_t cacheline = offset / cacheline_size;
+ uint32_t cacheline = offset / conf->cacheline_size;
size_t printed = 0;
if (cacheline > *conf->cachelinep) {
- const uint32_t cacheline_pos = offset % cacheline_size;
+ const uint32_t cacheline_pos = offset % conf->cacheline_size;
const uint32_t cacheline_in_bytes = offset - cacheline_pos;
if (cacheline_pos == 0)
@@ -1330,8 +1340,7 @@ static size_t class__fprintf_cacheline_boundary(struct conf_fprintf *conf,
return printed;
}
-static size_t class__vtable_fprintf(struct class *class, const struct cu *cu,
- const struct conf_fprintf *conf, FILE *fp)
+static size_t class__vtable_fprintf(struct class *class, const struct conf_fprintf *conf, FILE *fp)
{
struct function *pos;
size_t printed = 0;
@@ -1345,8 +1354,8 @@ static size_t class__vtable_fprintf(struct class *class, const struct cu *cu,
list_for_each_entry(pos, &class->vtable, vtable_node) {
printed += fprintf(fp, "%.*s [%d] = %s(%s), \n",
conf->indent, tabs, pos->vtable_entry,
- function__name(pos, cu),
- function__linkage_name(pos, cu));
+ function__name(pos),
+ function__linkage_name(pos));
}
printed += fprintf(fp, "%.*s} */", conf->indent, tabs);
@@ -1381,8 +1390,8 @@ static size_t __class__fprintf(struct class *class, const struct cu *cu,
t == DW_TAG_structure_type) ? "struct" :
t == DW_TAG_class_type ? "class" :
"interface"),
- type__name(type, cu) ? " " : "",
- type__name(type, cu) ?: "");
+ type__name(type) ? " " : "",
+ type__name(type) ?: "");
int indent = cconf.indent;
if (indent >= (int)sizeof(tabs))
@@ -1421,7 +1430,7 @@ static size_t __class__fprintf(struct class *class, const struct cu *cu,
struct tag *pos_type = cu__type(cu, tag_pos->type);
if (pos_type != NULL)
printed += fprintf(fp, " %s",
- type__name(tag__type(pos_type), cu));
+ type__name(tag__type(pos_type)));
else
printed += tag__id_not_found_fprintf(fp, tag_pos->type);
}
@@ -1702,7 +1711,7 @@ static size_t __class__fprintf(struct class *class, const struct cu *cu,
}
if (!cconf.show_only_data_members)
- class__vtable_fprintf(class, cu, &cconf, fp);
+ class__vtable_fprintf(class, &cconf, fp);
if (!cconf.emit_stats)
goto out;
@@ -1753,7 +1762,7 @@ static size_t __class__fprintf(struct class *class, const struct cu *cu,
}
printed += fprintf(fp, " */\n");
}
- cacheline = (cconf.base_offset + type->size) % cacheline_size;
+ cacheline = (cconf.base_offset + type->size) % conf->cacheline_size;
if (cacheline != 0)
printed += fprintf(fp, "%.*s/* last cacheline: %u bytes */\n",
cconf.indent, tabs,
@@ -1764,7 +1773,7 @@ static size_t __class__fprintf(struct class *class, const struct cu *cu,
printed += fprintf(fp, "%.*s/* first biggest size base type member: %s %u %zd */\n",
cconf.indent, tabs,
- class_member__name(m, cu), m->byte_offset,
+ class_member__name(m), m->byte_offset,
m->byte_size);
}
@@ -1806,7 +1815,7 @@ static size_t variable__fprintf(const struct tag *tag, const struct cu *cu,
const struct conf_fprintf *conf, FILE *fp)
{
const struct variable *var = tag__variable(tag);
- const char *name = variable__name(var, cu);
+ const char *name = variable__name(var);
size_t printed = 0;
if (name != NULL) {
@@ -1827,8 +1836,7 @@ static size_t namespace__fprintf(const struct tag *tag, const struct cu *cu,
{
struct namespace *space = tag__namespace(tag);
struct conf_fprintf cconf = *conf;
- size_t printed = fprintf(fp, "namespace %s {\n",
- namespace__name(space, cu));
+ size_t printed = fprintf(fp, "namespace %s {\n", namespace__name(space));
struct tag *pos;
++cconf.indent;
@@ -1887,7 +1895,7 @@ size_t tag__fprintf(struct tag *tag, const struct cu *cu,
printed += array_type__fprintf(tag, cu, "array", pconf, fp);
break;
case DW_TAG_enumeration_type:
- printed += enumeration__fprintf(tag, cu, pconf, fp);
+ printed += enumeration__fprintf(tag, pconf, fp);
break;
case DW_TAG_typedef:
printed += typedef__fprintf(tag, cu, pconf, fp);
@@ -1933,8 +1941,7 @@ size_t tag__fprintf(struct tag *tag, const struct cu *cu,
const struct function *func = tag__function(tag);
if (func->linkage_name)
- printed += fprintf(fp, " /* linkage=%s */",
- function__linkage_name(func, cu));
+ printed += fprintf(fp, " /* linkage=%s */", function__linkage_name(func));
}
if (pconf->expand_types)
@@ -1946,22 +1953,58 @@ size_t tag__fprintf(struct tag *tag, const struct cu *cu,
void cus__print_error_msg(const char *progname, const struct cus *cus,
const char *filename, const int err)
{
- if (err == -EINVAL || (cus != NULL && list_empty(&cus->cus)))
+ if (err == -EINVAL || (cus != NULL && cus__empty(cus)))
fprintf(stderr, "%s: couldn't load debugging info from %s\n",
progname, filename);
else
- fprintf(stderr, "%s: %s\n", progname, strerror(err));
+ fprintf(stderr, "%s: %s\n", progname, strerror(-err));
}
-void dwarves__fprintf_init(uint16_t user_cacheline_size)
+#ifndef _SC_LEVEL1_DCACHE_LINESIZE
+int filename__read_int(const char *filename, int *value)
{
+ char line[64];
+ int fd = open(filename, O_RDONLY), err = -1;
+
+ if (fd < 0)
+ return -1;
+
+ if (read(fd, line, sizeof(line)) > 0) {
+ *value = atoi(line);
+ err = 0;
+ }
+
+ close(fd);
+ return err;
+}
+#endif
+
+static long cacheline__size(void)
+{
+#ifdef _SC_LEVEL1_DCACHE_LINESIZE
+ return sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
+#else
+ int value;
+ return filename__read_int("/sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size", &value) == 0 ? value : -1;
+#endif
+}
+
+void dwarves__resolve_cacheline_size(const struct conf_load *conf, uint16_t user_cacheline_size)
+{
+ uint16_t size;
+
if (user_cacheline_size == 0) {
- long sys_cacheline_size = sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
+ long sys_cacheline_size = cacheline__size();
if (sys_cacheline_size > 0)
- cacheline_size = sys_cacheline_size;
+ size = sys_cacheline_size;
else
- cacheline_size = 64; /* Fall back to a sane value */
+ size = 64; /* Fall back to a sane value */
} else
- cacheline_size = user_cacheline_size;
+ size = user_cacheline_size;
+
+ if (conf)
+ conf->conf_fprintf->cacheline_size = size;
+
+ conf_fprintf__defaults.cacheline_size = size;
}
diff --git a/dwarves_reorganize.c b/dwarves_reorganize.c
index bae5b6e..79b159b 100644
--- a/dwarves_reorganize.c
+++ b/dwarves_reorganize.c
@@ -225,7 +225,7 @@ static bool class__move_member(struct class *class, struct class_member *dest,
if (verbose)
fprintf(fp, " bitfield('%s' ... ",
- class_member__name(from, cu));
+ class_member__name(from));
class__for_each_member_safe_from(class, from, pos, tmp) {
/*
* Have we reached the end of the bitfield?
@@ -241,10 +241,10 @@ static bool class__move_member(struct class *class, struct class_member *dest,
list_splice(&from_list, &dest->tag.node);
if (verbose)
fprintf(fp, "'%s')",
- class_member__name(tail_from, cu));
+ class_member__name(tail_from));
} else {
if (verbose)
- fprintf(fp, " '%s'", class_member__name(from, cu));
+ fprintf(fp, " '%s'", class_member__name(from));
/*
* Remove 'from' from the list
*/
@@ -260,8 +260,8 @@ static bool class__move_member(struct class *class, struct class_member *dest,
if (verbose)
fprintf(fp, " from after '%s' to after '%s' */\n",
- class_member__name(from_prev, cu),
- class_member__name(dest, cu));
+ class_member__name(from_prev),
+ class_member__name(dest));
if (from_padding) {
/*
@@ -279,7 +279,7 @@ static bool class__move_member(struct class *class, struct class_member *dest,
if (verbose)
fprintf(fp, "/* adding %zd bytes from %s to "
"the padding */\n",
- from_size, class_member__name(from, cu));
+ from_size, class_member__name(from));
}
} else if (from_was_last) {
class->type.size -= from_size + class->padding;
@@ -358,9 +358,9 @@ static void class__move_bit_member(struct class *class, const struct cu *cu,
if (verbose)
fprintf(fp, "/* Moving '%s:%u' from after '%s' to "
"after '%s:%u' */\n",
- class_member__name(from, cu), from->bitfield_size,
- class_member__name(from_prev, cu),
- class_member__name(dest, cu), dest->bitfield_size);
+ class_member__name(from), from->bitfield_size,
+ class_member__name(from_prev),
+ class_member__name(dest), dest->bitfield_size);
/*
* Remove 'from' from the list
*/
@@ -512,12 +512,12 @@ static int class__demote_bitfields(struct class *class, const struct cu *cu,
char old_bf[64], new_bf[64];
fprintf(fp, "/* Demoting bitfield ('%s' ... '%s') "
"from '%s' to '%s' */\n",
- class_member__name(bitfield_head, cu),
- class_member__name(member, cu),
+ class_member__name(bitfield_head),
+ class_member__name(member),
base_type__name(tag__base_type(old_type_tag),
- cu, old_bf, sizeof(old_bf)),
+ old_bf, sizeof(old_bf)),
base_type__name(tag__base_type(new_type_tag),
- cu, new_bf, sizeof(new_bf)));
+ new_bf, sizeof(new_bf)));
}
class__demote_bitfield_members(class,
@@ -557,11 +557,11 @@ static int class__demote_bitfields(struct class *class, const struct cu *cu,
char old_bf[64], new_bf[64];
fprintf(fp, "/* Demoting bitfield ('%s') "
"from '%s' to '%s' */\n",
- class_member__name(member, cu),
+ class_member__name(member),
base_type__name(tag__base_type(old_type_tag),
- cu, old_bf, sizeof(old_bf)),
+ old_bf, sizeof(old_bf)),
base_type__name(tag__base_type(new_type_tag),
- cu, new_bf, sizeof(new_bf)));
+ new_bf, sizeof(new_bf)));
}
class__demote_bitfield_members(class,
member, member,
diff --git a/elf_symtab.c b/elf_symtab.c
index 741990e..3a31d64 100644
--- a/elf_symtab.c
+++ b/elf_symtab.c
@@ -15,13 +15,15 @@
#define HASHSYMS__BITS 8
#define HASHSYMS__SIZE (1UL << HASHSYMS__BITS)
-struct elf_symtab *elf_symtab__new(const char *name, Elf *elf, GElf_Ehdr *ehdr)
+struct elf_symtab *elf_symtab__new(const char *name, Elf *elf)
{
+ size_t symtab_index;
+
if (name == NULL)
name = ".symtab";
GElf_Shdr shdr;
- Elf_Scn *sec = elf_section_by_name(elf, ehdr, &shdr, name, NULL);
+ Elf_Scn *sec = elf_section_by_name(elf, &shdr, name, &symtab_index);
if (sec == NULL)
return NULL;
@@ -29,7 +31,7 @@ struct elf_symtab *elf_symtab__new(const char *name, Elf *elf, GElf_Ehdr *ehdr)
if (gelf_getshdr(sec, &shdr) == NULL)
return NULL;
- struct elf_symtab *symtab = malloc(sizeof(*symtab));
+ struct elf_symtab *symtab = zalloc(sizeof(*symtab));
if (symtab == NULL)
return NULL;
@@ -41,6 +43,12 @@ struct elf_symtab *elf_symtab__new(const char *name, Elf *elf, GElf_Ehdr *ehdr)
if (symtab->syms == NULL)
goto out_free_name;
+ /*
+ * This returns extended section index table's
+ * section index, if it exists.
+ */
+ int symtab_xindex = elf_scnshndx(sec);
+
sec = elf_getscn(elf, shdr.sh_link);
if (sec == NULL)
goto out_free_name;
@@ -49,11 +57,40 @@ struct elf_symtab *elf_symtab__new(const char *name, Elf *elf, GElf_Ehdr *ehdr)
if (symtab->symstrs == NULL)
goto out_free_name;
+ /*
+ * The .symtab section has optional extended section index
+ * table, load its data so it can be used to resolve symbol's
+ * section index.
+ **/
+ if (symtab_xindex > 0) {
+ GElf_Shdr shdr_xindex;
+ Elf_Scn *sec_xindex;
+
+ sec_xindex = elf_getscn(elf, symtab_xindex);
+ if (sec_xindex == NULL)
+ goto out_free_name;
+
+ if (gelf_getshdr(sec_xindex, &shdr_xindex) == NULL)
+ goto out_free_name;
+
+ /* Extra check to verify it's correct type */
+ if (shdr_xindex.sh_type != SHT_SYMTAB_SHNDX)
+ goto out_free_name;
+
+ /* Extra check to verify it belongs to the .symtab */
+ if (symtab_index != shdr_xindex.sh_link)
+ goto out_free_name;
+
+ symtab->syms_sec_idx_table = elf_getdata(elf_getscn(elf, symtab_xindex), NULL);
+ if (symtab->syms_sec_idx_table == NULL)
+ goto out_free_name;
+ }
+
symtab->nr_syms = shdr.sh_size / shdr.sh_entsize;
return symtab;
out_free_name:
- free(symtab->name);
+ zfree(&symtab->name);
out_delete:
free(symtab);
return NULL;
@@ -63,6 +100,6 @@ void elf_symtab__delete(struct elf_symtab *symtab)
{
if (symtab == NULL)
return;
- free(symtab->name);
+ zfree(&symtab->name);
free(symtab);
}
diff --git a/elf_symtab.h b/elf_symtab.h
index 359add6..5d4cb52 100644
--- a/elf_symtab.h
+++ b/elf_symtab.h
@@ -16,10 +16,12 @@ struct elf_symtab {
uint32_t nr_syms;
Elf_Data *syms;
Elf_Data *symstrs;
+ /* Data of SHT_SYMTAB_SHNDX section. */
+ Elf_Data *syms_sec_idx_table;
char *name;
};
-struct elf_symtab *elf_symtab__new(const char *name, Elf *elf, GElf_Ehdr *ehdr);
+struct elf_symtab *elf_symtab__new(const char *name, Elf *elf);
void elf_symtab__delete(struct elf_symtab *symtab);
static inline uint32_t elf_symtab__nr_symbols(const struct elf_symtab *symtab)
@@ -77,6 +79,19 @@ static inline bool elf_sym__is_local_object(const GElf_Sym *sym)
sym->st_shndx != SHN_UNDEF;
}
+static inline bool
+elf_sym__get(Elf_Data *syms, Elf_Data *syms_sec_idx_table,
+ int id, GElf_Sym *sym, Elf32_Word *sym_sec_idx)
+{
+ if (!gelf_getsymshndx(syms, syms_sec_idx_table, id, sym, sym_sec_idx))
+ return false;
+
+ if (sym->st_shndx != SHN_XINDEX)
+ *sym_sec_idx = sym->st_shndx;
+
+ return true;
+}
+
/**
* elf_symtab__for_each_symbol - iterate thru all the symbols
*
@@ -89,4 +104,18 @@ static inline bool elf_sym__is_local_object(const GElf_Sym *sym)
index < symtab->nr_syms; \
index++, gelf_getsym(symtab->syms, index, &sym))
+/**
+ * elf_symtab__for_each_symbol_index - iterate through all the symbols,
+ * that takes extended symbols indexes into account
+ *
+ * @symtab: struct elf_symtab instance to iterate
+ * @index: uint32_t index
+ * @sym: GElf_Sym iterator
+ * @sym_sec_idx: symbol's index
+ */
+#define elf_symtab__for_each_symbol_index(symtab, id, sym, sym_sec_idx) \
+ for (id = 0; id < symtab->nr_syms; id++) \
+ if (elf_sym__get(symtab->syms, symtab->syms_sec_idx_table, \
+ id, &sym, &sym_sec_idx))
+
#endif /* _ELF_SYMTAB_H_ */
diff --git a/elfcreator.c b/elfcreator.c
index 3bbee84..8e775c5 100644
--- a/elfcreator.c
+++ b/elfcreator.c
@@ -108,7 +108,7 @@ static void update_dyn_cache(ElfCreator *ctor)
ctor->dyndata = elf_getdata(ctor->dynscn, NULL);
}
-void elfcreator_copy_scn(ElfCreator *ctor, Elf *src, Elf_Scn *scn)
+void elfcreator_copy_scn(ElfCreator *ctor, Elf_Scn *scn)
{
Elf_Scn *newscn;
Elf_Data *indata, *outdata;
diff --git a/elfcreator.h b/elfcreator.h
index a071de5..c2c8fe4 100644
--- a/elfcreator.h
+++ b/elfcreator.h
@@ -12,7 +12,7 @@
typedef struct elf_creator ElfCreator;
extern ElfCreator *elfcreator_begin(char *path, Elf *elf);
-extern void elfcreator_copy_scn(ElfCreator *ctor, Elf *src, Elf_Scn *scn);
+extern void elfcreator_copy_scn(ElfCreator *ctor, Elf_Scn *scn);
extern void elfcreator_end(ElfCreator *ctor);
#endif /* ELFCREATOR_H */
diff --git a/gobuffer.c b/gobuffer.c
index 1ea823b..02b2084 100644
--- a/gobuffer.c
+++ b/gobuffer.c
@@ -41,7 +41,10 @@ struct gobuffer *gobuffer__new(void)
void __gobuffer__delete(struct gobuffer *gb)
{
- free(gb->entries);
+ if (gb == NULL)
+ return;
+
+ zfree(&gb->entries);
}
void gobuffer__delete(struct gobuffer *gb)
diff --git a/hash.h b/hash.h
index d3aa416..37958bb 100644
--- a/hash.h
+++ b/hash.h
@@ -16,55 +16,9 @@
#include <stdint.h>
-/* 2^31 + 2^29 - 2^25 + 2^22 - 2^19 - 2^16 + 1 */
-#define GOLDEN_RATIO_PRIME_32 0x9e370001UL
-/* 2^63 + 2^61 - 2^57 + 2^54 - 2^51 - 2^18 + 1 */
-#define GOLDEN_RATIO_PRIME_64 0x9e37fffffffc0001UL
-
-#if __WORDSIZE == 32
-#define GOLDEN_RATIO_PRIME GOLDEN_RATIO_PRIME_32
-#define hash_long(val, bits) hash_32(val, bits)
-#elif __WORDSIZE == 64
-#define hash_long(val, bits) hash_64(val, bits)
-#define GOLDEN_RATIO_PRIME GOLDEN_RATIO_PRIME_64
-#else
-#error Wordsize not 32 or 64
-#endif
-
static inline uint64_t hash_64(const uint64_t val, const unsigned int bits)
{
- uint64_t hash = val;
-
- /* Sigh, gcc can't optimise this alone like it does for 32 bits. */
- uint64_t n = hash;
- n <<= 18;
- hash -= n;
- n <<= 33;
- hash -= n;
- n <<= 3;
- hash += n;
- n <<= 3;
- hash -= n;
- n <<= 4;
- hash += n;
- n <<= 2;
- hash += n;
-
- /* High bits are more random, so use them. */
- return hash >> (64 - bits);
-}
-
-static inline uint32_t hash_32(uint32_t val, unsigned int bits)
-{
- /* On some cpus multiply is faster, on others gcc will do shifts */
- uint32_t hash = val * GOLDEN_RATIO_PRIME_32;
-
- /* High bits are more random, so use them. */
- return hash >> (32 - bits);
+ return (val * 11400714819323198485LLU) >> (64 - bits);
}
-static inline unsigned long hash_ptr(void *ptr, unsigned int bits)
-{
- return hash_long((unsigned long)ptr, bits);
-}
#endif /* _LINUX_HASH_H */
diff --git a/lib/include/bpf b/lib/include/bpf
new file mode 120000
index 0000000..4c41b71
--- /dev/null
+++ b/lib/include/bpf
@@ -0,0 +1 @@
+../bpf/src \ No newline at end of file
diff --git a/libbtf.c b/libbtf.c
deleted file mode 100644
index 3709087..0000000
--- a/libbtf.c
+++ /dev/null
@@ -1,826 +0,0 @@
-/*
- SPDX-License-Identifier: GPL-2.0-only
-
- Copyright (C) 2019 Facebook
- */
-
-#include <fcntl.h>
-#include <gelf.h>
-#include <limits.h>
-#include <malloc.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <stdarg.h>
-
-#include "libbtf.h"
-#include "lib/bpf/include/uapi/linux/btf.h"
-#include "lib/bpf/include/linux/err.h"
-#include "lib/bpf/src/btf.h"
-#include "lib/bpf/src/libbpf.h"
-#include "dutil.h"
-#include "gobuffer.h"
-#include "dwarves.h"
-#include "elf_symtab.h"
-
-struct btf *base_btf;
-uint8_t btf_elf__verbose;
-uint8_t btf_elf__force;
-
-static int btf_var_secinfo_cmp(const void *a, const void *b)
-{
- const struct btf_var_secinfo *av = a;
- const struct btf_var_secinfo *bv = b;
-
- return av->offset - bv->offset;
-}
-
-static int libbpf_log(enum libbpf_print_level level, const char *format, va_list args)
-{
- return vfprintf(stderr, format, args);
-}
-
-int btf_elf__load(struct btf_elf *btfe)
-{
- int err;
-
- libbpf_set_print(libbpf_log);
-
- /* free initial empty BTF */
- btf__free(btfe->btf);
- if (btfe->raw_btf)
- btfe->btf = btf__parse_raw_split(btfe->filename, btfe->base_btf);
- else
- btfe->btf = btf__parse_elf_split(btfe->filename, btfe->base_btf);
-
- err = libbpf_get_error(btfe->btf);
- if (err)
- return err;
-
- return 0;
-}
-
-struct btf_elf *btf_elf__new(const char *filename, Elf *elf, struct btf *base_btf)
-{
- struct btf_elf *btfe = zalloc(sizeof(*btfe));
- GElf_Shdr shdr;
- Elf_Scn *sec;
-
- if (!btfe)
- return NULL;
-
- btfe->in_fd = -1;
- btfe->filename = strdup(filename);
- if (btfe->filename == NULL)
- goto errout;
-
- btfe->base_btf = base_btf;
- btfe->btf = btf__new_empty_split(base_btf);
- if (libbpf_get_error(btfe->btf)) {
- fprintf(stderr, "%s: failed to create empty BTF.\n", __func__);
- goto errout;
- }
-
- if (strstarts(filename, "/sys/kernel/btf/")) {
-try_as_raw_btf:
- btfe->raw_btf = true;
- btfe->wordsize = sizeof(long);
- btfe->is_big_endian = BYTE_ORDER == BIG_ENDIAN;
- btf__set_endianness(btfe->btf,
- btfe->is_big_endian ? BTF_BIG_ENDIAN : BTF_LITTLE_ENDIAN);
- return btfe;
- }
-
- if (elf != NULL) {
- btfe->elf = elf;
- } else {
- btfe->in_fd = open(filename, O_RDONLY);
- if (btfe->in_fd < 0)
- goto errout;
-
- if (elf_version(EV_CURRENT) == EV_NONE) {
- fprintf(stderr, "%s: cannot set libelf version.\n",
- __func__);
- goto errout;
- }
-
- btfe->elf = elf_begin(btfe->in_fd, ELF_C_READ_MMAP, NULL);
- if (!btfe->elf) {
- fprintf(stderr, "%s: cannot read %s ELF file.\n",
- __func__, filename);
- goto errout;
- }
- }
-
- if (gelf_getehdr(btfe->elf, &btfe->ehdr) == NULL) {
- struct btf_header hdr;
- if (lseek(btfe->in_fd, 0, SEEK_SET) == 0 &&
- read(btfe->in_fd, &hdr, sizeof(hdr)) == sizeof(hdr) &&
- hdr.magic == BTF_MAGIC) {
- close(btfe->in_fd);
- elf_end(btfe->elf);
- btfe->in_fd = -1;
- goto try_as_raw_btf;
- }
- if (btf_elf__verbose)
- fprintf(stderr, "%s: cannot get elf header.\n", __func__);
- goto errout;
- }
-
- switch (btfe->ehdr.e_ident[EI_DATA]) {
- case ELFDATA2LSB:
- btfe->is_big_endian = false;
- btf__set_endianness(btfe->btf, BTF_LITTLE_ENDIAN);
- break;
- case ELFDATA2MSB:
- btfe->is_big_endian = true;
- btf__set_endianness(btfe->btf, BTF_BIG_ENDIAN);
- break;
- default:
- fprintf(stderr, "%s: unknown elf endianness.\n", __func__);
- goto errout;
- }
-
- switch (btfe->ehdr.e_ident[EI_CLASS]) {
- case ELFCLASS32: btfe->wordsize = 4; break;
- case ELFCLASS64: btfe->wordsize = 8; break;
- default: btfe->wordsize = 0; break;
- }
-
- btfe->symtab = elf_symtab__new(NULL, btfe->elf, &btfe->ehdr);
- if (!btfe->symtab) {
- if (btf_elf__verbose)
- printf("%s: '%s' doesn't have symtab.\n", __func__,
- btfe->filename);
- return btfe;
- }
-
- /* find percpu section's shndx */
- sec = elf_section_by_name(btfe->elf, &btfe->ehdr, &shdr, PERCPU_SECTION,
- NULL);
- if (!sec) {
- if (btf_elf__verbose)
- printf("%s: '%s' doesn't have '%s' section\n", __func__,
- btfe->filename, PERCPU_SECTION);
- return btfe;
- }
- btfe->percpu_shndx = elf_ndxscn(sec);
- btfe->percpu_base_addr = shdr.sh_addr;
- btfe->percpu_sec_sz = shdr.sh_size;
-
- return btfe;
-
-errout:
- btf_elf__delete(btfe);
- return NULL;
-}
-
-void btf_elf__delete(struct btf_elf *btfe)
-{
- if (!btfe)
- return;
-
- if (btfe->in_fd != -1) {
- close(btfe->in_fd);
- if (btfe->elf)
- elf_end(btfe->elf);
- }
-
- elf_symtab__delete(btfe->symtab);
- __gobuffer__delete(&btfe->percpu_secinfo);
- btf__free(btfe->btf);
- free(btfe->filename);
- free(btfe);
-}
-
-const char *btf_elf__string(struct btf_elf *btfe, uint32_t ref)
-{
- const char *s = btf__str_by_offset(btfe->btf, ref);
-
- return s && s[0] == '\0' ? NULL : s;
-}
-
-#define BITS_PER_BYTE 8
-#define BITS_PER_BYTE_MASK (BITS_PER_BYTE - 1)
-#define BITS_PER_BYTE_MASKED(bits) ((bits) & BITS_PER_BYTE_MASK)
-#define BITS_ROUNDDOWN_BYTES(bits) ((bits) >> 3)
-#define BITS_ROUNDUP_BYTES(bits) (BITS_ROUNDDOWN_BYTES(bits) + !!BITS_PER_BYTE_MASKED(bits))
-
-static const char * const btf_kind_str[NR_BTF_KINDS] = {
- [BTF_KIND_UNKN] = "UNKNOWN",
- [BTF_KIND_INT] = "INT",
- [BTF_KIND_PTR] = "PTR",
- [BTF_KIND_ARRAY] = "ARRAY",
- [BTF_KIND_STRUCT] = "STRUCT",
- [BTF_KIND_UNION] = "UNION",
- [BTF_KIND_ENUM] = "ENUM",
- [BTF_KIND_FWD] = "FWD",
- [BTF_KIND_TYPEDEF] = "TYPEDEF",
- [BTF_KIND_VOLATILE] = "VOLATILE",
- [BTF_KIND_CONST] = "CONST",
- [BTF_KIND_RESTRICT] = "RESTRICT",
- [BTF_KIND_FUNC] = "FUNC",
- [BTF_KIND_FUNC_PROTO] = "FUNC_PROTO",
- [BTF_KIND_VAR] = "VAR",
- [BTF_KIND_DATASEC] = "DATASEC",
-};
-
-static const char *btf_elf__printable_name(const struct btf_elf *btfe, uint32_t offset)
-{
- if (!offset)
- return "(anon)";
- else
- return btf__str_by_offset(btfe->btf, offset);
-}
-
-static const char * btf_elf__int_encoding_str(uint8_t encoding)
-{
- if (encoding == 0)
- return "(none)";
- else if (encoding == BTF_INT_SIGNED)
- return "SIGNED";
- else if (encoding == BTF_INT_CHAR)
- return "CHAR";
- else if (encoding == BTF_INT_BOOL)
- return "BOOL";
- else
- return "UNKN";
-}
-
-
-__attribute ((format (printf, 5, 6)))
-static void btf_elf__log_err(const struct btf_elf *btfe, int kind, const char *name,
- bool output_cr, const char *fmt, ...)
-{
- fprintf(stderr, "[%u] %s %s", btf__get_nr_types(btfe->btf) + 1,
- btf_kind_str[kind], name ?: "(anon)");
-
- if (fmt && *fmt) {
- va_list ap;
-
- fprintf(stderr, " ");
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
- }
-
- if (output_cr)
- fprintf(stderr, "\n");
-}
-
-__attribute ((format (printf, 5, 6)))
-static void btf_elf__log_type(const struct btf_elf *btfe, const struct btf_type *t,
- bool err, bool output_cr, const char *fmt, ...)
-{
- uint8_t kind;
- FILE *out;
-
- if (!btf_elf__verbose && !err)
- return;
-
- kind = BTF_INFO_KIND(t->info);
- out = err ? stderr : stdout;
-
- fprintf(out, "[%u] %s %s",
- btf__get_nr_types(btfe->btf), btf_kind_str[kind],
- btf_elf__printable_name(btfe, t->name_off));
-
- if (fmt && *fmt) {
- va_list ap;
-
- fprintf(out, " ");
- va_start(ap, fmt);
- vfprintf(out, fmt, ap);
- va_end(ap);
- }
-
- if (output_cr)
- fprintf(out, "\n");
-}
-
-__attribute ((format (printf, 5, 6)))
-static void btf_log_member(const struct btf_elf *btfe,
- const struct btf_type *t,
- const struct btf_member *member,
- bool err, const char *fmt, ...)
-{
- FILE *out;
-
- if (!btf_elf__verbose && !err)
- return;
-
- out = err ? stderr : stdout;
-
- if (btf_kflag(t))
- fprintf(out, "\t%s type_id=%u bitfield_size=%u bits_offset=%u",
- btf_elf__printable_name(btfe, member->name_off),
- member->type,
- BTF_MEMBER_BITFIELD_SIZE(member->offset),
- BTF_MEMBER_BIT_OFFSET(member->offset));
- else
- fprintf(out, "\t%s type_id=%u bits_offset=%u",
- btf_elf__printable_name(btfe, member->name_off),
- member->type,
- member->offset);
-
- if (fmt && *fmt) {
- va_list ap;
-
- fprintf(out, " ");
- va_start(ap, fmt);
- vfprintf(out, fmt, ap);
- va_end(ap);
- }
-
- fprintf(out, "\n");
-}
-
-__attribute ((format (printf, 6, 7)))
-static void btf_log_func_param(const struct btf_elf *btfe,
- const char *name, uint32_t type,
- bool err, bool is_last_param,
- const char *fmt, ...)
-{
- FILE *out;
-
- if (!btf_elf__verbose && !err)
- return;
-
- out = err ? stderr : stdout;
-
- if (is_last_param && !type)
- fprintf(out, "vararg)\n");
- else
- fprintf(out, "%u %s%s", type, name, is_last_param ? ")\n" : ", ");
-
- if (fmt && *fmt) {
- va_list ap;
-
- fprintf(out, " ");
- va_start(ap, fmt);
- vfprintf(out, fmt, ap);
- va_end(ap);
- }
-}
-
-int32_t btf_elf__add_base_type(struct btf_elf *btfe, const struct base_type *bt,
- const char *name)
-{
- struct btf *btf = btfe->btf;
- const struct btf_type *t;
- uint8_t encoding = 0;
- int32_t id;
-
- if (bt->is_signed) {
- encoding = BTF_INT_SIGNED;
- } else if (bt->is_bool) {
- encoding = BTF_INT_BOOL;
- } else if (bt->float_type) {
- fprintf(stderr, "float_type is not supported\n");
- return -1;
- }
-
- id = btf__add_int(btf, name, BITS_ROUNDUP_BYTES(bt->bit_size), encoding);
- if (id < 0) {
- btf_elf__log_err(btfe, BTF_KIND_INT, name, true, "Error emitting BTF type");
- } else {
- t = btf__type_by_id(btf, id);
- btf_elf__log_type(btfe, t, false, true,
- "size=%u nr_bits=%u encoding=%s%s",
- t->size, bt->bit_size,
- btf_elf__int_encoding_str(encoding),
- id < 0 ? " Error in emitting BTF" : "" );
- }
-
- return id;
-}
-
-int32_t btf_elf__add_ref_type(struct btf_elf *btfe, uint16_t kind, uint32_t type,
- const char *name, bool kind_flag)
-{
- struct btf *btf = btfe->btf;
- const struct btf_type *t;
- int32_t id;
-
- switch (kind) {
- case BTF_KIND_PTR:
- id = btf__add_ptr(btf, type);
- break;
- case BTF_KIND_VOLATILE:
- id = btf__add_volatile(btf, type);
- break;
- case BTF_KIND_CONST:
- id = btf__add_const(btf, type);
- break;
- case BTF_KIND_RESTRICT:
- id = btf__add_restrict(btf, type);
- break;
- case BTF_KIND_TYPEDEF:
- id = btf__add_typedef(btf, name, type);
- break;
- case BTF_KIND_FWD:
- id = btf__add_fwd(btf, name, kind_flag);
- break;
- case BTF_KIND_FUNC:
- id = btf__add_func(btf, name, BTF_FUNC_STATIC, type);
- break;
- default:
- btf_elf__log_err(btfe, kind, name, true, "Unexpected kind for reference");
- return -1;
- }
-
- if (id > 0) {
- t = btf__type_by_id(btf, id);
- if (kind == BTF_KIND_FWD)
- btf_elf__log_type(btfe, t, false, true, "%s", kind_flag ? "union" : "struct");
- else
- btf_elf__log_type(btfe, t, false, true, "type_id=%u", t->type);
- } else {
- btf_elf__log_err(btfe, kind, name, true, "Error emitting BTF type");
- }
- return id;
-}
-
-int32_t btf_elf__add_array(struct btf_elf *btfe, uint32_t type, uint32_t index_type, uint32_t nelems)
-{
- struct btf *btf = btfe->btf;
- const struct btf_type *t;
- const struct btf_array *array;
- int32_t id;
-
- id = btf__add_array(btf, index_type, type, nelems);
- if (id > 0) {
- t = btf__type_by_id(btf, id);
- array = btf_array(t);
- btf_elf__log_type(btfe, t, false, true,
- "type_id=%u index_type_id=%u nr_elems=%u",
- array->type, array->index_type, array->nelems);
- } else {
- btf_elf__log_err(btfe, BTF_KIND_ARRAY, NULL, true,
- "type_id=%u index_type_id=%u nr_elems=%u Error emitting BTF type",
- type, index_type, nelems);
- }
- return id;
-}
-
-int btf_elf__add_member(struct btf_elf *btfe, const char *name, uint32_t type,
- uint32_t bitfield_size, uint32_t offset)
-{
- struct btf *btf = btfe->btf;
- const struct btf_type *t;
- const struct btf_member *m;
- int err;
-
- err = btf__add_field(btf, name, type, offset, bitfield_size);
- t = btf__type_by_id(btf, btf__get_nr_types(btf));
- if (err) {
- fprintf(stderr, "[%u] %s %s's field '%s' offset=%u bit_size=%u type=%u Error emitting field\n",
- btf__get_nr_types(btf), btf_kind_str[btf_kind(t)],
- btf_elf__printable_name(btfe, t->name_off),
- name, offset, bitfield_size, type);
- } else {
- m = &btf_members(t)[btf_vlen(t) - 1];
- btf_log_member(btfe, t, m, false, NULL);
- }
- return err;
-}
-
-int32_t btf_elf__add_struct(struct btf_elf *btfe, uint8_t kind, const char *name, uint32_t size)
-{
- struct btf *btf = btfe->btf;
- const struct btf_type *t;
- int32_t id;
-
- switch (kind) {
- case BTF_KIND_STRUCT:
- id = btf__add_struct(btf, name, size);
- break;
- case BTF_KIND_UNION:
- id = btf__add_union(btf, name, size);
- break;
- default:
- btf_elf__log_err(btfe, kind, name, true, "Unexpected kind of struct");
- return -1;
- }
-
- if (id < 0) {
- btf_elf__log_err(btfe, kind, name, true, "Error emitting BTF type");
- } else {
- t = btf__type_by_id(btf, id);
- btf_elf__log_type(btfe, t, false, true, "size=%u", t->size);
- }
-
- return id;
-}
-
-int32_t btf_elf__add_enum(struct btf_elf *btfe, const char *name, uint32_t bit_size)
-{
- struct btf *btf = btfe->btf;
- const struct btf_type *t;
- int32_t id, size;
-
- size = BITS_ROUNDUP_BYTES(bit_size);
- id = btf__add_enum(btf, name, size);
- if (id > 0) {
- t = btf__type_by_id(btf, id);
- btf_elf__log_type(btfe, t, false, true, "size=%u", t->size);
- } else {
- btf_elf__log_err(btfe, BTF_KIND_ENUM, name, true,
- "size=%u Error emitting BTF type", size);
- }
- return id;
-}
-
-int btf_elf__add_enum_val(struct btf_elf *btfe, const char *name, int32_t value)
-{
- struct btf *btf = btfe->btf;
- int err;
-
- err = btf__add_enum_value(btf, name, value);
- if (!err) {
- if (btf_elf__verbose)
- printf("\t%s val=%d\n", name, value);
- } else {
- fprintf(stderr, "\t%s val=%d Error emitting BTF enum value\n",
- name, value);
- }
- return err;
-}
-
-static int32_t btf_elf__add_func_proto_param(struct btf_elf *btfe, const char *name,
- uint32_t type, bool is_last_param)
-{
- int err;
-
- err = btf__add_func_param(btfe->btf, name, type);
- if (!err) {
- btf_log_func_param(btfe, name, type, false, is_last_param, NULL);
- return 0;
- } else {
- btf_log_func_param(btfe, name, type, true, is_last_param,
- "Error adding func param");
- return -1;
- }
-}
-
-extern struct debug_fmt_ops *dwarves__active_loader;
-
-int32_t btf_elf__add_func_proto(struct btf_elf *btfe, struct cu *cu, struct ftype *ftype, uint32_t type_id_off)
-{
- struct btf *btf = btfe->btf;
- const struct btf_type *t;
- struct parameter *param;
- uint16_t nr_params, param_idx;
- int32_t id, type_id;
-
- /* add btf_type for func_proto */
- nr_params = ftype->nr_parms + (ftype->unspec_parms ? 1 : 0);
- type_id = ftype->tag.type == 0 ? 0 : type_id_off + ftype->tag.type;
-
- id = btf__add_func_proto(btf, type_id);
- if (id > 0) {
- t = btf__type_by_id(btf, id);
- btf_elf__log_type(btfe, t, false, false, "return=%u args=(%s",
- t->type, !nr_params ? "void)\n" : "");
- } else {
- btf_elf__log_err(btfe, BTF_KIND_FUNC_PROTO, NULL, true,
- "return=%u vlen=%u Error emitting BTF type",
- type_id, nr_params);
- return id;
- }
-
- /* add parameters */
- param_idx = 0;
- ftype__for_each_parameter(ftype, param) {
- const char *name = dwarves__active_loader->strings__ptr(cu, param->name);
-
- type_id = param->tag.type == 0 ? 0 : type_id_off + param->tag.type;
- ++param_idx;
- if (btf_elf__add_func_proto_param(btfe, name, type_id, param_idx == nr_params))
- return -1;
- }
-
- ++param_idx;
- if (ftype->unspec_parms)
- if (btf_elf__add_func_proto_param(btfe, NULL, 0, param_idx == nr_params))
- return -1;
-
- return id;
-}
-
-int32_t btf_elf__add_var_type(struct btf_elf *btfe, uint32_t type, const char *name,
- uint32_t linkage)
-{
- struct btf *btf = btfe->btf;
- const struct btf_type *t;
- int32_t id;
-
- id = btf__add_var(btf, name, linkage, type);
- if (id > 0) {
- t = btf__type_by_id(btf, id);
- btf_elf__log_type(btfe, t, false, true, "type=%u linkage=%u",
- t->type, btf_var(t)->linkage);
- } else {
- btf_elf__log_err(btfe, BTF_KIND_VAR, name, true,
- "type=%u linkage=%u Error emitting BTF type",
- type, linkage);
- }
- return id;
-}
-
-int32_t btf_elf__add_var_secinfo(struct gobuffer *buf, uint32_t type,
- uint32_t offset, uint32_t size)
-{
- struct btf_var_secinfo si = {
- .type = type,
- .offset = offset,
- .size = size,
- };
- return gobuffer__add(buf, &si, sizeof(si));
-}
-
-int32_t btf_elf__add_datasec_type(struct btf_elf *btfe, const char *section_name,
- struct gobuffer *var_secinfo_buf)
-{
- struct btf *btf = btfe->btf;
- size_t sz = gobuffer__size(var_secinfo_buf);
- uint16_t nr_var_secinfo = sz / sizeof(struct btf_var_secinfo);
- struct btf_var_secinfo *last_vsi, *vsi;
- const struct btf_type *t;
- uint32_t datasec_sz;
- int32_t err, id, i;
-
- qsort(var_secinfo_buf->entries, nr_var_secinfo,
- sizeof(struct btf_var_secinfo), btf_var_secinfo_cmp);
-
- last_vsi = (struct btf_var_secinfo *)var_secinfo_buf->entries + nr_var_secinfo - 1;
- datasec_sz = last_vsi->offset + last_vsi->size;
-
- id = btf__add_datasec(btf, section_name, datasec_sz);
- if (id < 0) {
- btf_elf__log_err(btfe, BTF_KIND_DATASEC, section_name, true,
- "size=%u vlen=%u Error emitting BTF type",
- datasec_sz, nr_var_secinfo);
- } else {
- t = btf__type_by_id(btf, id);
- btf_elf__log_type(btfe, t, false, true, "size=%u vlen=%u",
- t->size, nr_var_secinfo);
- }
-
- for (i = 0; i < nr_var_secinfo; i++) {
- vsi = (struct btf_var_secinfo *)var_secinfo_buf->entries + i;
- err = btf__add_datasec_var_info(btf, vsi->type, vsi->offset, vsi->size);
- if (!err) {
- if (btf_elf__verbose)
- printf("\ttype=%u offset=%u size=%u\n",
- vsi->type, vsi->offset, vsi->size);
- } else {
- fprintf(stderr, "\ttype=%u offset=%u size=%u Error emitting BTF datasec var info\n",
- vsi->type, vsi->offset, vsi->size);
- return -1;
- }
- }
-
- return id;
-}
-
-static int btf_elf__write(const char *filename, struct btf *btf)
-{
- GElf_Shdr shdr_mem, *shdr;
- GElf_Ehdr ehdr_mem, *ehdr;
- Elf_Data *btf_data = NULL;
- Elf_Scn *scn = NULL;
- Elf *elf = NULL;
- const void *raw_btf_data;
- uint32_t raw_btf_size;
- int fd, err = -1;
- size_t strndx;
-
- fd = open(filename, O_RDWR);
- if (fd < 0) {
- fprintf(stderr, "Cannot open %s\n", filename);
- return -1;
- }
-
- if (elf_version(EV_CURRENT) == EV_NONE) {
- fprintf(stderr, "Cannot set libelf version.\n");
- goto out;
- }
-
- elf = elf_begin(fd, ELF_C_RDWR, NULL);
- if (elf == NULL) {
- fprintf(stderr, "Cannot update ELF file.\n");
- goto out;
- }
-
- elf_flagelf(elf, ELF_C_SET, ELF_F_DIRTY);
-
- ehdr = gelf_getehdr(elf, &ehdr_mem);
- if (ehdr == NULL) {
- fprintf(stderr, "%s: elf_getehdr failed.\n", __func__);
- goto out;
- }
-
- switch (ehdr_mem.e_ident[EI_DATA]) {
- case ELFDATA2LSB:
- btf__set_endianness(btf, BTF_LITTLE_ENDIAN);
- break;
- case ELFDATA2MSB:
- btf__set_endianness(btf, BTF_BIG_ENDIAN);
- break;
- default:
- fprintf(stderr, "%s: unknown elf endianness.\n", __func__);
- goto out;
- }
-
- /*
- * First we look if there was already a .BTF section to overwrite.
- */
-
- elf_getshdrstrndx(elf, &strndx);
- while ((scn = elf_nextscn(elf, scn)) != NULL) {
- shdr = gelf_getshdr(scn, &shdr_mem);
- if (shdr == NULL)
- continue;
- char *secname = elf_strptr(elf, strndx, shdr->sh_name);
- if (strcmp(secname, ".BTF") == 0) {
- btf_data = elf_getdata(scn, btf_data);
- break;
- }
- }
-
- raw_btf_data = btf__get_raw_data(btf, &raw_btf_size);
-
- if (btf_data) {
- /* Exisiting .BTF section found */
- btf_data->d_buf = (void *)raw_btf_data;
- btf_data->d_size = raw_btf_size;
- elf_flagdata(btf_data, ELF_C_SET, ELF_F_DIRTY);
-
- if (elf_update(elf, ELF_C_NULL) >= 0 &&
- elf_update(elf, ELF_C_WRITE) >= 0)
- err = 0;
- } else {
- const char *llvm_objcopy;
- char tmp_fn[PATH_MAX];
- char cmd[PATH_MAX * 2];
-
- llvm_objcopy = getenv("LLVM_OBJCOPY");
- if (!llvm_objcopy)
- llvm_objcopy = "llvm-objcopy";
-
- /* Use objcopy to add a .BTF section */
- snprintf(tmp_fn, sizeof(tmp_fn), "%s.btf", filename);
- close(fd);
- fd = creat(tmp_fn, S_IRUSR | S_IWUSR);
- if (fd == -1) {
- fprintf(stderr, "%s: open(%s) failed!\n", __func__,
- tmp_fn);
- goto out;
- }
-
- if (write(fd, raw_btf_data, raw_btf_size) != raw_btf_size) {
- fprintf(stderr, "%s: write of %d bytes to '%s' failed: %d!\n",
- __func__, raw_btf_size, tmp_fn, errno);
- goto out;
- }
-
- snprintf(cmd, sizeof(cmd), "%s --add-section .BTF=%s %s",
- llvm_objcopy, tmp_fn, filename);
- if (system(cmd)) {
- fprintf(stderr, "%s: failed to add .BTF section to '%s': %d!\n",
- __func__, tmp_fn, errno);
- goto out;
- }
-
- err = 0;
- unlink(tmp_fn);
- }
-
-out:
- if (fd != -1)
- close(fd);
- if (elf)
- elf_end(elf);
- return err;
-}
-
-int btf_elf__encode(struct btf_elf *btfe, uint8_t flags)
-{
- struct btf *btf = btfe->btf;
-
- /* Empty file, nothing to do, so... done! */
- if (btf__get_nr_types(btf) == 0)
- return 0;
-
- if (btf__dedup(btf, NULL, NULL)) {
- fprintf(stderr, "%s: btf__dedup failed!\n", __func__);
- return -1;
- }
-
- return btf_elf__write(btfe->filename, btf);
-}
diff --git a/libbtf.h b/libbtf.h
deleted file mode 100644
index 191f586..0000000
--- a/libbtf.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- SPDX-License-Identifier: GPL-2.0-only
-
- Copyright (C) 2019 Facebook
- */
-
-#ifndef _LIBBTF_H
-#define _LIBBTF_H
-
-#include "gobuffer.h"
-
-#include <stdbool.h>
-#include <stdint.h>
-#include "lib/bpf/src/btf.h"
-
-struct btf_elf {
- void *priv;
- Elf *elf;
- GElf_Ehdr ehdr;
- struct elf_symtab *symtab;
- struct gobuffer percpu_secinfo;
- char *filename;
- int in_fd;
- uint8_t wordsize;
- bool is_big_endian;
- bool raw_btf; // "/sys/kernel/btf/vmlinux"
- uint32_t percpu_shndx;
- uint64_t percpu_base_addr;
- uint64_t percpu_sec_sz;
- struct btf *btf;
- struct btf *base_btf;
-};
-
-extern struct btf *base_btf;
-extern uint8_t btf_elf__verbose;
-extern uint8_t btf_elf__force;
-#define btf_elf__verbose_log(fmt, ...) { if (btf_elf__verbose) printf(fmt, __VA_ARGS__); }
-
-#define PERCPU_SECTION ".data..percpu"
-
-struct cu;
-struct base_type;
-struct ftype;
-
-struct btf_elf *btf_elf__new(const char *filename, Elf *elf, struct btf *base_btf);
-void btf_elf__delete(struct btf_elf *btf);
-
-int32_t btf_elf__add_base_type(struct btf_elf *btf, const struct base_type *bt,
- const char *name);
-int32_t btf_elf__add_ref_type(struct btf_elf *btf, uint16_t kind, uint32_t type,
- const char *name, bool kind_flag);
-int btf_elf__add_member(struct btf_elf *btf, const char *name, uint32_t type,
- uint32_t bitfield_size, uint32_t bit_offset);
-int32_t btf_elf__add_struct(struct btf_elf *btf, uint8_t kind, const char *name, uint32_t size);
-int32_t btf_elf__add_array(struct btf_elf *btf, uint32_t type, uint32_t index_type,
- uint32_t nelems);
-int32_t btf_elf__add_enum(struct btf_elf *btf, const char *name, uint32_t size);
-int btf_elf__add_enum_val(struct btf_elf *btf, const char *name, int32_t value);
-int32_t btf_elf__add_func_proto(struct btf_elf *btf, struct cu *cu, struct ftype *ftype,
- uint32_t type_id_off);
-int32_t btf_elf__add_var_type(struct btf_elf *btfe, uint32_t type, const char *name,
- uint32_t linkage);
-int32_t btf_elf__add_var_secinfo(struct gobuffer *buf, uint32_t type,
- uint32_t offset, uint32_t size);
-int32_t btf_elf__add_datasec_type(struct btf_elf *btfe, const char *section_name,
- struct gobuffer *var_secinfo_buf);
-int btf_elf__encode(struct btf_elf *btf, uint8_t flags);
-
-const char *btf_elf__string(struct btf_elf *btf, uint32_t ref);
-int btf_elf__load(struct btf_elf *btf);
-
-#endif /* _LIBBTF_H */
diff --git a/libctf.c b/libctf.c
index 2de3912..edb34db 100644
--- a/libctf.c
+++ b/libctf.c
@@ -19,7 +19,6 @@
#include "ctf.h"
#include "dutil.h"
#include "gobuffer.h"
-#include "pahole_strings.h"
bool ctf__ignore_symtab_function(const GElf_Sym *sym, const char *sym_name)
{
@@ -133,8 +132,7 @@ int ctf__load(struct ctf *ctf)
{
int err = -ENOTSUP;
GElf_Shdr shdr;
- Elf_Scn *sec = elf_section_by_name(ctf->elf, &ctf->ehdr,
- &shdr, ".SUNW_ctf", NULL);
+ Elf_Scn *sec = elf_section_by_name(ctf->elf, &shdr, ".SUNW_ctf", NULL);
if (sec == NULL)
return -ESRCH;
@@ -229,7 +227,7 @@ out_close:
if (elf == NULL)
close(ctf->in_fd);
out_delete_filename:
- free(ctf->filename);
+ zfree(&ctf->filename);
out_delete:
free(ctf);
return NULL;
@@ -246,8 +244,8 @@ void ctf__delete(struct ctf *ctf)
__gobuffer__delete(&ctf->types);
__gobuffer__delete(&ctf->funcs);
elf_symtab__delete(ctf->symtab);
- free(ctf->filename);
- free(ctf->buf);
+ zfree(&ctf->filename);
+ zfree(&ctf->buf);
free(ctf);
}
}
@@ -284,7 +282,7 @@ size_t ctf__get_size(struct ctf *ctf)
int ctf__load_symtab(struct ctf *ctf)
{
- ctf->symtab = elf_symtab__new(".symtab", ctf->elf, &ctf->ehdr);
+ ctf->symtab = elf_symtab__new(".symtab", ctf->elf);
return ctf->symtab == NULL ? -1 : 0;
}
@@ -505,6 +503,7 @@ int ctf__add_object(struct ctf *ctf, uint16_t type)
sizeof(type)) >= 0 ? 0 : -ENOMEM;
}
+#if 0
static const void *ctf__compress(void *orig_buf, unsigned int *size)
{
z_stream z = {
@@ -770,3 +769,4 @@ out_close:
close(fd);
return err;
}
+#endif
diff --git a/list.h b/list.h
index 6072919..d5aee43 100644
--- a/list.h
+++ b/list.h
@@ -290,6 +290,14 @@ static inline void list_splice_init(struct list_head *list,
list_entry((ptr)->next, type, member)
/**
+ * list_next_entry - get the next element in list
+ * @pos: the type * to cursor
+ * @member: the name of the list_head within the struct.
+ */
+#define list_next_entry(pos, member) \
+ list_entry((pos)->member.next, typeof(*(pos)), member)
+
+/**
* list_for_each - iterate over a list
* @pos: the &struct list_head to use as a loop cursor.
* @head: the head for your list.
diff --git a/man-pages/pahole.1 b/man-pages/pahole.1
index 352bb5e..c1ec63e 100644
--- a/man-pages/pahole.1
+++ b/man-pages/pahole.1
@@ -21,7 +21,7 @@ It also uses these structure layouts to pretty print data feed to its standard
input, e.g.:
.PP
.nf
-$ pahole --header elf64_hdr < /lib/modules/5.8.0-rc6+/build/vmlinux
+$ pahole --header elf64_hdr --prettify /lib/modules/5.8.0-rc6+/build/vmlinux
{
.e_ident = { 127, 69, 76, 70, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
.e_type = 2,
@@ -101,6 +101,15 @@ or file URLs (e.g.: file://class_list.txt)
Set cacheline size to SIZE bytes.
.TP
+.B \-\-sort
+Sort the output by type name, maybe this will grow to allow sorting by other
+criteria.
+
+This is mostly needed so that pretty printing from BTF and DWARF can be
+comparable when using using multiple threads to load DWARF data, when the order
+that the types in the compile units is processed is not deterministic.
+
+.TP
.B \-\-count=COUNT
Pretty print the first COUNT records from input.
@@ -120,6 +129,13 @@ includes "ctf" and "dwarf". The default format path used is equivalent to
"-F dwarf,ctf".
.TP
+.B \-\-hashbits=BITS
+Allows specifying the number of bits for the debugging format loader to use.
+The only one affected so far is the "dwarf" one, its default now is 15, the
+maximum for it is now 21 bits. Tweak it to see if it improves performance as
+the kernel evolves and more types and functions have to be loaded.
+
+.TP
.B \-\-hex
Print offsets and sizes in hexadecimal.
@@ -182,6 +198,19 @@ the debugging information.
Do not encode VARs in BTF.
.TP
+.B \-\-skip_encoding_btf_decl_tag
+Do not encode decl tags in BTF.
+
+.TP
+.B \-\-skip_encoding_btf_type_tag
+Do not encode type tags in BTF.
+
+.TP
+.B \-j, \-\-jobs=N
+Run N jobs in parallel. Defaults to number of online processors + 10% (like
+the 'ninja' build system) if no argument is specified.
+
+.TP
.B \-J, \-\-btf_encode
Encode BTF information from DWARF, used in the Linux kernel build process when
CONFIG_DEBUG_INFO_BTF=y is present, introduced in Linux v5.2. Used to implement
@@ -190,6 +219,10 @@ features such as BPF CO-RE (Compile Once - Run Everywhere).
See \fIhttps://nakryiko.com/posts/bpf-portability-and-co-re/\fR.
.TP
+.B \-\-btf_encode_detached=FILENAME
+Same thing as -J/--btf_encode, but storing the raw BTF info into a separate file.
+
+.TP
.B \-\-btf_encode_force
Ignore those symbols found invalid when encoding BTF.
@@ -200,12 +233,30 @@ This may be inferred when asking for a /sys/kernel/btf/MODULE, when it will be a
to "/sys/kernel/btf/vmlinux".
.TP
+.B \-\-btf_gen_floats
+Allow producing BTF_KIND_FLOAT entries in systems where the vmlinux DWARF
+information has float types.
+
+.TP
+.B \-\-btf_gen_all
+Allow using all the BTF features supported by pahole.
+
+.TP
.B \-l, \-\-show_first_biggest_size_base_type_member
Show first biggest size base_type member.
.TP
.B \-m, \-\-nr_methods
-Show number of methods.
+Show number of methods of all classes, i.e. the number of functions have arguments that
+are pointers to a given class.
+
+To get the number of methods for an specific class, please use:
+
+ $ pahole --nr_methods | grep -w sock
+ sock 1005
+ $
+
+In the above example it used the BTF information in /sys/kernel/btf/vmlinux.
.TP
.B \-M, \-\-show_only_data_members
@@ -230,6 +281,10 @@ Show only structs that has holes that can be packed if members are reorganized,
for instance when using the \fB\-\-reorganize\fR option.
.TP
+.B \-P, \-\-with_flexible_array
+Show only structs that have a flexible array.
+
+.TP
.B \-q, \-\-quiet
Be quieter.
@@ -284,6 +339,12 @@ Converts silly bitfields such as "int foo:32" to plain "int foo".
be verbose
.TP
+.B \-\-ptr_table_stats
+Print statistics about ptr_table data structures, used to hold all the types,
+tags and functions data structures, for development tuning of such tables, tuned
+for a typical 2021 vmlinux file.
+
+.TP
.B \-w, \-\-word_size=WORD_SIZE
Change the arch word size to WORD_SIZE.
@@ -327,6 +388,10 @@ Show a traditional string version, i.e.: "v1.18".
Show a numeric only version, suitable for use in Makefiles and scripts where
one wants to know what if the installed version has some feature, i.e.: 118 instead of "v1.18".
+.TP
+.B \-\-kabi_prefix=STRING
+When the prefix of the string is STRING, treat the string as STRING.
+
.SH NOTES
To enable the generation of debugging information in the Linux kernel build
@@ -537,6 +602,11 @@ $ pahole rcu_state | grep raw_spinlock_t -B1 -A5
};
$
.fi
+
+.SH PRETTY PRINTING
+.P
+pahole can also use the data structure types to pretty print raw data specified via --prettify.
+To consume raw data from the standard input, just use '--prettify -'
.P
It can also pretty print raw data from stdin according to the type specified:
.PP
@@ -554,7 +624,7 @@ $
$ ls -la versions
-rw-rw-r--. 1 acme acme 7616 Jun 25 11:33 versions
$
-$ pahole --count 3 -C modversion_info drivers/scsi/sg.ko < versions
+$ pahole --count 3 -C modversion_info drivers/scsi/sg.ko --prettify versions
{
.crc = 0x8dabd84,
.name = "module_layout",
@@ -568,7 +638,7 @@ $ pahole --count 3 -C modversion_info drivers/scsi/sg.ko < versions
.name = "param_ops_int",
},
$
-$ pahole --skip 1 --count 2 -C modversion_info drivers/scsi/sg.ko < versions
+$ pahole --skip 1 --count 2 -C modversion_info drivers/scsi/sg.ko --prettify - < versions
{
.crc = 0x45e4617b,
.name = "no_llseek",
@@ -580,7 +650,7 @@ $ pahole --skip 1 --count 2 -C modversion_info drivers/scsi/sg.ko < versions
$
This is equivalent to:
-$ pahole --seek_bytes 64 --count 1 -C modversion_info drivers/scsi/sg.ko < versions
+$ pahole --seek_bytes 64 --count 1 -C modversion_info drivers/scsi/sg.ko --prettify versions
{
.crc = 0x45e4617b,
.name = "no_llseek",
@@ -589,11 +659,6 @@ $
.fi
.P
-.SH PRETTY PRINTING
-.P
-pahole can also use the data structure types to pretty print raw data coming
-from its standard input.
-
.TP
.B \-C, \-\-class_name=CLASS_NAME
Pretty print according to this class. Arguments may be passed to it to affect how
@@ -636,7 +701,7 @@ $
Now we can use this to show the first record from offset zero:
.PP
.nf
-$ pahole -C elf64_hdr --count 1 < /lib/modules/5.8.0-rc3+/build/vmlinux
+$ pahole -C elf64_hdr --count 1 --prettify /lib/modules/5.8.0-rc3+/build/vmlinux
{
.e_ident = { 127, 69, 76, 70, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
.e_type = 2,
@@ -659,7 +724,7 @@ $
This is equivalent to:
.PP
.nf
-$ pahole --header elf64_hdr < /lib/modules/5.8.0-rc3+/build/vmlinux
+$ pahole --header elf64_hdr --prettify /lib/modules/5.8.0-rc3+/build/vmlinux
.fi
.P
The --header option also allows reference in other command line options to fields in the header.
@@ -667,7 +732,7 @@ This is useful when one wants to show multiple records in a file and the range w
are located is specified in header fields, such as for perf.data files:
.PP
.nf
-$ pahole --hex ~/bin/perf --header perf_file_header < perf.data
+$ pahole --hex ~/bin/perf --header perf_file_header --prettify perf.data
{
.magic = 0x32454c4946524550,
.size = 0x68,
@@ -692,7 +757,7 @@ $
So to display the cgroups records in the perf_file_header.data section we can use:
.PP
.nf
-$ pahole ~/bin/perf --header=perf_file_header --seek_bytes '$header.data.offset' --size_bytes='$header.data.size' -C 'perf_event_header(sizeof,type,type_enum=perf_event_type,filter=type==PERF_RECORD_CGROUP)' < perf.data
+$ pahole ~/bin/perf --header=perf_file_header --seek_bytes '$header.data.offset' --size_bytes='$header.data.size' -C 'perf_event_header(sizeof,type,type_enum=perf_event_type,filter=type==PERF_RECORD_CGROUP)' --prettify perf.data
{
.header = {
.type = PERF_RECORD_CGROUP,
@@ -736,7 +801,7 @@ $ pahole ~/bin/perf --header=perf_file_header --seek_bytes '$header.data.offset'
.size = 88,
},
.id = 13,
- .path = "/machine.slice/machine-qemu\x2d1\x2drhel6.sandy.scope",
+ .path = "/machine.slice/machine-qemu\\x2d1\\x2drhel6.sandy.scope",
},
$
.fi
@@ -744,12 +809,12 @@ $
For the common case of the header having a member that has the 'offset' and 'size' members, it is possible to use this more compact form:
.PP
.nf
-$ pahole ~/bin/perf --header=perf_file_header --range=data -C 'perf_event_header(sizeof,type,type_enum=perf_event_type,filter=type==PERF_RECORD_CGROUP)' < perf.data
+$ pahole ~/bin/perf --header=perf_file_header --range=data -C 'perf_event_header(sizeof,type,type_enum=perf_event_type,filter=type==PERF_RECORD_CGROUP)' --prettify perf.data
.fi
.P
This uses ~/bin/perf to get the type definitions, the defines 'struct perf_file_header' as the header,
then seeks '$header.data.offset' bytes from the start of the file, and considers '$header.data.size' bytes
-worth of such records. The filter expression may omit a common prefix, in this case it could additonally be
+worth of such records. The filter expression may omit a common prefix, in this case it could additionally be
equivalently written as both 'filter=type==CGROUP' or the 'filter=' can also be omitted, getting as compact
as 'type==CGROUP':
.P
@@ -818,7 +883,7 @@ If we remove that type_enum=perf_event_type, we will lose the conversion of 'str
more descriptive 'struct perf_record_cgroup', and also the beautification of the header.type field:
.PP
.nf
-$ pahole ~/bin/perf --header=perf_file_header --seek_bytes '$header.data.offset' --size_bytes='$header.data.size' -C 'perf_event_header(sizeof,type,filter=type==19)' < perf.data
+$ pahole ~/bin/perf --header=perf_file_header --seek_bytes '$header.data.offset' --size_bytes='$header.data.size' -C 'perf_event_header(sizeof,type,filter=type==19)' --prettify perf.data
{
.type = 19,
.misc = 0,
@@ -850,7 +915,7 @@ $
Some of the records are not found in 'type_enum=perf_event_type' so some of the records don't get converted to a type that fully shows its contents. For perf we know that those are in another enumeration, 'enum perf_user_event_type', so, for these cases, we can create a 'virtual enum', i.e. the sum of two enums and then get all those entries decoded and properly casted, first few records with just 'enum perf_event_type':
.PP
.nf
-$ pahole ~/bin/perf --header=perf_file_header --seek_bytes '$header.data.offset' --size_bytes='$header.data.size' -C 'perf_event_header(sizeof,type,type_enum=perf_event_type)' --count 4 < perf.data
+$ pahole ~/bin/perf --header=perf_file_header --seek_bytes '$header.data.offset' --size_bytes='$header.data.size' -C 'perf_event_header(sizeof,type,type_enum=perf_event_type)' --count 4 --prettify perf.data
{
.type = 79,
.misc = 0,
@@ -881,7 +946,7 @@ $
Now with both enumerations, i.e. with 'type_enum=perf_event_type+perf_user_event_type':
.PP
.nf
-$ pahole ~/bin/perf --header=perf_file_header --seek_bytes '$header.data.offset' --size_bytes='$header.data.size' -C 'perf_event_header(sizeof,type,type_enum=perf_event_type+perf_user_event_type)' --count 5 < perf.data
+$ pahole ~/bin/perf --header=perf_file_header --seek_bytes '$header.data.offset' --size_bytes='$header.data.size' -C 'perf_event_header(sizeof,type,type_enum=perf_event_type+perf_user_event_type)' --count 5 --prettify perf.data
{
.header = {
.type = PERF_RECORD_TIME_CONV,
@@ -940,7 +1005,7 @@ data range with the following command:
.PP
.nf
pahole ~/bin/perf --header=perf_file_header \
- -C 'perf_file_attr(range=attrs),perf_event_header(range=data,sizeof,type,type_enum=perf_event_type+perf_user_event_type)' < perf.data
+ -C 'perf_file_attr(range=attrs),perf_event_header(range=data,sizeof,type,type_enum=perf_event_type+perf_user_event_type)' --prettify perf.data
.fi
.SH SEE ALSO
diff --git a/pahole.c b/pahole.c
index 4a34ba5..f3a51cb 100644
--- a/pahole.c
+++ b/pahole.c
@@ -10,28 +10,39 @@
#include <assert.h>
#include <stdio.h>
#include <dwarf.h>
+#include <elfutils/version.h>
#include <inttypes.h>
+#include <limits.h>
+#include <pthread.h>
#include <search.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <bpf/btf.h>
+#include "bpf/libbpf.h"
#include "dwarves_reorganize.h"
#include "dwarves.h"
#include "dutil.h"
-#include "ctf_encoder.h"
+//#include "ctf_encoder.h" FIXME: disabled, probably its better to move to Oracle's libctf
#include "btf_encoder.h"
-#include "libbtf.h"
-#include "lib/bpf/src/libbpf.h"
+static struct btf_encoder *btf_encoder;
+static char *detached_btf_filename;
static bool btf_encode;
+static bool btf_gen_floats;
static bool ctf_encode;
+static bool sort_output;
+static bool need_resort;
static bool first_obj_only;
static bool skip_encoding_btf_vars;
static bool btf_encode_force;
static const char *base_btf_file;
+static const char *prettify_input_filename;
+static FILE *prettify_input;
+
static uint8_t class__include_anonymous;
static uint8_t class__include_nested_anonymous;
static uint8_t word_size, original_word_size;
@@ -52,6 +63,7 @@ static uint16_t nr_holes;
static uint16_t nr_bit_holes;
static uint16_t hole_size_ge;
static uint8_t show_packable;
+static bool show_with_flexible_array;
static uint8_t global_verbose;
static uint8_t recursive;
static size_t cacheline_size;
@@ -79,23 +91,23 @@ static struct conf_load conf_load = {
struct structure {
struct list_head node;
struct rb_node rb_node;
- char *name;
+ struct class *class;
+ struct cu *cu;
+ uint32_t id;
uint32_t nr_files;
uint32_t nr_methods;
};
-static struct structure *structure__new(const char *name)
+static struct structure *structure__new(struct class *class, struct cu *cu, uint32_t id)
{
struct structure *st = malloc(sizeof(*st));
if (st != NULL) {
- st->name = strdup(name);
- if (st->name == NULL) {
- free(st);
- return NULL;
- }
st->nr_files = 1;
st->nr_methods = 0;
+ st->class = class;
+ st->cu = cu;
+ st->id = id;
}
return st;
@@ -103,28 +115,209 @@ static struct structure *structure__new(const char *name)
static void structure__delete(struct structure *st)
{
- free(st->name);
+ if (st == NULL)
+ return;
+
free(st);
}
static struct rb_root structures__tree = RB_ROOT;
static LIST_HEAD(structures__list);
+static pthread_mutex_t structures_lock = PTHREAD_MUTEX_INITIALIZER;
+
+static int type__compare_members_types(struct type *a, struct cu *cu_a, struct type *b, struct cu *cu_b)
+{
+ int ret = strcmp(type__name(a), type__name(b));
+
+ if (ret)
+ return ret;
+
+ // a->nr_members should be equal to b->nr_members at this point
+
+ if (a->nr_members == 0)
+ return 0;
+
+ struct class_member *ma, *mb = type__first_member(b);
+
+ type__for_each_member(a, ma) {
+ struct tag *type_ma = cu__type(cu_a, ma->tag.type),
+ *type_mb = cu__type(cu_b, mb->tag.type);
+
+ if (type_ma && !type_mb && class_member__name(mb) == NULL) {
+ /*
+ * FIXME This is happening with a vmlinux built with
+ * clang and thin-LTO, and since this is not
+ * multithreadeded, we can get the previous behaviour
+ * by considering just the first occurence, the one with
+ * all the class member names and proper types, and since
+ * the name, size, number of members is the same, consider them equal
+ * and use the complete type (the first one found).
+ * With this btfdiff works for both non-thin-LTO and thin-LTO vmlinux files
+ */
+ return 0;
+ }
+
+ if (!type_ma || !type_mb) // shuldn't happen
+ return type_ma ? 1 : -1; // best effort
+
+ const char *name_a = class_member__name(ma),
+ *name_b = class_member__name(mb);
+
+ if (name_a && name_b) {
+ ret = strcmp(name_a, name_b);
+ if (ret)
+ return ret;
+ }
+
+ ret = (int)ma->bit_offset - (int)mb->bit_offset;
+ if (ret)
+ return ret;
+
+ ret = (int)ma->bitfield_size - (int)mb->bitfield_size;
+ if (ret)
+ return ret;
+
+ char bf_a[1024], bf_b[1024];
+
+ ret = strcmp(tag__name(type_ma, cu_a, bf_a, sizeof(bf_a), NULL),
+ tag__name(type_mb, cu_b, bf_b, sizeof(bf_b), NULL));
+ if (ret)
+ return ret;
+
+ mb = class_member__next(mb);
+ }
+
+ return 0;
+}
+
+static int type__compare_members(struct type *a, struct type *b)
+{
+ int ret;
+
+ // a->nr_members should be equal to b->nr_members at this point
+
+ if (a->nr_members == 0)
+ return 0;
+
+ struct class_member *ma, *mb = type__first_member(b);
+
+ // Don't look at the types, as we may be referring to a CU being loaded
+ // in another thread and since we're not locking the ptr_table's, we
+ // may race When printing all the types using --sort we'll do an extra
+ // check that takes into account the types, since at that time all the
+ // ptr_tables/cus are quiescent.
+
+ type__for_each_member(a, ma) {
+ const char *name_a = class_member__name(ma),
+ *name_b = class_member__name(mb);
+
+ if (name_a && name_b) {
+ ret = strcmp(name_a, name_b);
+ if (ret)
+ return ret;
+ }
+
+ ret = (int)ma->bit_offset - (int)mb->bit_offset;
+ if (ret)
+ return ret;
+
+ ret = (int)ma->bitfield_size - (int)mb->bitfield_size;
+ if (ret)
+ return ret;
+
+ mb = class_member__next(mb);
+ }
+
+ /*
+ Since we didn't check the types, we may end with at least this btfdiff output:
-static struct structure *structures__add(struct class *class,
- const struct cu *cu,
- bool *existing_entry)
++++ /tmp/btfdiff.btf.b5DJu4 2021-08-18 12:06:27.773932193 -0300
+@@ -31035,7 +31035,7 @@ struct elf_note_info {
+ struct memelfnote auxv; / * 56 24 * /
+ / * --- cacheline 1 boundary (64 bytes) was 16 bytes ago --- * /
+ struct memelfnote files; / * 80 24 * /
+- compat_siginfo_t csigdata; / * 104 128 * /
++ siginfo_t csigdata; / * 104 128 * /
+
+ So if we're printing everything, consider the types as different and
+ at the end with type__compare_members_types() when using --sort,
+ we'll need as well to resort, to avoid things like:
+
+@@ -47965,8 +47965,8 @@ struct instance_attribute {
+
+ / * XXX last struct has 6 bytes of padding * /
+
+- ssize_t (*show)(struct edac_device_instance *, char *); / * 16 8 * /
+- ssize_t (*store)(struct edac_device_instance *, const char *, size_t); / * 24 8 * /
++ ssize_t (*show)(struct edac_pci_ctl_info *, char *); / * 16 8 * /
++ ssize_t (*store)(struct edac_pci_ctl_info *, const char *, size_t); / * 24 8 * /
+
+ / * size: 32, cachelines: 1, members: 3 * /
+ / * paddings: 1, sum paddings: 6 * /
+@@ -47977,8 +47977,8 @@ struct instance_attribute {
+
+ / * XXX last struct has 6 bytes of padding * /
+
+- ssize_t (*show)(struct edac_pci_ctl_info *, char *); / * 16 8 * /
+- ssize_t (*store)(struct edac_pci_ctl_info *, const char *, size_t); / * 24 8 * /
++ ssize_t (*show)(struct edac_device_instance *, char *); / * 16 8 * /
++ ssize_t (*store)(struct edac_device_instance *, const char *, size_t); / * 24 8 * /
+
+ / * size: 32, cachelines: 1, members: 3 * /
+ / * paddings: 1, sum paddings: 6 * /
+
+ I.e. the difference is in the arguments to those show/store function
+ pointers, but since we didn't took the types into account when first
+ sorting, we need to resort.
+
+ So the first sort weeds out duplicates when loading from multiple
+ CUs, i.e. DWARF, the second will make sure both BTF and DWARF are
+ sorted taking into account types and then btfdiff finally will be
+ happy and we can continue to depend on it for regression tests for
+ the BTF and DWARF encoder and loader
+
+ */
+
+ if (sort_output) {
+ need_resort = true;
+ return 1;
+ }
+
+ return 0;
+}
+
+static int type__compare(struct type *a, struct cu *cu_a, struct type *b, struct cu *cu_b)
+{
+ int ret = strcmp(type__name(a), type__name(b));
+
+ if (ret)
+ goto found;
+
+ ret = (int)a->size - (int)b->size;
+ if (ret)
+ goto found;
+
+ ret = (int)a->nr_members - (int)b->nr_members;
+ if (ret)
+ goto found;
+
+ ret = type__compare_members(a, b);
+found:
+ return ret;
+}
+
+static struct structure *__structures__add(struct class *class, struct cu *cu, uint32_t id, bool *existing_entry)
{
struct rb_node **p = &structures__tree.rb_node;
struct rb_node *parent = NULL;
struct structure *str;
- const char *new_class_name = class__name(class, cu);
while (*p != NULL) {
int rc;
parent = *p;
str = rb_entry(parent, struct structure, rb_node);
- rc = strcmp(str->name, new_class_name);
+ rc = type__compare(&str->class->type, str->cu, &class->type, cu);
if (rc > 0)
p = &(*p)->rb_left;
@@ -136,7 +329,7 @@ static struct structure *structures__add(struct class *class,
}
}
- str = structure__new(new_class_name);
+ str = structure__new(class, cu, id);
if (str == NULL)
return NULL;
@@ -150,7 +343,18 @@ static struct structure *structures__add(struct class *class,
return str;
}
-void structures__delete(void)
+static struct structure *structures__add(struct class *class, struct cu *cu, uint32_t id, bool *existing_entry)
+{
+ struct structure *str;
+
+ pthread_mutex_lock(&structures_lock);
+ str = __structures__add(class, cu, id, existing_entry);
+ pthread_mutex_unlock(&structures_lock);
+
+ return str;
+}
+
+static void __structures__delete(void)
{
struct rb_node *next = rb_first(&structures__tree);
@@ -162,48 +366,50 @@ void structures__delete(void)
}
}
+void structures__delete(void)
+{
+ pthread_mutex_lock(&structures_lock);
+ __structures__delete();
+ pthread_mutex_unlock(&structures_lock);
+}
+
static void nr_definitions_formatter(struct structure *st)
{
- printf("%s%c%u\n", st->name, separator, st->nr_files);
+ printf("%s%c%u\n", class__name(st->class), separator, st->nr_files);
}
-static void nr_members_formatter(struct class *class,
- struct cu *cu, uint32_t id __unused)
+static void nr_members_formatter(struct class *class, struct cu *cu __maybe_unused, uint32_t id __maybe_unused)
{
- printf("%s%c%u\n", class__name(class, cu), separator,
- class__nr_members(class));
+ printf("%s%c%u\n", class__name(class), separator, class__nr_members(class));
}
static void nr_methods_formatter(struct structure *st)
{
- printf("%s%c%u\n", st->name, separator, st->nr_methods);
+ printf("%s%c%u\n", class__name(st->class), separator, st->nr_methods);
}
-static void size_formatter(struct class *class,
- struct cu *cu, uint32_t id __unused)
+static void size_formatter(struct class *class, struct cu *cu __maybe_unused, uint32_t id __maybe_unused)
{
- printf("%s%c%d%c%u\n", class__name(class, cu), separator,
+ printf("%s%c%d%c%u\n", class__name(class), separator,
class__size(class), separator, tag__is_union(class__tag(class)) ? 0 : class->nr_holes);
}
-static void class_name_len_formatter(struct class *class, struct cu *cu,
- uint32_t id __unused)
+static void class_name_len_formatter(struct class *class, struct cu *cu __maybe_unused, uint32_t id __maybe_unused)
{
- const char *name = class__name(class, cu);
+ const char *name = class__name(class);
printf("%s%c%zd\n", name, separator, strlen(name));
}
-static void class_name_formatter(struct class *class,
- struct cu *cu, uint32_t id __unused)
+static void class_name_formatter(struct class *class, struct cu *cu __maybe_unused, uint32_t id __maybe_unused)
{
- puts(class__name(class, cu));
+ puts(class__name(class));
}
static void class_formatter(struct class *class, struct cu *cu, uint32_t id)
{
struct tag *typedef_alias = NULL;
struct tag *tag = class__tag(class);
- const char *name = class__name(class, cu);
+ const char *name = class__name(class);
if (name == NULL) {
/*
@@ -227,7 +433,7 @@ static void class_formatter(struct class *class, struct cu *cu, uint32_t id)
struct type *tdef = tag__type(typedef_alias);
conf.prefix = "typedef";
- conf.suffix = type__name(tdef, cu);
+ conf.suffix = type__name(tdef);
} else
conf.prefix = conf.suffix = NULL;
@@ -242,7 +448,7 @@ static void print_packable_info(struct class *c, struct cu *cu, uint32_t id)
const size_t orig_size = class__size(c);
const size_t new_size = class__size(c->priv);
const size_t savings = orig_size - new_size;
- const char *name = class__name(c, cu);
+ const char *name = class__name(c);
/* Anonymous struct? Try finding a typedef */
if (name == NULL) {
@@ -250,7 +456,7 @@ static void print_packable_info(struct class *c, struct cu *cu, uint32_t id)
cu__find_first_typedef_of_type(cu, id);
if (tdef != NULL)
- name = class__name(tag__class(tdef), cu);
+ name = class__name(tag__class(tdef));
}
if (name != NULL)
printf("%s%c%zd%c%zd%c%zd\n",
@@ -309,7 +515,7 @@ static void print_classes(struct cu *cu)
* and I'm sleepy, will leave for later...
*/
if (pos->type.namespace.name != 0) {
- str = structures__add(pos, cu, &existing_entry);
+ str = structures__add(pos, cu, id, &existing_entry);
if (str == NULL) {
fprintf(stderr, "pahole: insufficient memory for "
"processing %s, skipping it...\n", cu->name);
@@ -325,11 +531,73 @@ static void print_classes(struct cu *cu)
if (show_packable && !global_verbose)
print_packable_info(pos, cu, id);
+ else if (sort_output && formatter == class_formatter)
+ continue; // we'll print it at the end, in order, out of structures__tree
else if (formatter != NULL)
formatter(pos, cu, id);
}
}
+static void __print_ordered_classes(struct rb_root *root)
+{
+ struct rb_node *next = rb_first(root);
+
+ while (next) {
+ struct structure *st = rb_entry(next, struct structure, rb_node);
+
+ class_formatter(st->class, st->cu, st->id);
+
+ next = rb_next(&st->rb_node);
+ }
+
+}
+
+static void resort_add(struct rb_root *resorted, struct structure *str)
+{
+ struct rb_node **p = &resorted->rb_node;
+ struct rb_node *parent = NULL;
+ struct structure *node;
+
+ while (*p != NULL) {
+ int rc;
+
+ parent = *p;
+ node = rb_entry(parent, struct structure, rb_node);
+ rc = type__compare_members_types(&node->class->type, node->cu, &str->class->type, str->cu);
+
+ if (rc > 0)
+ p = &(*p)->rb_left;
+ else if (rc < 0)
+ p = &(*p)->rb_right;
+ else
+ return; // Duplicate, ignore it
+ }
+
+ rb_link_node(&str->rb_node, parent, p);
+ rb_insert_color(&str->rb_node, resorted);
+}
+
+static void resort_classes(struct rb_root *resorted, struct list_head *head)
+{
+ struct structure *str;
+
+ list_for_each_entry(str, head, node)
+ resort_add(resorted, str);
+}
+
+static void print_ordered_classes(void)
+{
+ if (!need_resort) {
+ __print_ordered_classes(&structures__tree);
+ } else {
+ struct rb_root resorted = RB_ROOT;
+
+ resort_classes(&resorted, &structures__list);
+ __print_ordered_classes(&resorted);
+ }
+}
+
+
static struct cu *cu__filter(struct cu *cu)
{
if (cu__exclude_prefix != NULL &&
@@ -348,7 +616,7 @@ static int class__packable(struct class *class, struct cu *cu)
if (class->nr_holes == 0 && class->nr_bit_holes == 0)
return 0;
- clone = class__clone(class, NULL, cu);
+ clone = class__clone(class, NULL);
if (clone == NULL)
return 0;
class__reorganize(clone, cu, 0, stdout);
@@ -356,13 +624,33 @@ static int class__packable(struct class *class, struct cu *cu)
class->priv = clone;
return 1;
}
- /* FIXME: we need to free in the right order,
- * cu->obstack is being corrupted...
- class__delete(clone, cu);
- */
+ class__delete(clone);
return 0;
}
+static bool class__has_flexible_array(struct class *class, struct cu *cu)
+{
+ struct class_member *member = type__last_member(&class->type);
+
+ if (member == NULL)
+ return false;
+
+ struct tag *type = cu__type(cu, member->tag.type);
+
+ if (type->tag != DW_TAG_array_type)
+ return false;
+
+ struct array_type *array = tag__array_type(type);
+
+ if (array->dimensions > 1)
+ return false;
+
+ if (array->nr_entries == NULL || array->nr_entries[0] == 0)
+ return true;
+
+ return false;
+}
+
static struct class *class__filter(struct class *class, struct cu *cu,
uint32_t tag_id)
{
@@ -388,7 +676,7 @@ static struct class *class__filter(struct class *class, struct cu *cu,
return NULL;
}
- name = class__name(class, cu);
+ name = class__name(class);
if (class__is_declaration(class))
return NULL;
@@ -403,7 +691,7 @@ static struct class *class__filter(struct class *class, struct cu *cu,
if (tdef != NULL) {
struct class *c = tag__class(tdef);
- name = class__name(c, cu);
+ name = class__name(c);
}
}
if (name != NULL && strncmp(class__exclude_prefix, name,
@@ -418,7 +706,7 @@ static struct class *class__filter(struct class *class, struct cu *cu,
if (tdef != NULL) {
struct class *c = tag__class(tdef);
- name = class__name(c, cu);
+ name = class__name(c);
}
}
if (name != NULL && strncmp(class__include_prefix, name,
@@ -457,6 +745,9 @@ static struct class *class__filter(struct class *class, struct cu *cu,
if (show_packable && !class__packable(class, cu))
return NULL;
+ if (show_with_flexible_array && !class__has_flexible_array(class, cu))
+ return NULL;
+
return class;
}
@@ -509,13 +800,12 @@ static void class__resize_LP(struct tag *tag, struct cu *cu)
case DW_TAG_base_type: {
struct base_type *bt = tag__base_type(type);
char bf[64];
- const char *name = base_type__name(bt, cu, bf,
- sizeof(bf));
+ const char *name = base_type__name(bt, bf, sizeof(bf));
if (strcmp(name, "long int") != 0 &&
strcmp(name, "long unsigned int") != 0)
break;
- /* fallthru */
}
+ /* fallthru */
case DW_TAG_pointer_type:
diff = word_size_diff;
break;
@@ -616,7 +906,7 @@ static void tag__fixup_word_size(struct tag *tag, struct cu *cu)
if (!bt->name)
return;
char bf[64];
- const char *name = base_type__name(bt, cu, bf, sizeof(bf));
+ const char *name = base_type__name(bt, bf, sizeof(bf));
if (strcmp(name, "long int") == 0 ||
strcmp(name, "long unsigned int") == 0)
@@ -674,7 +964,7 @@ static void cu__account_nr_methods(struct cu *cu)
continue;
bool existing_entry;
- str = structures__add(class, cu, &existing_entry);
+ str = structures__add(class, cu, id, &existing_entry);
if (str == NULL) {
fprintf(stderr, "pahole: insufficient memory "
"for processing %s, skipping it...\n",
@@ -723,7 +1013,7 @@ static void print_structs_with_pointer_to(struct cu *cu, uint32_t type)
if (!looked) {
bool existing_entry;
- str = structures__add(pos, cu, &existing_entry);
+ str = structures__add(pos, cu, id, &existing_entry);
if (str == NULL) {
fprintf(stderr, "pahole: insufficient memory for "
"processing %s, skipping it...\n",
@@ -737,8 +1027,8 @@ static void print_structs_with_pointer_to(struct cu *cu, uint32_t type)
break;
looked = true;
}
- printf("%s: %s\n", str->name,
- class_member__name(pos_member, cu));
+ printf("%s: %s\n", class__name(str->class),
+ class_member__name(pos_member));
}
}
}
@@ -750,8 +1040,8 @@ static int type__print_containers(struct type *type, struct cu *cu, uint32_t con
return 0;
if (ident == 0) {
- bool existing_entry;
- struct structure *str = structures__add(type__class(type), cu, &existing_entry);
+ bool existing_entry; // FIXME: This should really just search, no need to try to add it.
+ struct structure *str = structures__add(type__class(type), cu, 0, &existing_entry);
if (str == NULL) {
fprintf(stderr, "pahole: insufficient memory for "
"processing %s, skipping it...\n",
@@ -765,7 +1055,7 @@ static int type__print_containers(struct type *type, struct cu *cu, uint32_t con
return 0;
}
- printf("%.*s%s", ident * 2, tab, type__name(type, cu));
+ printf("%.*s%s", ident * 2, tab, type__name(type));
if (global_verbose)
printf(": %u", n);
putchar('\n');
@@ -825,6 +1115,18 @@ ARGP_PROGRAM_VERSION_HOOK_DEF = dwarves_print_version;
#define ARGP_just_packed_structs 319
#define ARGP_numeric_version 320
#define ARGP_btf_base 321
+#define ARGP_btf_gen_floats 322
+#define ARGP_btf_gen_all 323
+#define ARGP_with_flexible_array 324
+#define ARGP_kabi_prefix 325
+#define ARGP_btf_encode_detached 326
+#define ARGP_prettify_input_filename 327
+#define ARGP_sort_output 328
+#define ARGP_hashbits 329
+#define ARGP_devel_stats 330
+#define ARGP_skip_encoding_btf_decl_tag 331
+#define ARGP_skip_missing 332
+#define ARGP_skip_encoding_btf_type_tag 333
static const struct argp_option pahole__options[] = {
{
@@ -923,6 +1225,11 @@ static const struct argp_option pahole__options[] = {
.doc = "show only structs that has holes that can be packed",
},
{
+ .name = "with_flexible_array",
+ .key = ARGP_with_flexible_array,
+ .doc = "show only structs with a flexible array",
+ },
+ {
.name = "expand_types",
.key = 'E',
.doc = "expand class members",
@@ -1051,7 +1358,7 @@ static const struct argp_option pahole__options[] = {
{
.name = "ctf_encode",
.key = 'Z',
- .doc = "Encode as CTF",
+ .doc = "Encode as CTF: DISABLED, consider helping porting to libctf",
},
{
.name = "flat_arrays",
@@ -1105,11 +1412,30 @@ static const struct argp_option pahole__options[] = {
.doc = "Path to the base BTF file",
},
{
+ .name = "kabi_prefix",
+ .key = ARGP_kabi_prefix,
+ .arg = "STRING",
+ .doc = "When the prefix of the string is STRING, treat the string as STRING.",
+ },
+ {
+ .name = "jobs",
+ .key = 'j',
+ .arg = "NR_JOBS",
+ .flags = OPTION_ARG_OPTIONAL, // Use sysconf(_SC_NPROCESSORS_ONLN) * 1.1 by default
+ .doc = "run N jobs in parallel [default to number of online processors + 10%]",
+ },
+ {
.name = "btf_encode",
.key = 'J',
.doc = "Encode as BTF",
},
{
+ .name = "btf_encode_detached",
+ .key = ARGP_btf_encode_detached,
+ .arg = "FILENAME",
+ .doc = "Encode as BTF in a detached file",
+ },
+ {
.name = "skip_encoding_btf_vars",
.key = ARGP_skip_encoding_btf_vars,
.doc = "Do not encode VARs in BTF."
@@ -1120,6 +1446,16 @@ static const struct argp_option pahole__options[] = {
.doc = "Ignore those symbols found invalid when encoding BTF."
},
{
+ .name = "btf_gen_floats",
+ .key = ARGP_btf_gen_floats,
+ .doc = "Allow producing BTF_KIND_FLOAT entries."
+ },
+ {
+ .name = "btf_gen_all",
+ .key = ARGP_btf_gen_all,
+ .doc = "Allow using all the BTF features supported by pahole."
+ },
+ {
.name = "structs",
.key = ARGP_just_structs,
.doc = "Show just structs",
@@ -1140,6 +1476,43 @@ static const struct argp_option pahole__options[] = {
.doc = "Print a numeric version, i.e. 119 instead of v1.19"
},
{
+ .name = "sort",
+ .key = ARGP_sort_output,
+ .doc = "Sort types by name",
+ },
+ {
+ .name = "prettify",
+ .key = ARGP_prettify_input_filename,
+ .arg = "PATH",
+ .doc = "Path to the raw data to pretty print",
+ },
+ {
+ .name = "hashbits",
+ .key = ARGP_hashbits,
+ .arg = "BITS",
+ .doc = "Number of bits for the hash table key",
+ },
+ {
+ .name = "ptr_table_stats",
+ .key = ARGP_devel_stats,
+ .doc = "Print internal data structures stats",
+ },
+ {
+ .name = "skip_encoding_btf_decl_tag",
+ .key = ARGP_skip_encoding_btf_decl_tag,
+ .doc = "Do not encode TAGs in BTF."
+ },
+ {
+ .name = "skip_missing",
+ .key = ARGP_skip_missing,
+ .doc = "skip missing types passed to -C rather than stop",
+ },
+ {
+ .name = "skip_encoding_btf_type_tag",
+ .key = ARGP_skip_encoding_btf_type_tag,
+ .doc = "Do not encode TAGs in BTF."
+ },
+ {
.name = NULL,
}
};
@@ -1170,8 +1543,24 @@ static error_t pahole__options_parser(int key, char *arg,
conf_load.extra_dbg_info = 1; break;
case 'i': find_containers = 1;
class_name = arg; break;
+ case 'j':
+#if _ELFUTILS_PREREQ(0, 178)
+ conf_load.nr_jobs = arg ? atoi(arg) :
+ sysconf(_SC_NPROCESSORS_ONLN) * 1.1;
+#else
+ fputs("pahole: Multithreading requires elfutils >= 0.178. Continuing with a single thread...\n", stderr);
+#endif
+ break;
+ case ARGP_btf_encode_detached:
+ detached_btf_filename = arg; // fallthru
case 'J': btf_encode = 1;
conf_load.get_addr_info = true;
+ conf_load.ignore_alignment_attr = true;
+ // XXX for now, test this more thoroughly
+ // We may have some references from formal parameters, etc, (abstract_origin)
+ // conf_load.ignore_inline_expansions = true;
+ conf_load.ignore_labels = true;
+ conf_load.use_obstack = true;
no_bitfield_type_recode = true; break;
case 'l': conf.show_first_biggest_size_base_type_member = 1; break;
case 'M': conf.show_only_data_members = 1; break;
@@ -1208,7 +1597,7 @@ static error_t pahole__options_parser(int key, char *arg,
if (!global_verbose)
formatter = class_name_formatter;
break;
- case 'Z': ctf_encode = 1; break;
+ // case 'Z': ctf_encode = 1; break; // FIXME: Disabled
case ARGP_flat_arrays: conf.flat_arrays = 1; break;
case ARGP_suppress_aligned_attribute:
conf.suppress_aligned_attribute = 1; break;
@@ -1252,8 +1641,31 @@ static error_t pahole__options_parser(int key, char *arg,
btf_encode_force = true; break;
case ARGP_btf_base:
base_btf_file = arg; break;
+ case ARGP_kabi_prefix:
+ conf_load.kabi_prefix = arg;
+ conf_load.kabi_prefix_len = strlen(arg); break;
case ARGP_numeric_version:
print_numeric_version = true; break;
+ case ARGP_btf_gen_floats:
+ btf_gen_floats = true; break;
+ case ARGP_btf_gen_all:
+ btf_gen_floats = true; break;
+ case ARGP_with_flexible_array:
+ show_with_flexible_array = true; break;
+ case ARGP_prettify_input_filename:
+ prettify_input_filename = arg; break;
+ case ARGP_sort_output:
+ sort_output = true; break;
+ case ARGP_hashbits:
+ conf_load.hashtable_bits = atoi(arg); break;
+ case ARGP_devel_stats:
+ conf_load.ptr_table_stats = true; break;
+ case ARGP_skip_encoding_btf_decl_tag:
+ conf_load.skip_encoding_btf_decl_tag = true; break;
+ case ARGP_skip_missing:
+ conf_load.skip_missing = true; break;
+ case ARGP_skip_encoding_btf_type_tag:
+ conf_load.skip_encoding_btf_type_tag = true; break;
default:
return ARGP_ERR_UNKNOWN;
}
@@ -1273,7 +1685,7 @@ static void do_reorg(struct tag *class, struct cu *cu)
int savings;
const uint8_t reorg_verbose =
show_reorg_steps ? 2 : global_verbose;
- struct class *clone = class__clone(tag__class(class), NULL, cu);
+ struct class *clone = class__clone(tag__class(class), NULL);
if (clone == NULL) {
fprintf(stderr, "pahole: out of memory!\n");
exit(EXIT_FAILURE);
@@ -1288,8 +1700,8 @@ static void do_reorg(struct tag *class, struct cu *cu)
tag__fprintf(class__tag(clone), cu, &conf, stdout);
if (savings != 0) {
const size_t cacheline_savings =
- (tag__nr_cachelines(class, cu) -
- tag__nr_cachelines(class__tag(clone), cu));
+ (tag__nr_cachelines(&conf, class, cu) -
+ tag__nr_cachelines(&conf, class__tag(clone), cu));
printf(" /* saved %d byte%s", savings,
savings != 1 ? "s" : "");
@@ -1302,13 +1714,10 @@ static void do_reorg(struct tag *class, struct cu *cu)
} else
putchar('\n');
- /* FIXME: we need to free in the right order,
- * cu->obstack is being corrupted...
- class__delete(clone, cu);
- */
+ class__delete(clone);
}
-static int tag__fprintf_hexdump_value(struct tag *type, struct cu *cu, void *instance, int _sizeof, FILE *fp)
+static int instance__fprintf_hexdump_value(void *instance, int _sizeof, FILE *fp)
{
uint8_t *contents = instance;
int i, printed = 0;
@@ -1378,13 +1787,13 @@ static int class_member__fprintf_bitfield_value(struct class_member *member, voi
return fprintf(fp, format, class_member__bitfield_value(member, instance));
}
-static const char *enumeration__lookup_value(struct type *enumeration, struct cu *cu, uint64_t value)
+static const char *enumeration__lookup_value(struct type *enumeration, uint64_t value)
{
struct enumerator *entry;
type__for_each_enumerator(enumeration, entry) {
if (entry->value == value)
- return enumerator__name(entry, cu);
+ return enumerator__name(entry);
}
return NULL;
@@ -1395,7 +1804,7 @@ static const char *enumerations__lookup_value(struct list_head *enumerations, ui
struct tag_cu_node *pos;
list_for_each_entry(pos, enumerations, node) {
- const char *s = enumeration__lookup_value(tag__type(pos->tc.tag), pos->tc.cu, value);
+ const char *s = enumeration__lookup_value(tag__type(pos->tc.tag), value);
if (s)
return s;
}
@@ -1403,7 +1812,7 @@ static const char *enumerations__lookup_value(struct list_head *enumerations, ui
return NULL;
}
-static struct enumerator *enumeration__lookup_entry_from_value(struct type *enumeration, struct cu *cu, uint64_t value)
+static struct enumerator *enumeration__lookup_entry_from_value(struct type *enumeration, uint64_t value)
{
struct enumerator *entry;
@@ -1415,14 +1824,13 @@ static struct enumerator *enumeration__lookup_entry_from_value(struct type *enum
return NULL;
}
-static struct enumerator *enumerations__lookup_entry_from_value(struct list_head *enumerations, struct cu **cup, uint64_t value)
+static struct enumerator *enumerations__lookup_entry_from_value(struct list_head *enumerations, uint64_t value)
{
struct tag_cu_node *pos;
list_for_each_entry(pos, enumerations, node) {
- struct enumerator *enumerator = enumeration__lookup_entry_from_value(tag__type(pos->tc.tag), pos->tc.cu, value);
+ struct enumerator *enumerator = enumeration__lookup_entry_from_value(tag__type(pos->tc.tag), value);
if (enumerator) {
- *cup = pos->tc.cu;
return enumerator;
}
}
@@ -1430,12 +1838,12 @@ static struct enumerator *enumerations__lookup_entry_from_value(struct list_head
return NULL;
}
-static int64_t enumeration__lookup_enumerator(struct type *enumeration, struct cu *cu, const char *enumerator)
+static int64_t enumeration__lookup_enumerator(struct type *enumeration, const char *enumerator)
{
struct enumerator *entry;
type__for_each_enumerator(enumeration, entry) {
- const char *entry_name = enumerator__name(entry, cu);
+ const char *entry_name = enumerator__name(entry);
if (!strcmp(entry_name, enumerator))
return entry->value;
@@ -1453,7 +1861,7 @@ static int64_t enumerations__lookup_enumerator(struct list_head *enumerations, c
struct tag_cu_node *pos;
list_for_each_entry(pos, enumerations, node) {
- int64_t value = enumeration__lookup_enumerator(tag__type(pos->tc.tag), pos->tc.cu, enumerator);
+ int64_t value = enumeration__lookup_enumerator(tag__type(pos->tc.tag), enumerator);
if (value != -1)
return value;
}
@@ -1486,7 +1894,7 @@ static int array__fprintf_base_type_value(struct tag *tag, struct cu *cu, void *
if (array->dimensions != 1) {
// Support multi dimensional arrays later
- return tag__fprintf_hexdump_value(tag, cu, instance, _sizeof, fp);
+ return instance__fprintf_hexdump_value(instance, _sizeof, fp);
}
if (tag__is_typedef(array_type))
@@ -1523,7 +1931,7 @@ static int array__fprintf_value(struct tag *tag, struct cu *cu, void *instance,
if (tag__is_base_type(array_type, cu))
return array__fprintf_base_type_value(tag, cu, instance, _sizeof, fp);
- return tag__fprintf_hexdump_value(tag, cu, instance, _sizeof, fp);
+ return instance__fprintf_hexdump_value(instance, _sizeof, fp);
}
static int __class__fprintf_value(struct tag *tag, struct cu *cu, void *instance, int _sizeof, int indent, bool brackets, FILE *fp)
@@ -1538,7 +1946,7 @@ static int __class__fprintf_value(struct tag *tag, struct cu *cu, void *instance
type__for_each_member(type, member) {
void *member_contents = instance + member->byte_offset;
struct tag *member_type = cu__type(cu, member->tag.type);
- const char *name = class_member__name(member, cu);
+ const char *name = class_member__name(member);
if (name)
printed += fprintf(fp, "\n%.*s\t.%s = ", indent, tabs, name);
@@ -1563,7 +1971,7 @@ static int __class__fprintf_value(struct tag *tag, struct cu *cu, void *instance
if (!name)
continue;
} else {
- printed += tag__fprintf_hexdump_value(member_type, cu, member_contents, member->byte_size, fp);
+ printed += instance__fprintf_hexdump_value(member_contents, member->byte_size, fp);
}
fputc(',', fp);
@@ -1585,7 +1993,7 @@ static int tag__fprintf_value(struct tag *type, struct cu *cu, void *instance, i
if (tag__is_struct(type))
return class__fprintf_value(type, cu, instance, _sizeof, 0, fp);
- return tag__fprintf_hexdump_value(type, cu, instance, _sizeof, fp);
+ return instance__fprintf_hexdump_value(instance, _sizeof, fp);
}
static int pipe_seek(FILE *fp, off_t offset)
@@ -1596,7 +2004,7 @@ static int pipe_seek(FILE *fp, off_t offset)
if (chunk > offset)
chunk = offset;
- while (fread(bf, chunk, 1, stdin) == 1) {
+ while (fread(bf, chunk, 1, fp) == 1) {
offset -= chunk;
if (offset == 0)
return 0;
@@ -1607,7 +2015,7 @@ static int pipe_seek(FILE *fp, off_t offset)
return offset == 0 ? 0 : -1;
}
-static uint64_t tag__real_sizeof(struct tag *tag, struct cu *cu, int _sizeof, void *instance)
+static uint64_t tag__real_sizeof(struct tag *tag, int _sizeof, void *instance)
{
if (tag__is_struct(tag)) {
struct type *type = tag__type(tag);
@@ -1658,8 +2066,7 @@ static struct tag *tag__real_type(struct tag *tag, struct cu **cup, void *instan
if (!list_empty(&type->type_enum) && type->type_member) {
struct class_member *member = type->type_member;
uint64_t value = base_type__value(instance + member->byte_offset, member->byte_size);
- struct cu *cu_enumerator;
- struct enumerator *enumerator = enumerations__lookup_entry_from_value(&type->type_enum, &cu_enumerator, value);
+ struct enumerator *enumerator = enumerations__lookup_entry_from_value(&type->type_enum, value);
char name[1024];
if (!enumerator)
@@ -1670,7 +2077,7 @@ static struct tag *tag__real_type(struct tag *tag, struct cu **cup, void *instan
return enumerator->type_enum.tag;
}
- snprintf(name, sizeof(name), "%s", enumerator__name(enumerator, cu_enumerator));
+ snprintf(name, sizeof(name), "%s", enumerator__name(enumerator));
strlwr(name);
struct tag *real_type = cu__find_type_by_name(*cup, name, false, NULL);
@@ -1723,7 +2130,7 @@ static void type_instance__delete(struct type_instance *instance)
static int64_t type_instance__int_value(struct type_instance *instance, const char *member_name_orig)
{
struct cu *cu = instance->cu;
- struct class_member *member = type__find_member_by_name(instance->type, cu, member_name_orig);
+ struct class_member *member = type__find_member_by_name(instance->type, member_name_orig);
int byte_offset = 0;
if (!member) {
@@ -1744,7 +2151,7 @@ static int64_t type_instance__int_value(struct type_instance *instance, const ch
*sep = 0;
while (1) {
- member = type__find_member_by_name(type, cu, member_name);
+ member = type__find_member_by_name(type, member_name);
if (!member) {
out_free_member_name:
free(member_name_alloc);
@@ -1761,7 +2168,7 @@ out_free_member_name:
}
- member = type__find_member_by_name(type, cu, member_name);
+ member = type__find_member_by_name(type, member_name);
free(member_name_alloc);
if (member == NULL)
return -1;
@@ -1784,7 +2191,7 @@ static int64_t type__instance_read_once(struct type_instance *instance, FILE *fp
instance->read_already = true;
- return fread(instance->instance, instance->type->size, 1, stdin) != 1 ? -1 : instance->type->size;
+ return fread(instance->instance, instance->type->size, 1, fp) != 1 ? -1 : (int64_t)instance->type->size;
}
/*
@@ -1813,7 +2220,7 @@ struct prototype {
};
-static int prototype__stdio_fprintf_value(struct prototype *prototype, struct type_instance *header, FILE *fp)
+static int prototype__stdio_fprintf_value(struct prototype *prototype, struct type_instance *header, FILE *input, FILE *output)
{
struct tag *type = prototype->class;
struct cu *cu = prototype->cu;
@@ -1827,9 +2234,9 @@ static int prototype__stdio_fprintf_value(struct prototype *prototype, struct ty
if (instance == NULL)
return -ENOMEM;
- if (type__instance_read_once(header, stdin) < 0) {
+ if (type__instance_read_once(header, input) < 0) {
int err = --errno;
- fprintf(stderr, "pahole: --header (%s) type not be read\n", conf.header_type);
+ fprintf(stderr, "pahole: --header (%s) type couldn't be read\n", conf.header_type);
return err;
}
@@ -1865,17 +2272,18 @@ static int prototype__stdio_fprintf_value(struct prototype *prototype, struct ty
free(member_name);
- off_t total_read_bytes = ftell(stdin);
+ off_t total_read_bytes = ftell(input);
- // Since we're reading stdin, we need to account for what we already read
+ // Since we're reading input, we need to account for what we already read
+ // FIXME: we now have a FILE pointer that _may_ be stdin, but not necessarily
if (seek_bytes < total_read_bytes) {
- fprintf(stderr, "pahole: can't go back in stdin, already read %" PRIu64 " bytes, can't go to position %#" PRIx64 "\n",
+ fprintf(stderr, "pahole: can't go back in input, already read %" PRIu64 " bytes, can't go to position %#" PRIx64 "\n",
total_read_bytes, seek_bytes);
return -ENOMEM;
}
if (global_verbose) {
- fprintf(fp, "pahole: range.seek_bytes evaluated from range=%s is %#" PRIx64 " \n",
+ fprintf(output, "pahole: range.seek_bytes evaluated from range=%s is %#" PRIx64 " \n",
range, seek_bytes);
}
@@ -1897,13 +2305,13 @@ static int prototype__stdio_fprintf_value(struct prototype *prototype, struct ty
size_bytes = value;
if (global_verbose) {
- fprintf(fp, "pahole: range.size_bytes evaluated from range=%s is %#" PRIx64 " \n",
+ fprintf(output, "pahole: range.size_bytes evaluated from range=%s is %#" PRIx64 " \n",
range, size_bytes);
}
free(member_name);
- if (pipe_seek(stdin, seek_bytes) < 0) {
+ if (pipe_seek(input, seek_bytes) < 0) {
int err = --errno;
fprintf(stderr, "Couldn't --seek_bytes %s (%" PRIu64 "\n", conf.seek_bytes, seek_bytes);
return err;
@@ -1947,11 +2355,11 @@ static int prototype__stdio_fprintf_value(struct prototype *prototype, struct ty
if (header) {
- // Since we're reading stdin, we need to account for already read header:
- seek_bytes -= ftell(stdin);
+ // Since we're reading input, we need to account for already read header:
+ seek_bytes -= ftell(input);
}
- if (pipe_seek(stdin, seek_bytes) < 0) {
+ if (pipe_seek(input, seek_bytes) < 0) {
int err = --errno;
fprintf(stderr, "Couldn't --seek_bytes %s (%" PRIu64 "\n", conf.seek_bytes, seek_bytes);
return err;
@@ -1986,11 +2394,11 @@ static int prototype__stdio_fprintf_value(struct prototype *prototype, struct ty
do_read:
{
uint64_t read_bytes = 0;
- off_t record_offset = ftell(stdin);
+ off_t record_offset = ftell(input);
- while (fread(instance, _sizeof, 1, stdin) == 1) {
+ while (fread(instance, _sizeof, 1, input) == 1) {
// Read it from each record/instance
- int real_sizeof = tag__real_sizeof(type, cu, _sizeof, instance);
+ int real_sizeof = tag__real_sizeof(type, _sizeof, instance);
if (real_sizeof > _sizeof) {
if (real_sizeof > max_sizeof) {
@@ -2003,7 +2411,7 @@ do_read:
instance = new_instance;
max_sizeof = real_sizeof;
}
- if (fread(instance + _sizeof, real_sizeof - _sizeof, 1, stdin) != 1) {
+ if (fread(instance + _sizeof, real_sizeof - _sizeof, 1, input) != 1) {
fprintf(stderr, "Couldn't read record: %d bytes\n", real_sizeof);
printed = -1;
goto out;
@@ -2070,14 +2478,14 @@ do_read:
real_type = type;
if (global_verbose) {
- printed += fprintf(fp, "// type=%s, offset=%#" PRIx64 ", sizeof=%d", type__name(tag__type(type), cu), record_offset, _sizeof);
+ printed += fprintf(output, "// type=%s, offset=%#" PRIx64 ", sizeof=%d", type__name(tag__type(type)), record_offset, _sizeof);
if (real_sizeof != _sizeof)
- printed += fprintf(fp, ", real_sizeof=%d\n", real_sizeof);
+ printed += fprintf(output, ", real_sizeof=%d\n", real_sizeof);
else
- printed += fprintf(fp, "\n");
+ printed += fprintf(output, "\n");
}
- printed += tag__fprintf_value(real_type, real_type_cu, instance, real_sizeof, fp);
- printed += fprintf(fp, ",\n");
+ printed += tag__fprintf_value(real_type, real_type_cu, instance, real_sizeof, output);
+ printed += fprintf(output, ",\n");
if (conf.count && ++count == conf.count)
break;
@@ -2085,7 +2493,7 @@ next_record:
if (read_bytes >= size_bytes)
break;
- record_offset = ftell(stdin);
+ record_offset = ftell(input);
}
}
out:
@@ -2093,7 +2501,7 @@ out:
return printed;
}
-static int class_member_filter__parse(struct class_member_filter *filter, struct type *type, struct cu *cu, char *sfilter)
+static int class_member_filter__parse(struct class_member_filter *filter, struct type *type, char *sfilter)
{
const char *member_name = sfilter;
char *sep = strstr(sfilter, "==");
@@ -2116,11 +2524,11 @@ static int class_member_filter__parse(struct class_member_filter *filter, struct
char before = s[1];
s[1] = '\0';
- filter->left = type__find_member_by_name(type, cu, member_name);
+ filter->left = type__find_member_by_name(type, member_name);
if (!filter->left) {
if (global_verbose)
- fprintf(stderr, "The '%s' member wasn't found in '%s'\n", member_name, type__name(type, cu));
+ fprintf(stderr, "The '%s' member wasn't found in '%s'\n", member_name, type__name(type));
s[1] = before;
return -1;
}
@@ -2130,7 +2538,7 @@ static int class_member_filter__parse(struct class_member_filter *filter, struct
while (isspace(*value))
if (*++value == '\0') {
if (global_verbose)
- fprintf(stderr, "The '%s' member was asked without a value to filter '%s'\n", member_name, type__name(type, cu));
+ fprintf(stderr, "The '%s' member was asked without a value to filter '%s'\n", member_name, type__name(type));
return -1; // no value
}
@@ -2155,7 +2563,7 @@ static int class_member_filter__parse(struct class_member_filter *filter, struct
if (enumerator_value < 0) {
if (global_verbose)
fprintf(stderr, "Couldn't resolve right operand ('%s') in '%s' with the specified 'type=%s' and type_enum' \n",
- value, sfilter, class_member__name(type->type_member, cu));
+ value, sfilter, class_member__name(type->type_member));
return -1;
}
@@ -2164,11 +2572,11 @@ static int class_member_filter__parse(struct class_member_filter *filter, struct
return 0;
}
-static struct class_member_filter *class_member_filter__new(struct type *type, struct cu *cu, char *sfilter)
+static struct class_member_filter *class_member_filter__new(struct type *type, char *sfilter)
{
struct class_member_filter *filter = malloc(sizeof(*filter));
- if (filter && class_member_filter__parse(filter, type, cu, sfilter)) {
+ if (filter && class_member_filter__parse(filter, type, sfilter)) {
free(filter);
filter = NULL;
}
@@ -2391,32 +2799,64 @@ out:
static struct type_instance *header;
static enum load_steal_kind pahole_stealer(struct cu *cu,
- struct conf_load *conf_load __unused)
+ struct conf_load *conf_load)
{
int ret = LSK__DELETE;
if (!cu__filter(cu))
goto filter_it;
+ if (conf_load->ptr_table_stats) {
+ static bool first = true;
+
+ if (first) {
+ cus__fprintf_ptr_table_stats_csv_header(stderr);
+ first = false;
+ }
+ cu__fprintf_ptr_table_stats_csv(cu, stderr);
+ }
+
if (btf_encode) {
- if (cu__encode_btf(cu, global_verbose, btf_encode_force,
- skip_encoding_btf_vars)) {
+ static pthread_mutex_t btf_lock = PTHREAD_MUTEX_INITIALIZER;
+
+ pthread_mutex_lock(&btf_lock);
+ /*
+ * FIXME:
+ *
+ * This should be really done at main(), but since in the current codebase only at this
+ * point we'll have cu->elf setup...
+ */
+ if (!btf_encoder) {
+ btf_encoder = btf_encoder__new(cu, detached_btf_filename, conf_load->base_btf, skip_encoding_btf_vars,
+ btf_encode_force, btf_gen_floats, global_verbose);
+ if (btf_encoder == NULL) {
+ ret = LSK__STOP_LOADING;
+ goto out_btf;
+ }
+ }
+
+ if (btf_encoder__encode_cu(btf_encoder, cu)) {
fprintf(stderr, "Encountered error while encoding BTF.\n");
exit(1);
}
- return LSK__DELETE;
+ ret = LSK__DELETE;
+out_btf:
+ pthread_mutex_unlock(&btf_lock);
+ return ret;
}
-
+#if 0
if (ctf_encode) {
cu__encode_ctf(cu, global_verbose);
/*
* We still have to get the type signature code merged to eliminate
* dups, reference another CTF file, etc, so for now just encode the
* first cu that is let thru by cu__filter.
+ *
+ * FIXME: Disabled, should use Oracle's libctf
*/
goto dump_and_stop;
}
-
+#endif
if (class_name == NULL) {
if (stats_formatter == nr_methods_formatter) {
cu__account_nr_methods(cu);
@@ -2427,6 +2867,10 @@ static enum load_steal_kind pahole_stealer(struct cu *cu,
cu_fixup_word_size_iterator(cu);
print_classes(cu);
+
+ if (sort_output && formatter == class_formatter)
+ ret = LSK__KEEPIT;
+
goto dump_it;
}
@@ -2451,8 +2895,13 @@ static enum load_steal_kind pahole_stealer(struct cu *cu,
static type_id_t class_id;
struct tag *class = cu__find_type_by_name(cu, prototype->name, include_decls, &class_id);
- if (class == NULL)
- return ret; // couldn't find that class name in this CU, continue to the next one.
+ // couldn't find that class name in this CU, continue to the next one.
+ if (class == NULL) {
+ if (conf_load->skip_missing)
+ continue;
+ else
+ return ret;
+ }
if (prototype->nr_args != 0 && !tag__is_struct(class)) {
fprintf(stderr, "pahole: attributes are only supported with 'class' and 'struct' types\n");
@@ -2462,7 +2911,7 @@ static enum load_steal_kind pahole_stealer(struct cu *cu,
struct type *type = tag__type(class);
if (prototype->size) {
- type->sizeof_member = type__find_member_by_name(type, cu, prototype->size);
+ type->sizeof_member = type__find_member_by_name(type, prototype->size);
if (type->sizeof_member == NULL) {
fprintf(stderr, "pahole: the sizeof member '%s' wasn't found in the '%s' type\n",
prototype->size, prototype->name);
@@ -2471,7 +2920,7 @@ static enum load_steal_kind pahole_stealer(struct cu *cu,
}
if (prototype->type) {
- type->type_member = type__find_member_by_name(type, cu, prototype->type);
+ type->type_member = type__find_member_by_name(type, prototype->type);
if (type->type_member == NULL) {
fprintf(stderr, "pahole: the type member '%s' wasn't found in the '%s' type\n",
prototype->type, prototype->name);
@@ -2484,7 +2933,7 @@ static enum load_steal_kind pahole_stealer(struct cu *cu,
}
if (prototype->filter) {
- type->filter = class_member_filter__new(type, cu, prototype->filter);
+ type->filter = class_member_filter__new(type, prototype->filter);
if (type->filter == NULL) {
fprintf(stderr, "pahole: invalid filter '%s' for '%s'\n",
prototype->filter, prototype->name);
@@ -2498,7 +2947,7 @@ static enum load_steal_kind pahole_stealer(struct cu *cu,
class_id = 0;
}
- if (!isatty(0)) {
+ if (prettify_input) {
prototype->class = class;
prototype->cu = cu;
continue;
@@ -2534,10 +2983,13 @@ static enum load_steal_kind pahole_stealer(struct cu *cu,
}
}
- // If we got here with pretty printing is because we have everything solved except for type_enum
+ // If we got here with pretty printing is because we have everything solved except for type_enum or --header
+
+ if (prettify_input) {
+ // Check if we need to continue loading CUs to get those type_enum= and --header resolved
+ if (header == NULL && conf.header_type)
+ return LSK__KEEPIT;
- if (!isatty(0)) {
- // Check if we need to continue loading CUs to get those type_enum= resolved
list_for_each_entry(prototype, &class_names, node) {
if (prototype->type_enum && !prototype->type_enum_resolved)
return LSK__KEEPIT;
@@ -2546,7 +2998,7 @@ static enum load_steal_kind pahole_stealer(struct cu *cu,
// All set, pretty print it!
list_for_each_entry_safe(prototype, n, &class_names, node) {
list_del_init(&prototype->node);
- if (prototype__stdio_fprintf_value(prototype, header, stdout) < 0)
+ if (prototype__stdio_fprintf_value(prototype, header, prettify_input, stdout) < 0)
break;
}
@@ -2583,6 +3035,9 @@ static void prototypes__delete(struct list_head *prototypes)
{
struct prototype *prototype, *n;
+ if (prototypes == NULL)
+ return;
+
list_for_each_entry_safe(prototype, n, prototypes, node) {
list_del_init(&prototype->node);
prototype__delete(prototype);
@@ -2605,7 +3060,7 @@ static int prototypes__load(struct list_head *prototypes, const char *filename)
if (len == 0)
continue;
entry[len - 1] = '\0';
- if (prototypes__add(&class_names, entry))
+ if (prototypes__add(prototypes, entry))
goto out;
}
@@ -2689,29 +3144,51 @@ int main(int argc, char *argv[])
{
int err, remaining, rc = EXIT_FAILURE;
- if (!isatty(0))
- conf.hex_fmt = 0;
-
if (argp_parse(&pahole__argp, argc, argv, 0, &remaining, NULL)) {
argp_help(&pahole__argp, stderr, ARGP_HELP_SEE, argv[0]);
goto out;
}
+ if (class_name != NULL && stats_formatter == nr_methods_formatter) {
+ fputs("pahole: -m/nr_methods doesn't work with --class/-C, it shows all classes and the number of its methods\n", stderr);
+ return rc;
+ }
+
if (print_numeric_version) {
dwarves_print_numeric_version(stdout);
return 0;
}
- if (dwarves__init(cacheline_size)) {
+ if (conf_load.hashtable_bits > 31) {
+ fprintf(stderr, "Invalid --hashbits value (%d) should be less than 32\n", conf_load.hashtable_bits);
+ goto out;
+ }
+
+ if (dwarves__init()) {
fputs("pahole: insufficient memory\n", stderr);
goto out;
}
+ dwarves__resolve_cacheline_size(&conf_load, cacheline_size);
+
+ if (prettify_input_filename) {
+ if (strcmp(prettify_input_filename, "-") == 0) {
+ prettify_input = stdin;
+ } else {
+ prettify_input = fopen(prettify_input_filename, "r");
+ if (prettify_input == NULL) {
+ fprintf(stderr, "Failed to read input '%s': %s\n",
+ prettify_input_filename, strerror(errno));
+ goto out_dwarves_exit;
+ }
+ }
+ }
+
if (base_btf_file) {
- base_btf = btf__parse(base_btf_file, NULL);
- if (libbpf_get_error(base_btf)) {
+ conf_load.base_btf = btf__parse(base_btf_file, NULL);
+ if (libbpf_get_error(conf_load.base_btf)) {
fprintf(stderr, "Failed to parse base BTF '%s': %ld\n",
- base_btf_file, libbpf_get_error(base_btf));
+ base_btf_file, libbpf_get_error(conf_load.base_btf));
goto out;
}
if (!btf_encode && !ctf_encode) {
@@ -2731,7 +3208,7 @@ int main(int argc, char *argv[])
conf_load.steal = pahole_stealer;
// Make 'pahole --header type < file' a shorter form of 'pahole -C type --count 1 < file'
- if (conf.header_type && !class_name && !isatty(0)) {
+ if (conf.header_type && !class_name && prettify_input) {
conf.count = 1;
class_name = conf.header_type;
conf.header_type = 0; // so that we don't read it and then try to read the -C type
@@ -2748,10 +3225,10 @@ try_sole_arg_as_class_names:
strstarts(filename, "/sys/kernel/btf/") &&
strstr(filename, "/vmlinux") == NULL) {
base_btf_file = "/sys/kernel/btf/vmlinux";
- base_btf = btf__parse(base_btf_file, NULL);
- if (libbpf_get_error(base_btf)) {
+ conf_load.base_btf = btf__parse(base_btf_file, NULL);
+ if (libbpf_get_error(conf_load.base_btf)) {
fprintf(stderr, "Failed to parse base BTF '%s': %ld\n",
- base_btf_file, libbpf_get_error(base_btf));
+ base_btf_file, libbpf_get_error(conf_load.base_btf));
goto out;
}
}
@@ -2773,6 +3250,11 @@ try_sole_arg_as_class_names:
goto out_cus_delete;
}
+ if (sort_output && formatter == class_formatter) {
+ print_ordered_classes();
+ goto out_ok;
+ }
+
if (!list_empty(&class_names)) {
struct prototype *prototype;
@@ -2811,23 +3293,29 @@ try_sole_arg_as_class_names:
header = NULL;
if (btf_encode) {
- err = btf_encoder__encode();
+ err = btf_encoder__encode(btf_encoder);
if (err) {
fputs("Failed to encode BTF\n", stderr);
goto out_cus_delete;
}
}
-
+out_ok:
if (stats_formatter != NULL)
print_stats();
+
rc = EXIT_SUCCESS;
out_cus_delete:
#ifdef DEBUG_CHECK_LEAKS
cus__delete(cus);
structures__delete();
- btf__free(base_btf);
+ btf__free(conf_load.base_btf);
+ conf_load.base_btf = NULL;
#endif
out_dwarves_exit:
+ if (prettify_input && prettify_input != stdin) {
+ fclose(prettify_input);
+ prettify_input = NULL;
+ }
#ifdef DEBUG_CHECK_LEAKS
dwarves__exit();
#endif
diff --git a/pahole_strings.h b/pahole_strings.h
deleted file mode 100644
index 522fbf2..0000000
--- a/pahole_strings.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef _STRINGS_H_
-#define _STRINGS_H_ 1
-/*
- SPDX-License-Identifier: GPL-2.0-only
-
- Copyright (C) 2008 Arnaldo Carvalho de Melo <acme@redhat.com>
-*/
-
-#include "lib/bpf/src/btf.h"
-
-typedef unsigned int strings_t;
-
-struct strings {
- struct btf *btf;
-};
-
-struct strings *strings__new(void);
-
-void strings__delete(struct strings *strings);
-
-strings_t strings__add(struct strings *strings, const char *str);
-strings_t strings__find(struct strings *strings, const char *str);
-strings_t strings__size(const struct strings *strings);
-int strings__copy(const struct strings *strings, void *dst);
-
-static inline const char *strings__ptr(const struct strings *strings, strings_t s)
-{
- return btf__str_by_offset(strings->btf, s);
-}
-
-#endif /* _STRINGS_H_ */
diff --git a/pdwtags.c b/pdwtags.c
index a869767..2b5ba1b 100644
--- a/pdwtags.c
+++ b/pdwtags.c
@@ -25,8 +25,7 @@ static void emit_tag(struct tag *tag, uint32_t tag_id, struct cu *cu)
if (tag->tag == DW_TAG_base_type) {
char bf[64];
- const char *name = base_type__name(tag__base_type(tag), cu,
- bf, sizeof(bf));
+ const char *name = base_type__name(tag__base_type(tag), bf, sizeof(bf));
if (name == NULL)
printf("anonymous base_type\n");
@@ -73,7 +72,7 @@ static int cu__emit_tags(struct cu *cu)
}
static enum load_steal_kind pdwtags_stealer(struct cu *cu,
- struct conf_load *conf_load __unused)
+ struct conf_load *conf_load __maybe_unused)
{
cu__emit_tags(cu);
return LSK__DELETE;
@@ -104,7 +103,7 @@ static const struct argp_option pdwtags__options[] = {
}
};
-static error_t pdwtags__options_parser(int key, char *arg __unused,
+static error_t pdwtags__options_parser(int key, char *arg __maybe_unused,
struct argp_state *state)
{
switch (key) {
@@ -132,11 +131,13 @@ int main(int argc, char *argv[])
int remaining, rc = EXIT_FAILURE, err;
struct cus *cus = cus__new();
- if (dwarves__init(0) || cus == NULL) {
+ if (dwarves__init() || cus == NULL) {
fputs("pwdtags: insufficient memory\n", stderr);
goto out;
}
+ dwarves__resolve_cacheline_size(&pdwtags_conf_load, 0);
+
if (argp_parse(&pdwtags__argp, argc, argv, 0, &remaining, NULL) ||
remaining == argc) {
argp_help(&pdwtags__argp, stderr, ARGP_HELP_SEE, argv[0]);
diff --git a/pfunct.c b/pfunct.c
index bc8e4ab..5485622 100644
--- a/pfunct.c
+++ b/pfunct.c
@@ -80,8 +80,7 @@ static struct fn_stats *fn_stats__find(const char *name)
struct fn_stats *pos;
list_for_each_entry(pos, &fn_stats__list, node)
- if (strcmp(function__name(tag__function(pos->tag), pos->cu),
- name) == 0)
+ if (strcmp(function__name(tag__function(pos->tag)), name) == 0)
return pos;
return NULL;
}
@@ -107,7 +106,7 @@ static void fn_stats_inline_exps_fmtr(const struct fn_stats *stats)
{
struct function *fn = tag__function(stats->tag);
if (fn->lexblock.nr_inline_expansions > 0)
- printf("%s: %u %d\n", function__name(fn, stats->cu),
+ printf("%s: %u %d\n", function__name(fn),
fn->lexblock.nr_inline_expansions,
fn->lexblock.size_inline_expansions);
}
@@ -116,29 +115,26 @@ static void fn_stats_labels_fmtr(const struct fn_stats *stats)
{
struct function *fn = tag__function(stats->tag);
if (fn->lexblock.nr_labels > 0)
- printf("%s: %u\n", function__name(fn, stats->cu),
- fn->lexblock.nr_labels);
+ printf("%s: %u\n", function__name(fn), fn->lexblock.nr_labels);
}
static void fn_stats_variables_fmtr(const struct fn_stats *stats)
{
struct function *fn = tag__function(stats->tag);
if (fn->lexblock.nr_variables > 0)
- printf("%s: %u\n", function__name(fn, stats->cu),
- fn->lexblock.nr_variables);
+ printf("%s: %u\n", function__name(fn), fn->lexblock.nr_variables);
}
static void fn_stats_nr_parms_fmtr(const struct fn_stats *stats)
{
struct function *fn = tag__function(stats->tag);
- printf("%s: %u\n", function__name(fn, stats->cu),
- fn->proto.nr_parms);
+ printf("%s: %u\n", function__name(fn), fn->proto.nr_parms);
}
static void fn_stats_name_len_fmtr(const struct fn_stats *stats)
{
struct function *fn = tag__function(stats->tag);
- const char *name = function__name(fn, stats->cu);
+ const char *name = function__name(fn);
printf("%s: %zd\n", name, strlen(name));
}
@@ -148,7 +144,7 @@ static void fn_stats_size_fmtr(const struct fn_stats *stats)
const size_t size = function__size(fn);
if (size != 0)
- printf("%s: %zd\n", function__name(fn, stats->cu), size);
+ printf("%s: %zd\n", function__name(fn), size);
}
static void fn_stats_fmtr(const struct fn_stats *stats)
@@ -164,7 +160,7 @@ static void fn_stats_fmtr(const struct fn_stats *stats)
putchar('\n');
} else {
struct function *fn = tag__function(stats->tag);
- puts(function__name(fn, stats->cu));
+ puts(function__name(fn));
}
}
@@ -180,7 +176,7 @@ static void fn_stats_inline_stats_fmtr(const struct fn_stats *stats)
{
if (stats->nr_expansions > 1)
printf("%-31.31s %6u %7u %6u %6u\n",
- function__name(tag__function(stats->tag), stats->cu),
+ function__name(tag__function(stats->tag)),
stats->size_expansions, stats->nr_expansions,
stats->size_expansions / stats->nr_expansions,
stats->nr_files);
@@ -195,17 +191,14 @@ static void print_total_inline_stats(void)
static void fn_stats__dupmsg(struct function *func,
const struct cu *func_cu,
- struct function *dup __unused,
+ struct function *dup __maybe_unused,
const struct cu *dup_cu,
char *hdr, const char *fmt, ...)
{
va_list args;
if (!*hdr)
- printf("function: %s\nfirst: %s\ncurrent: %s\n",
- function__name(func, func_cu),
- func_cu->name,
- dup_cu->name);
+ printf("function: %s\nfirst: %s\ncurrent: %s\n", function__name(func), func_cu->name, dup_cu->name);
va_start(args, fmt);
vprintf(fmt, args);
@@ -253,7 +246,7 @@ static bool function__filter(struct function *function, struct cu *cu)
if (!function->name)
return true;
- name = function__name(function, cu);
+ name = function__name(function);
if (show_externals && !function->external)
return true;
@@ -282,7 +275,7 @@ static bool function__filter(struct function *function, struct cu *cu)
return false;
}
-static int cu_unique_iterator(struct cu *cu, void *cookie __unused)
+static int cu_unique_iterator(struct cu *cu, void *cookie __maybe_unused)
{
cu__account_inline_expansions(cu);
@@ -314,7 +307,7 @@ static int cu_class_iterator(struct cu *cu, void *cookie)
if (verbose)
tag__fprintf(function__tag(pos), cu, &conf, stdout);
else
- fputs(function__name(pos, cu), stdout);
+ fputs(function__name(pos), stdout);
putchar('\n');
}
@@ -385,11 +378,11 @@ static void function__show(struct function *func, struct cu *cu)
if (tag__is_pointer(type))
fprintf(stdout, "\n\treturn (void *)0;");
else if (tag__is_struct(type))
- fprintf(stdout, "\n\treturn *(struct %s *)1;", class__name(tag__class(type), cu));
+ fprintf(stdout, "\n\treturn *(struct %s *)1;", class__name(tag__class(type)));
else if (tag__is_union(type))
- fprintf(stdout, "\n\treturn *(union %s *)1;", type__name(tag__type(type), cu));
+ fprintf(stdout, "\n\treturn *(union %s *)1;", type__name(tag__type(type)));
else if (tag__is_typedef(type))
- fprintf(stdout, "\n\treturn *(%s *)1;", type__name(tag__type(type), cu));
+ fprintf(stdout, "\n\treturn *(%s *)1;", type__name(tag__type(type)));
else
fprintf(stdout, "\n\treturn 0;");
}
@@ -406,7 +399,7 @@ static int cu_function_iterator(struct cu *cu, void *cookie)
uint32_t id;
cu__for_each_function(cu, id, function) {
- if (cookie && strcmp(function__name(function, cu), cookie) != 0)
+ if (cookie && strcmp(function__name(function), cookie) != 0)
continue;
function__show(function, cu);
if (!expand_types)
@@ -439,7 +432,7 @@ int elf_symtab__show(char *filename)
goto out_elf_end;
}
- struct elf_symtab *symtab = elf_symtab__new(symtab_name, elf, &ehdr);
+ struct elf_symtab *symtab = elf_symtab__new(symtab_name, elf);
if (symtab == NULL)
goto out_elf_end;
@@ -496,7 +489,7 @@ int elf_symtabs__show(char *filenames[])
return EXIT_SUCCESS;
}
-static enum load_steal_kind pfunct_stealer(struct cu *cu, struct conf_load *conf_load __unused)
+static enum load_steal_kind pfunct_stealer(struct cu *cu, struct conf_load *conf_load __maybe_unused)
{
if (function_name) {
@@ -728,11 +721,13 @@ int main(int argc, char *argv[])
if (symtab_name != NULL)
return elf_symtabs__show(argv + remaining);
- if (dwarves__init(0)) {
+ if (dwarves__init()) {
fputs("pfunct: insufficient memory\n", stderr);
goto out;
}
+ dwarves__resolve_cacheline_size(&conf_load, 0);
+
struct cus *cus = cus__new();
if (cus == NULL) {
fputs("pfunct: insufficient memory\n", stderr);
diff --git a/pglobal.c b/pglobal.c
index 84746bf..9341244 100644
--- a/pglobal.c
+++ b/pglobal.c
@@ -56,7 +56,7 @@ static struct extvar *extvar__new(const struct variable *var,
gvar->next = NULL;
gvar->var = var;
gvar->cu = cu;
- gvar->name = variable__name(var, cu);
+ gvar->name = variable__name(var);
}
return gvar;
@@ -71,7 +71,7 @@ static struct extfun *extfun__new(struct function *fun,
gfun->next = NULL;
gfun->fun = fun;
gfun->cu = cu;
- gfun->name = function__name(fun, cu);
+ gfun->name = function__name(fun);
}
return gfun;
@@ -124,7 +124,7 @@ static void extfun__add(struct function *fun, const struct cu *cu)
}
}
-static int cu_extvar_iterator(struct cu *cu, void *cookie __unused)
+static int cu_extvar_iterator(struct cu *cu, void *cookie __maybe_unused)
{
struct tag *pos;
uint32_t id;
@@ -137,7 +137,7 @@ static int cu_extvar_iterator(struct cu *cu, void *cookie __unused)
return 0;
}
-static int cu_extfun_iterator(struct cu *cu, void *cookie __unused)
+static int cu_extfun_iterator(struct cu *cu, void *cookie __maybe_unused)
{
struct function *pos;
uint32_t id;
@@ -169,7 +169,7 @@ static inline struct tag *extfun__tag(const struct extfun *gfun)
}
static void declaration_action__walk(const void *nodep, const VISIT which,
- const int depth __unused)
+ const int depth __maybe_unused)
{
uint32_t count = 0;
struct tag *tag;
@@ -202,7 +202,7 @@ static void declaration_action__walk(const void *nodep, const VISIT which,
}
static void function_action__walk(const void *nodep, const VISIT which,
- const int depth __unused)
+ const int depth __maybe_unused)
{
struct tag *tag;
const struct extfun *gfun = NULL;
@@ -268,7 +268,7 @@ static const struct argp_option pglobal__options[] = {
static int walk_var, walk_fun;
-static error_t pglobal__options_parser(int key, char *arg __unused,
+static error_t pglobal__options_parser(int key, char *arg __maybe_unused,
struct argp_state *state)
{
switch (key) {
@@ -303,11 +303,13 @@ int main(int argc, char *argv[])
goto out;
}
- if (dwarves__init(0)) {
+ if (dwarves__init()) {
fputs("pglobal: insufficient memory\n", stderr);
goto out;
}
+ dwarves__resolve_cacheline_size(&conf_load, 0);
+
struct cus *cus = cus__new();
if (cus == NULL) {
fputs("pglobal: insufficient memory\n", stderr);
diff --git a/prefcnt.c b/prefcnt.c
index d8f14ee..8010afd 100644
--- a/prefcnt.c
+++ b/prefcnt.c
@@ -106,7 +106,7 @@ static void refcnt_function(struct function *function, const struct cu *cu)
refcnt_lexblock(&function->lexblock, cu);
}
-static int cu_refcnt_iterator(struct cu *cu, void *cookie __unused)
+static int cu_refcnt_iterator(struct cu *cu, void *cookie __maybe_unused)
{
struct function *pos;
uint32_t id;
@@ -117,7 +117,7 @@ static int cu_refcnt_iterator(struct cu *cu, void *cookie __unused)
}
static int lost_iterator(struct tag *tag, struct cu *cu,
- void *cookie __unused)
+ void *cookie __maybe_unused)
{
if (!tag->visited && tag__decl_file(tag, cu)) {
tag__fprintf(tag, cu, NULL, stdout);
@@ -131,16 +131,18 @@ static int cu_lost_iterator(struct cu *cu, void *cookie)
return cu__for_all_tags(cu, lost_iterator, cookie);
}
-int main(int argc __unused, char *argv[])
+int main(int argc __maybe_unused, char *argv[])
{
int err;
struct cus *cus = cus__new();
- if (dwarves__init(0) || cus == NULL) {
+ if (dwarves__init() || cus == NULL) {
fputs("prefcnt: insufficient memory\n", stderr);
return EXIT_FAILURE;
}
+ dwarves__resolve_cacheline_size(NULL, 0);
+
err = cus__load_files(cus, NULL, argv + 1);
if (err != 0) {
cus__fprintf_load_files_err(cus, "prefcnt", argv + 1, err, stderr);
diff --git a/rpm/SPECS/dwarves.spec b/rpm/SPECS/dwarves.spec
index 693a9da..0b4846e 100644
--- a/rpm/SPECS/dwarves.spec
+++ b/rpm/SPECS/dwarves.spec
@@ -2,7 +2,7 @@
%define libver 1
Name: dwarves
-Version: 1.19
+Version: 1.23
Release: 1%{?dist}
License: GPLv2
Summary: Debugging Information Manipulation Tools (pahole & friends)
@@ -10,7 +10,7 @@ URL: http://acmel.wordpress.com
Source: http://fedorapeople.org/~acme/dwarves/%{name}-%{version}.tar.xz
Requires: %{libname}%{libver} = %{version}-%{release}
BuildRequires: gcc
-BuildRequires: cmake
+BuildRequires: cmake >= 2.8.12
BuildRequires: zlib-devel
BuildRequires: elfutils-devel >= 0.130
@@ -79,7 +79,7 @@ rm -Rf %{buildroot}
%files
%doc README.ctracer
%doc README.btf
-%doc changes-v1.19
+%doc changes-v1.23
%doc NEWS
%{_bindir}/btfdiff
%{_bindir}/codiff
@@ -114,7 +114,6 @@ rm -Rf %{buildroot}
%doc MANIFEST README
%{_includedir}/dwarves/btf_encoder.h
%{_includedir}/dwarves/config.h
-%{_includedir}/dwarves/ctf_encoder.h
%{_includedir}/dwarves/ctf.h
%{_includedir}/dwarves/dutil.h
%{_includedir}/dwarves/dwarves.h
@@ -124,16 +123,84 @@ rm -Rf %{buildroot}
%{_includedir}/dwarves/elf_symtab.h
%{_includedir}/dwarves/gobuffer.h
%{_includedir}/dwarves/hash.h
-%{_includedir}/dwarves/libbtf.h
%{_includedir}/dwarves/libctf.h
%{_includedir}/dwarves/list.h
%{_includedir}/dwarves/rbtree.h
-%{_includedir}/dwarves/pahole_strings.h
%{_libdir}/%{libname}.so
%{_libdir}/%{libname}_emit.so
%{_libdir}/%{libname}_reorganize.so
%changelog
+* Wed Dec 8 2021 Arnaldo Carvalho de Melo <acme@redhat.com> - 1.23-1
+- New release: v1.23
+- Process DW_TAG_LLVM_annotation tags.
+- Initial support for DW_TAG_skeleton_unit.
+- Encode BTF_KIND_TYPE_TAG and BTF_KIND_DECL_TAG
+- Fix handling of percpu symbols on s390.
+- Use cacheline size to infer struct member alignment from BTF.
+- Add --skip_missing to not stop when not finding one of -C arguments.
+- Fix __attribute__((__aligned__(N)) printing alignment for struct members.
+- Fix nested __attribute__(__aligned__(N)) struct printing order.
+
+* Mon Aug 23 2021 Arnaldo Carvalho de Melo <acme@redhat.com> - 1.22-1
+- New release: v1.22
+- Introduce -j/--jobs option to specify the number of threads to use.
+- Multithreaded DWARF loading, requires elfutils >= 0.178.
+- Preparatory work for multithreaded BTF encoding, the focus for 1.23.
+- Allow encoding BTF to a separate file.
+- Show all different types with the same name, not just the first one found.
+- Stop assuming that reading from stdin means pretty, add --prettify.
+- Improve type resolution for the --header command line option.
+- Do not consider the ftrace filter when encoding BTF for kernel functions.
+- Lock calls to non-thread safe elfutils' dwarf_decl_file() and dwarf_decl_line().
+- Change hash table size to one that performs better with current typical vmlinux files.
+- Allow tweaking the hash table size from the command line.
+- Add --kabi_prefix to avoid deduplication woes when using _RH_KABI_REPLACE().
+- Add --with_flexible_array to show just types with flexible arrays.
+- Support btfdiff with a detached BTF file.
+- Introduce sorted type output (--sort).
+- Disable incomplete CTF encoder.
+
+* Fri Apr 9 2021 Arnaldo Carvalho de Melo <acme@redhat.com> - 1.21-1
+- New release: v1.21
+- DWARF loader:
+- Handle DWARF5 DW_OP_addrx properly
+- Handle subprogram ret type with abstract_origin properly
+- Check .notes section for LTO build info
+- Check .debug_abbrev for cross-CU references
+- Permit merging all DWARF CU's for clang LTO built binary
+- Factor out common code to initialize a cu
+- Permit a flexible HASHTAGS__BITS
+- Use a better hashing function, from libbpf
+- btf_encoder:
+- Add --btf_gen_all flag
+- Match ftrace addresses within ELF functions
+- Funnel ELF error reporting through a macro
+- Sanitize non-regular int base type
+- Add support for the floating-point types
+- Pretty printer:
+- Honour conf_fprintf.hex when printing enumerations
+
+* Tue Feb 2 2021 Arnaldo Carvalho de Melo <acme@redhat.com> - 1.20-1
+- New release: v1.20
+- btf_encoder:
+- Improve ELF error reporting using elf_errmsg(elf_errno())
+- Improve objcopy error handling.
+- Fix handling of 'restrict' qualifier, that was being treated as a 'const'.
+- Support SHN_XINDEX in st_shndx symbol indexes
+- Cope with functions without a name
+- Fix BTF variable generation for kernel modules
+- Fix address size to match what is in the ELF file being processed.
+- Use kernel module ftrace addresses when finding which functions to encode.
+- libbpf:
+- Allow use of packaged version.
+- dwarf_loader:
+- Support DW_AT_data_bit_offset
+- DW_FORM_implicit_const in attr_numeric() and attr_offset()
+- Support DW_TAG_GNU_call_site, standardized rename of DW_TAG_GNU_call_site.
+- build:
+- Fix compilation on 32-bit architectures.
+
* Fri Nov 20 2020 Arnaldo Carvalho de Melo <acme@redhat.com> - 1.19-1
- New release: 1.19
- Split BTF
@@ -275,7 +342,7 @@ rm -Rf %{buildroot}
* Sat Nov 20 2010 Arnaldo Carvalho de Melo <acme@redhat.com> - 1.9-1
- New release
-* Tue Feb 08 2010 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.8-2
+* Mon Feb 08 2010 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.8-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild
* Fri Dec 4 2009 Arnaldo Carvalho de Melo <acme@redhat.com> - 1.8-1
@@ -426,7 +493,7 @@ rm -Rf %{buildroot}
- Fix emission of arrays of structs, unions, etc
- use sysconf for the default cacheline size
-* Wed Jan 18 2007 Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
+* Thu Jan 18 2007 Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
- fab0db03ea9046893ca110bb2b7d71b764f61033
- pdwtags added
diff --git a/scncopy.c b/scncopy.c
index 539186f..233cae2 100644
--- a/scncopy.c
+++ b/scncopy.c
@@ -118,7 +118,7 @@ err:
if (!should_copy_scn(elf, shdr, sections) && !copy_all_sections)
continue;
- elfcreator_copy_scn(ctor, elf, scn);
+ elfcreator_copy_scn(ctor, scn);
}
elfcreator_end(ctor);
return 0;
diff --git a/strings.c b/strings.c
deleted file mode 100644
index d37f49d..0000000
--- a/strings.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- SPDX-License-Identifier: GPL-2.0-only
-
- Copyright (C) 2008 Arnaldo Carvalho de Melo <acme@redhat.com>
-*/
-
-#include "pahole_strings.h"
-#include "gobuffer.h"
-
-#include <search.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <zlib.h>
-
-#include "dutil.h"
-#include "lib/bpf/src/libbpf.h"
-
-struct strings *strings__new(void)
-{
- struct strings *strs = malloc(sizeof(*strs));
-
- if (!strs)
- return NULL;
-
- strs->btf = btf__new_empty();
- if (libbpf_get_error(strs->btf)) {
- free(strs);
- return NULL;
- }
-
- return strs;
-}
-
-void strings__delete(struct strings *strs)
-{
- if (strs == NULL)
- return;
- btf__free(strs->btf);
- free(strs);
-}
-
-strings_t strings__add(struct strings *strs, const char *str)
-{
- strings_t index;
-
- if (str == NULL)
- return 0;
-
- index = btf__add_str(strs->btf, str);
- if (index < 0)
- return 0;
-
- return index;
-}
-
-strings_t strings__find(struct strings *strs, const char *str)
-{
- return btf__find_str(strs->btf, str);
-}
-
-/* a horrible and inefficient hack to get string section size out of BTF */
-strings_t strings__size(const struct strings *strs)
-{
- const struct btf_header *p;
- uint32_t sz;
-
- p = btf__get_raw_data(strs->btf, &sz);
- if (!p)
- return -1;
-
- return p->str_len;
-}
-
-/* similarly horrible hack to copy out string section out of BTF */
-int strings__copy(const struct strings *strs, void *dst)
-{
- const struct btf_header *p;
- uint32_t sz;
-
- p = btf__get_raw_data(strs->btf, &sz);
- if (!p)
- return -1;
-
- memcpy(dst, (void *)p + p->str_off, p->str_len);
- return 0;
-}
diff --git a/syscse.c b/syscse.c
index 6df8674..67a6c52 100644
--- a/syscse.c
+++ b/syscse.c
@@ -18,10 +18,10 @@
static const char *prefix = "sys_";
static size_t prefix_len = 4;
-static bool filter(struct function *f, struct cu *cu)
+static bool filter(struct function *f)
{
if (f->proto.nr_parms != 0) {
- const char *name = function__name(f, cu);
+ const char *name = function__name(f);
if (strlen(name) > prefix_len &&
memcmp(name, prefix, prefix_len) == 0)
@@ -30,8 +30,7 @@ static bool filter(struct function *f, struct cu *cu)
return true;
}
-static void zero_extend(const int regparm, const struct base_type *bt,
- struct cu *cu, const char *parm)
+static void zero_extend(const int regparm, const struct base_type *bt, const char *parm)
{
const char *instr = "INVALID";
@@ -51,14 +50,14 @@ static void zero_extend(const int regparm, const struct base_type *bt,
printf("\t%s\t$a%d, $a%d, 0"
"\t/* zero extend $a%d(%s %s) from %d to 64-bit */\n",
instr, regparm, regparm, regparm,
- base_type__name(bt, cu, bf, sizeof(bf)),
+ base_type__name(bt, bf, sizeof(bf)),
parm, bt->bit_size);
}
static void emit_wrapper(struct function *f, struct cu *cu)
{
struct parameter *parm;
- const char *name = function__name(f, cu);
+ const char *name = function__name(f);
int regparm = 0, needs_wrapper = 0;
function__for_each_parameter(f, cu, parm) {
@@ -71,14 +70,12 @@ static void emit_wrapper(struct function *f, struct cu *cu)
char bf[64];
if (bt->bit_size < 64 &&
- strncmp(base_type__name(bt, cu, bf, sizeof(bf)),
- "unsigned", 8) == 0) {
+ strncmp(base_type__name(bt, bf, sizeof(bf)), "unsigned", 8) == 0) {
if (!needs_wrapper) {
printf("wrap_%s:\n", name);
needs_wrapper = 1;
}
- zero_extend(regparm, bt, cu,
- parameter__name(parm, cu));
+ zero_extend(regparm, bt, parameter__name(parm));
}
}
++regparm;
@@ -88,13 +85,13 @@ static void emit_wrapper(struct function *f, struct cu *cu)
printf("\tj\t%s\n\n", name);
}
-static int cu__emit_wrapper(struct cu *cu, void *cookie __unused)
+static int cu__emit_wrapper(struct cu *cu, void *cookie __maybe_unused)
{
struct function *pos;
uint32_t id;
cu__for_each_function(cu, id, pos)
- if (!filter(pos, cu))
+ if (!filter(pos))
emit_wrapper(pos, cu);
return 0;
}