[test][dwarfdump] infrostructure for parsing dwarfdump output
This commit is contained in:
+1
@@ -16,6 +16,7 @@ object DistProperties {
|
||||
val konanc: Path = dist.resolve("bin/$konancDriver")
|
||||
val lldb: Path = Paths.get("lldb")
|
||||
val devToolsSecurity: Path = Paths.get("DevToolsSecurity")
|
||||
val dwarfDump: Path = Paths.get("dwarfdump")
|
||||
val lldbPrettyPrinters: Path = dist.resolve("tools/konan_lldb.py")
|
||||
|
||||
private fun requireProp(name: String): String
|
||||
|
||||
+10
@@ -19,9 +19,14 @@ import java.nio.file.Path
|
||||
import java.time.temporal.ChronoUnit
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
|
||||
/**
|
||||
* TODO: This constructor looks weird in conjunction with [DistProperties]
|
||||
*/
|
||||
class ToolDriver(
|
||||
private val konancDriver: Path,
|
||||
private val lldb: Path,
|
||||
private val dwarfDump: Path,
|
||||
private val lldbPrettyPrinters: Path,
|
||||
private val useInProcessCompiler: Boolean = false
|
||||
) {
|
||||
@@ -46,6 +51,11 @@ class ToolDriver(
|
||||
.thrownIfFailed()
|
||||
.stdout
|
||||
}
|
||||
|
||||
fun runDwarfDump(program: Path, processor:List<DwarfTag>.()->Unit) {
|
||||
val out = subprocess(dwarfDump, "${program}.dSYM/Contents/Resources/DWARF/${program.fileName}").takeIf { it.process.exitValue() == 0 }?.stdout ?: error("${program}.dSYM/Contents/Resources/DWARF/${program.fileName}")
|
||||
DwarfUtilParser().parse(StringReader(out)).tags.toList().processor()
|
||||
}
|
||||
}
|
||||
|
||||
data class ProcessOutput(
|
||||
|
||||
+363
@@ -0,0 +1,363 @@
|
||||
package org.jetbrains.kotlin.native.test.debugger
|
||||
|
||||
import java.io.File
|
||||
import java.io.Reader
|
||||
import java.lang.StringBuilder
|
||||
|
||||
sealed class DwarfTag(val tag: Tag) {
|
||||
enum class Tag(val value: Int) {
|
||||
DW_TAG_array_type(0x0001),
|
||||
DW_TAG_class_type(0x0002),
|
||||
DW_TAG_entry_point(0x0003),
|
||||
DW_TAG_enumeration_type(0x0004),
|
||||
DW_TAG_formal_parameter(0x0005),
|
||||
DW_TAG_imported_declaration(0x0008),
|
||||
DW_TAG_label(0x000a),
|
||||
DW_TAG_lexical_block(0x000b),
|
||||
DW_TAG_member(0x000d),
|
||||
DW_TAG_pointer_type(0x000f),
|
||||
DW_TAG_reference_type(0x0010),
|
||||
DW_TAG_compile_unit(0x0011),
|
||||
DW_TAG_string_type(0x0012),
|
||||
DW_TAG_structure_type(0x0013),
|
||||
DW_TAG_subroutine_type(0x0015),
|
||||
DW_TAG_typedef(0x0016),
|
||||
DW_TAG_union_type(0x0017),
|
||||
DW_TAG_unspecified_parameters(0x0018),
|
||||
DW_TAG_variant(0x0019),
|
||||
DW_TAG_common_block(0x001a),
|
||||
DW_TAG_common_inclusion(0x001b),
|
||||
DW_TAG_inheritance(0x001c),
|
||||
DW_TAG_inlined_subroutine(0x001d),
|
||||
DW_TAG_module(0x001e),
|
||||
DW_TAG_ptr_to_member_type(0x001f),
|
||||
DW_TAG_set_type(0x0020),
|
||||
DW_TAG_subrange_type(0x0021),
|
||||
DW_TAG_with_stmt(0x0022),
|
||||
DW_TAG_access_declaration(0x0023),
|
||||
DW_TAG_base_type(0x0024),
|
||||
DW_TAG_catch_block(0x0025),
|
||||
DW_TAG_const_type(0x0026),
|
||||
DW_TAG_constant(0x0027),
|
||||
DW_TAG_enumerator(0x0028),
|
||||
DW_TAG_file_type(0x0029),
|
||||
DW_TAG_friend(0x002a),
|
||||
DW_TAG_namelist(0x002b),
|
||||
DW_TAG_namelist_item(0x002c),
|
||||
DW_TAG_packed_type(0x002d),
|
||||
DW_TAG_subprogram(0x002e),
|
||||
DW_TAG_template_type_parameter(0x002f),
|
||||
DW_TAG_template_value_parameter(0x0030),
|
||||
DW_TAG_thrown_type(0x0031),
|
||||
DW_TAG_try_block(0x0032),
|
||||
DW_TAG_variant_part(0x0033),
|
||||
DW_TAG_variable(0x0034),
|
||||
DW_TAG_volatile_type(0x0035),
|
||||
DW_TAG_dwarf_procedure(0x0036),
|
||||
DW_TAG_restrict_type(0x0037),
|
||||
DW_TAG_interface_type(0x0038),
|
||||
DW_TAG_namespace(0x0039),
|
||||
DW_TAG_imported_module(0x003a),
|
||||
DW_TAG_unspecified_type(0x003b),
|
||||
DW_TAG_partial_unit(0x003c),
|
||||
DW_TAG_imported_unit(0x003d),
|
||||
DW_TAG_condition(0x003f),
|
||||
DW_TAG_shared_type(0x0040),
|
||||
DW_TAG_type_unit(0x0041),
|
||||
DW_TAG_rvalue_reference_type(0x0042),
|
||||
DW_TAG_template_alias(0x0043),
|
||||
DW_TAG_coarray_type(0x0044),
|
||||
DW_TAG_generic_subrange(0x0045),
|
||||
DW_TAG_dynamic_type(0x0046),
|
||||
DW_TAG_MIPS_loop(0x4081),
|
||||
DW_TAG_format_label(0x4101),
|
||||
DW_TAG_function_template(0x4102),
|
||||
DW_TAG_class_template(0x4103),
|
||||
DW_TAG_GNU_template_template_param(0x4106),
|
||||
DW_TAG_GNU_template_parameter_pack(0x4107),
|
||||
DW_TAG_GNU_formal_parameter_pack(0x4108),
|
||||
DW_TAG_APPLE_property(0x4200),
|
||||
DW_TAG_BORLAND_property(0xb000),
|
||||
DW_TAG_BORLAND_Delphi_string(0xb001),
|
||||
DW_TAG_BORLAND_Delphi_dynamic_array(0xb002),
|
||||
DW_TAG_BORLAND_Delphi_set(0xb003),
|
||||
DW_TAG_BORLAND_Delphi_variant(0xb004),
|
||||
}
|
||||
val attributes = mutableMapOf<DwarfAttribute.Attribute, DwarfAttribute>()
|
||||
operator fun DwarfAttribute.unaryPlus() { attributes[this.attribute] = this }
|
||||
companion object {
|
||||
fun by(name: String) = by(Tag.valueOf(name))
|
||||
fun by(tag: Tag) = when(tag) {
|
||||
Tag.DW_TAG_subprogram -> DwarfTagSubprogram()
|
||||
else -> DwarfTagDefault(tag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class DwarfTagDefault(tag: DwarfTag.Tag): DwarfTag(tag)
|
||||
class DwarfTagSubprogram: DwarfTag(Tag.DW_TAG_subprogram) {
|
||||
val name: String
|
||||
get() = attributes[DwarfAttribute.Attribute.DW_AT_name]!!.rvString
|
||||
val path: String?
|
||||
get() = attributes[DwarfAttribute.Attribute.DW_AT_decl_file]?.rvString
|
||||
val file: File?
|
||||
get() = path?.run { File(this) }
|
||||
}
|
||||
|
||||
class DwarfAttribute(val attribute: Attribute, val rawValue: String) {
|
||||
enum class Attribute(val value: Int) {
|
||||
DW_AT_sibling(0x01),
|
||||
DW_AT_location(0x02),
|
||||
DW_AT_name(0x03),
|
||||
DW_AT_ordering(0x09),
|
||||
DW_AT_byte_size(0x0b),
|
||||
DW_AT_bit_offset(0x0c),
|
||||
DW_AT_bit_size(0x0d),
|
||||
DW_AT_stmt_list(0x10),
|
||||
DW_AT_low_pc(0x11),
|
||||
DW_AT_high_pc(0x12),
|
||||
DW_AT_language(0x13),
|
||||
DW_AT_discr(0x15),
|
||||
DW_AT_discr_value(0x16),
|
||||
DW_AT_visibility(0x17),
|
||||
DW_AT_import(0x18),
|
||||
DW_AT_string_length(0x19),
|
||||
DW_AT_common_reference(0x1a),
|
||||
DW_AT_comp_dir(0x1b),
|
||||
DW_AT_const_value(0x1c),
|
||||
DW_AT_containing_type(0x1d),
|
||||
DW_AT_default_value(0x1e),
|
||||
DW_AT_inline(0x20),
|
||||
DW_AT_is_optional(0x21),
|
||||
DW_AT_lower_bound(0x22),
|
||||
DW_AT_producer(0x25),
|
||||
DW_AT_prototyped(0x27),
|
||||
DW_AT_return_addr(0x2a),
|
||||
DW_AT_start_scope(0x2c),
|
||||
DW_AT_bit_stride(0x2e),
|
||||
DW_AT_upper_bound(0x2f),
|
||||
DW_AT_abstract_origin(0x31),
|
||||
DW_AT_accessibility(0x32),
|
||||
DW_AT_address_class(0x33),
|
||||
DW_AT_artificial(0x34),
|
||||
DW_AT_base_types(0x35),
|
||||
DW_AT_calling_convention(0x36),
|
||||
DW_AT_count(0x37),
|
||||
DW_AT_data_member_location(0x38),
|
||||
DW_AT_decl_column(0x39),
|
||||
DW_AT_decl_file(0x3a),
|
||||
DW_AT_decl_line(0x3b),
|
||||
DW_AT_declaration(0x3c),
|
||||
DW_AT_discr_list(0x3d),
|
||||
DW_AT_encoding(0x3e),
|
||||
DW_AT_external(0x3f),
|
||||
DW_AT_frame_base(0x40),
|
||||
DW_AT_friend(0x41),
|
||||
DW_AT_identifier_case(0x42),
|
||||
DW_AT_macro_info(0x43),
|
||||
DW_AT_namelist_item(0x44),
|
||||
DW_AT_priority(0x45),
|
||||
DW_AT_segment(0x46),
|
||||
DW_AT_specification(0x47),
|
||||
DW_AT_static_link(0x48),
|
||||
DW_AT_type(0x49),
|
||||
DW_AT_use_location(0x4a),
|
||||
DW_AT_variable_parameter(0x4b),
|
||||
DW_AT_virtuality(0x4c),
|
||||
DW_AT_vtable_elem_location(0x4d),
|
||||
DW_AT_allocated(0x4e),
|
||||
DW_AT_associated(0x4f),
|
||||
DW_AT_data_location(0x50),
|
||||
DW_AT_byte_stride(0x51),
|
||||
DW_AT_entry_pc(0x52),
|
||||
DW_AT_use_UTF8(0x53),
|
||||
DW_AT_extension(0x54),
|
||||
DW_AT_ranges(0x55),
|
||||
DW_AT_trampoline(0x56),
|
||||
DW_AT_call_column(0x57),
|
||||
DW_AT_call_file(0x58),
|
||||
DW_AT_call_line(0x59),
|
||||
DW_AT_description(0x5a),
|
||||
DW_AT_binary_scale(0x5b),
|
||||
DW_AT_decimal_scale(0x5c),
|
||||
DW_AT_small(0x5d),
|
||||
DW_AT_decimal_sign(0x5e),
|
||||
DW_AT_digit_count(0x5f),
|
||||
DW_AT_picture_string(0x60),
|
||||
DW_AT_mutable(0x61),
|
||||
DW_AT_threads_scaled(0x62),
|
||||
DW_AT_explicit(0x63),
|
||||
DW_AT_object_pointer(0x64),
|
||||
DW_AT_endianity(0x65),
|
||||
DW_AT_elemental(0x66),
|
||||
DW_AT_pure(0x67),
|
||||
DW_AT_recursive(0x68),
|
||||
DW_AT_signature(0x69),
|
||||
DW_AT_main_subprogram(0x6a),
|
||||
DW_AT_data_bit_offset(0x6b),
|
||||
DW_AT_const_expr(0x6c),
|
||||
DW_AT_enum_class(0x6d),
|
||||
DW_AT_linkage_name(0x6e),
|
||||
DW_AT_string_length_bit_size(0x6f),
|
||||
DW_AT_string_length_byte_size(0x70),
|
||||
DW_AT_rank(0x71),
|
||||
DW_AT_str_offsets_base(0x72),
|
||||
DW_AT_addr_base(0x73),
|
||||
DW_AT_rnglists_base(0x74),
|
||||
DW_AT_dwo_id(0x75), ///< Retracted from DWARF v5.
|
||||
DW_AT_dwo_name(0x76),
|
||||
DW_AT_reference(0x77),
|
||||
DW_AT_rvalue_reference(0x78),
|
||||
DW_AT_macros(0x79),
|
||||
DW_AT_call_all_calls(0x7a),
|
||||
DW_AT_call_all_source_calls(0x7b),
|
||||
DW_AT_call_all_tail_calls(0x7c),
|
||||
DW_AT_call_return_pc(0x7d),
|
||||
DW_AT_call_value(0x7e),
|
||||
DW_AT_call_origin(0x7f),
|
||||
DW_AT_call_parameter(0x80),
|
||||
DW_AT_call_pc(0x81),
|
||||
DW_AT_call_tail_call(0x82),
|
||||
DW_AT_call_target(0x83),
|
||||
DW_AT_call_target_clobbered(0x84),
|
||||
DW_AT_call_data_location(0x85),
|
||||
DW_AT_call_data_value(0x86),
|
||||
DW_AT_noreturn(0x87),
|
||||
DW_AT_alignment(0x88),
|
||||
DW_AT_export_symbols(0x89),
|
||||
DW_AT_deleted(0x8a),
|
||||
DW_AT_defaulted(0x8b),
|
||||
DW_AT_loclists_base(0x8c),
|
||||
DW_AT_MIPS_loop_begin(0x2002),
|
||||
DW_AT_MIPS_tail_loop_begin(0x2003),
|
||||
DW_AT_MIPS_epilog_begin(0x2004),
|
||||
DW_AT_MIPS_loop_unroll_factor(0x2005),
|
||||
DW_AT_MIPS_software_pipeline_depth(0x2006),
|
||||
DW_AT_MIPS_linkage_name(0x2007),
|
||||
DW_AT_MIPS_stride(0x2008),
|
||||
DW_AT_MIPS_abstract_name(0x2009),
|
||||
DW_AT_MIPS_clone_origin(0x200a),
|
||||
DW_AT_MIPS_has_inlines(0x200b),
|
||||
DW_AT_MIPS_stride_byte(0x200c),
|
||||
DW_AT_MIPS_stride_elem(0x200d),
|
||||
DW_AT_MIPS_ptr_dopetype(0x200e),
|
||||
DW_AT_MIPS_allocatable_dopetype(0x200f),
|
||||
DW_AT_MIPS_assumed_shape_dopetype(0x2010),
|
||||
DW_AT_MIPS_assumed_size(0x2011),
|
||||
DW_AT_sf_names(0x2101),
|
||||
DW_AT_src_info(0x2102),
|
||||
DW_AT_mac_info(0x2103),
|
||||
DW_AT_src_coords(0x2104),
|
||||
DW_AT_body_begin(0x2105),
|
||||
DW_AT_body_end(0x2106),
|
||||
DW_AT_GNU_vector(0x2107),
|
||||
DW_AT_GNU_template_name(0x2110),
|
||||
DW_AT_GNU_odr_signature(0x210f),
|
||||
DW_AT_GNU_call_site_value(0x2111),
|
||||
DW_AT_GNU_all_call_sites(0x2117),
|
||||
DW_AT_GNU_macros(0x2119),
|
||||
DW_AT_GNU_dwo_name(0x2130),
|
||||
DW_AT_GNU_dwo_id(0x2131),
|
||||
DW_AT_GNU_ranges_base(0x2132),
|
||||
DW_AT_GNU_addr_base(0x2133),
|
||||
DW_AT_GNU_pubnames(0x2134),
|
||||
DW_AT_GNU_pubtypes(0x2135),
|
||||
DW_AT_GNU_discriminator(0x2136),
|
||||
DW_AT_BORLAND_property_read(0x3b11),
|
||||
DW_AT_BORLAND_property_write(0x3b12),
|
||||
DW_AT_BORLAND_property_implements(0x3b13),
|
||||
DW_AT_BORLAND_property_index(0x3b14),
|
||||
DW_AT_BORLAND_property_default(0x3b15),
|
||||
DW_AT_BORLAND_Delphi_unit(0x3b20),
|
||||
DW_AT_BORLAND_Delphi_class(0x3b21),
|
||||
DW_AT_BORLAND_Delphi_record(0x3b22),
|
||||
DW_AT_BORLAND_Delphi_metaclass(0x3b23),
|
||||
DW_AT_BORLAND_Delphi_constructor(0x3b24),
|
||||
DW_AT_BORLAND_Delphi_destructor(0x3b25),
|
||||
DW_AT_BORLAND_Delphi_anonymous_method(0x3b26),
|
||||
DW_AT_BORLAND_Delphi_interface(0x3b27),
|
||||
DW_AT_BORLAND_Delphi_ABI(0x3b28),
|
||||
DW_AT_BORLAND_Delphi_return(0x3b29),
|
||||
DW_AT_BORLAND_Delphi_frameptr(0x3b30),
|
||||
DW_AT_BORLAND_closure(0x3b31),
|
||||
DW_AT_LLVM_include_path(0x3e00),
|
||||
DW_AT_LLVM_config_macros(0x3e01),
|
||||
DW_AT_LLVM_isysroot(0x3e02),
|
||||
DW_AT_APPLE_optimized(0x3fe1),
|
||||
DW_AT_APPLE_flags(0x3fe2),
|
||||
DW_AT_APPLE_isa(0x3fe3),
|
||||
DW_AT_APPLE_block(0x3fe4),
|
||||
DW_AT_APPLE_major_runtime_vers(0x3fe5),
|
||||
DW_AT_APPLE_runtime_class(0x3fe6),
|
||||
DW_AT_APPLE_omit_frame_ptr(0x3fe7),
|
||||
DW_AT_APPLE_property_name(0x3fe8),
|
||||
DW_AT_APPLE_property_getter(0x3fe9),
|
||||
DW_AT_APPLE_property_setter(0x3fea),
|
||||
DW_AT_APPLE_property_attribute(0x3feb),
|
||||
DW_AT_APPLE_objc_complete_type(0x3fec),
|
||||
DW_AT_APPLE_property(0x3fed),
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun by(name: String, rawValue: String): DwarfAttribute = by(Attribute.valueOf(name), rawValue)
|
||||
fun by(attribute: Attribute, rawValue: String) = DwarfAttribute(attribute, rawValue)
|
||||
}
|
||||
}
|
||||
|
||||
val DwarfAttribute.rvString: String
|
||||
get() = rawValue.trim().substring(1, rawValue.length - 2)
|
||||
|
||||
|
||||
class DwarfUtilParser() {
|
||||
val tags = mutableListOf<DwarfTag>()
|
||||
var currentTag: DwarfTag? = null
|
||||
var currentAttribute: DwarfAttribute.Attribute? = null
|
||||
val currentAttributePayload = StringBuilder()
|
||||
companion object {
|
||||
val tagRegexp = Regex("^(0x[0-9a-f]{8}):\\ {3}(.*)$")
|
||||
val attributeRegexp = Regex("^\\s+(DW_AT_[a-zA-Z0-9_]*)\\s+\\((.*)\\)$")
|
||||
}
|
||||
|
||||
fun tag(tag: DwarfTag) {
|
||||
appendCurrentAttribute()
|
||||
tags.add(tag)
|
||||
currentTag = tag
|
||||
currentAttribute = null
|
||||
}
|
||||
|
||||
private fun appendCurrentAttribute() {
|
||||
currentTag ?: return
|
||||
with(currentTag!!) {
|
||||
currentAttribute ?: return
|
||||
+DwarfAttribute.by(currentAttribute!!, currentAttributePayload.toString())
|
||||
currentAttributePayload.clear()
|
||||
}
|
||||
}
|
||||
|
||||
fun attribute(attribute: DwarfAttribute.Attribute, payload: String) {
|
||||
appendCurrentAttribute()
|
||||
currentAttribute = attribute
|
||||
currentAttributePayload.appendln(payload)
|
||||
}
|
||||
|
||||
fun parse(reader: Reader): DwarfUtilParser {
|
||||
reader.forEachLine { line ->
|
||||
tagRegexp.find(line)?.apply {
|
||||
val str = this.destructured.component2().trim()
|
||||
if (str == "NULL")
|
||||
return@forEachLine
|
||||
tag(DwarfTag.by(str))
|
||||
return@forEachLine
|
||||
}
|
||||
|
||||
attributeRegexp.find(line)?.apply {
|
||||
attribute(DwarfAttribute.Attribute.valueOf(destructured.component1()), destructured.component2())
|
||||
return@forEachLine
|
||||
}
|
||||
|
||||
currentTag ?: return@forEachLine
|
||||
currentAttributePayload.appendLine(line)
|
||||
}
|
||||
return this
|
||||
}
|
||||
}
|
||||
+42
-1
@@ -78,7 +78,7 @@ fun lldbTest(@Language("kotlin") programText: String, lldbSession: String) {
|
||||
val source = tmpdir.resolve("main.kt")
|
||||
val output = tmpdir.resolve("program.kexe")
|
||||
|
||||
val driver = ToolDriver(DistProperties.konanc, DistProperties.lldb, DistProperties.lldbPrettyPrinters)
|
||||
val driver = ToolDriver(DistProperties.konanc, DistProperties.lldb, DistProperties.dwarfDump, DistProperties.lldbPrettyPrinters)
|
||||
Files.write(source, programText.trimIndent().toByteArray())
|
||||
driver.compile(source, output, "-g")
|
||||
val result = driver.runLldb(output, lldbSessionSpec.commands)
|
||||
@@ -94,6 +94,47 @@ private val isOsxDevToolsEnabled: Boolean by lazy {
|
||||
r.find(rawStatus.stdout)?.destructured?.component1() == "enabled"
|
||||
}
|
||||
|
||||
fun dwarfDumpTest(@Language("kotlin") programText: String, flags: List<String>, test:List<DwarfTag>.()->Unit) {
|
||||
if (!haveDwarfDump) {
|
||||
println("Skipping test: no dwarfdump")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
with(Files.createTempDirectory("dwarfdump_test")) {
|
||||
toFile().deleteOnExit()
|
||||
val source = resolve("main.kt")
|
||||
val output = resolve("program.kexe")
|
||||
|
||||
val driver = ToolDriver(
|
||||
DistProperties.konanc,
|
||||
DistProperties.lldb,
|
||||
DistProperties.dwarfDump,
|
||||
DistProperties.lldbPrettyPrinters)
|
||||
Files.write(source, programText.trimIndent().toByteArray())
|
||||
driver.compile(source, output, "-g", *flags.toTypedArray())
|
||||
driver.runDwarfDump(output, test)
|
||||
}
|
||||
}
|
||||
|
||||
private val haveDwarfDump: Boolean by lazy {
|
||||
val version = try {
|
||||
subprocess(DistProperties.dwarfDump, "--version")
|
||||
.takeIf { it.process.exitValue() == 0 }
|
||||
?.stdout
|
||||
} catch (e: IOException) {
|
||||
null
|
||||
}
|
||||
|
||||
if (version == null) {
|
||||
println("No LLDB found")
|
||||
} else {
|
||||
println("Using $version")
|
||||
}
|
||||
|
||||
version != null
|
||||
}
|
||||
|
||||
private val haveLldb: Boolean by lazy {
|
||||
val lldbVersion = try {
|
||||
subprocess(DistProperties.lldb, "-version")
|
||||
|
||||
Reference in New Issue
Block a user