diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2022-07-27 20:11:54 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2023-02-08 19:04:48 +0000 |
commit | 972a253a57b6f144b0e4a3e2080a2a0076ec55a0 (patch) | |
tree | a8aeeb0997a0a52500f1fa0644244206cf71df94 /contrib/llvm-project/lldb | |
parent | fcaf7f8644a9988098ac6be2165bce3ea4786e91 (diff) | |
parent | 08e8dd7b9db7bb4a9de26d44c1cbfd24e869c014 (diff) |
Diffstat (limited to 'contrib/llvm-project/lldb')
53 files changed, 1276 insertions, 750 deletions
diff --git a/contrib/llvm-project/lldb/include/lldb/Core/Disassembler.h b/contrib/llvm-project/lldb/include/lldb/Core/Disassembler.h index 2cb983c40d19..b9ac0a5bca39 100644 --- a/contrib/llvm-project/lldb/include/lldb/Core/Disassembler.h +++ b/contrib/llvm-project/lldb/include/lldb/Core/Disassembler.h @@ -83,7 +83,10 @@ public: /// The control flow kind of this instruction, or /// eInstructionControlFlowKindUnknown if the instruction /// can't be classified. - lldb::InstructionControlFlowKind GetControlFlowKind(const ArchSpec &arch); + virtual lldb::InstructionControlFlowKind + GetControlFlowKind(const ExecutionContext *exe_ctx) { + return lldb::eInstructionControlFlowKindUnknown; + } virtual void CalculateMnemonicOperandsAndComment(const ExecutionContext *exe_ctx) = 0; @@ -223,6 +226,9 @@ public: virtual bool IsCall() { return false; } + static const char *GetNameForInstructionControlFlowKind( + lldb::InstructionControlFlowKind instruction_control_flow_kind); + protected: Address m_address; // The section offset address of this instruction // We include an address class in the Instruction class to diff --git a/contrib/llvm-project/lldb/include/lldb/Target/MemoryTagManager.h b/contrib/llvm-project/lldb/include/lldb/Target/MemoryTagManager.h index 28a8acc34632..b082224c38ed 100644 --- a/contrib/llvm-project/lldb/include/lldb/Target/MemoryTagManager.h +++ b/contrib/llvm-project/lldb/include/lldb/Target/MemoryTagManager.h @@ -113,6 +113,21 @@ public: UnpackTagsData(const std::vector<uint8_t> &tags, size_t granules = 0) const = 0; + // Unpack tags from a corefile segment containing compressed tags + // (compression that may be different from the one used for GDB transport). + // + // This method asumes that: + // * addr and len have been granule aligned by a tag manager + // * addr >= tag_segment_virtual_address + // + // 'reader' will always be a wrapper around a CoreFile in real use + // but allows testing without having to mock a CoreFile. + typedef std::function<size_t(lldb::offset_t, size_t, void *)> CoreReaderFn; + std::vector<lldb::addr_t> virtual UnpackTagsFromCoreFileSegment( + CoreReaderFn reader, lldb::addr_t tag_segment_virtual_address, + lldb::addr_t tag_segment_data_address, lldb::addr_t addr, + size_t len) const = 0; + // Pack uncompressed tags into their storage format (e.g. for gdb QMemTags). // Checks that each tag is within the expected value range. // We do not check the number of tags or range they apply to because diff --git a/contrib/llvm-project/lldb/include/lldb/Target/Process.h b/contrib/llvm-project/lldb/include/lldb/Target/Process.h index a55659225ef1..505e211e09b6 100644 --- a/contrib/llvm-project/lldb/include/lldb/Target/Process.h +++ b/contrib/llvm-project/lldb/include/lldb/Target/Process.h @@ -1715,8 +1715,8 @@ public: /// an error saying so. /// If it does, either the memory tags or an error describing a /// failure to read or unpack them. - llvm::Expected<std::vector<lldb::addr_t>> ReadMemoryTags(lldb::addr_t addr, - size_t len); + virtual llvm::Expected<std::vector<lldb::addr_t>> + ReadMemoryTags(lldb::addr_t addr, size_t len); /// Write memory tags for a range of memory. /// (calls DoWriteMemoryTags to do the target specific work) diff --git a/contrib/llvm-project/lldb/include/lldb/Target/TraceCursor.h b/contrib/llvm-project/lldb/include/lldb/Target/TraceCursor.h index f6337e3d3d3f..95b022331634 100644 --- a/contrib/llvm-project/lldb/include/lldb/Target/TraceCursor.h +++ b/contrib/llvm-project/lldb/include/lldb/Target/TraceCursor.h @@ -215,7 +215,7 @@ public: /// of this cursor. ExecutionContextRef &GetExecutionContextRef(); - /// Instruction, event or error information + /// Trace item information (instructions, errors and events) /// \{ /// \return @@ -255,27 +255,35 @@ public: /// The load address of the instruction the cursor is pointing at. virtual lldb::addr_t GetLoadAddress() const = 0; - /// Get the hardware counter of a given type associated with the current - /// instruction. Each architecture might support different counters. It might - /// happen that only some instructions of an entire trace have a given counter - /// associated with them. - /// - /// \param[in] counter_type - /// The counter type. - /// \return - /// The value of the counter or \b llvm::None if not available. - virtual llvm::Optional<uint64_t> - GetCounter(lldb::TraceCounter counter_type) const = 0; - /// Get the CPU associated with the current trace item. /// /// This call might not be O(1), so it's suggested to invoke this method - /// whenever a cpu change event is fired. + /// whenever an eTraceEventCPUChanged event is fired. /// /// \return /// The requested CPU id, or \a llvm::None if this information is /// not available for the current item. virtual llvm::Optional<lldb::cpu_id_t> GetCPU() const = 0; + + /// Get the last hardware clock value that was emitted before the current + /// trace item. + /// + /// This call might not be O(1), so it's suggested to invoke this method + /// whenever an eTraceEventHWClockTick event is fired. + /// + /// \return + /// The requested HW clock value, or \a llvm::None if this information is + /// not available for the current item. + virtual llvm::Optional<uint64_t> GetHWClock() const = 0; + + /// Get the approximate wall clock time in nanoseconds at which the current + /// trace item was executed. Each trace plug-in has a different definition for + /// what time 0 means. + /// + /// \return + /// The approximate wall clock time for the trace item, or \a llvm::None + /// if not available. + virtual llvm::Optional<double> GetWallClockTime() const = 0; /// \} protected: diff --git a/contrib/llvm-project/lldb/include/lldb/Target/TraceDumper.h b/contrib/llvm-project/lldb/include/lldb/Target/TraceDumper.h index bbc1a55873d7..ada779990e07 100644 --- a/contrib/llvm-project/lldb/include/lldb/Target/TraceDumper.h +++ b/contrib/llvm-project/lldb/include/lldb/Target/TraceDumper.h @@ -29,9 +29,9 @@ struct TraceDumperOptions { bool json = false; /// When dumping in JSON format, pretty print the output. bool pretty_print_json = false; - /// For each instruction, print the corresponding timestamp counter if + /// For each trace item, print the corresponding timestamp in nanoseconds if /// available. - bool show_tsc = false; + bool show_timestamps = false; /// Dump the events that happened between instructions. bool show_events = false; /// For each instruction, print the instruction kind. @@ -61,7 +61,8 @@ public: struct TraceItem { lldb::user_id_t id; lldb::addr_t load_address; - llvm::Optional<uint64_t> tsc; + llvm::Optional<double> timestamp; + llvm::Optional<uint64_t> hw_clock; llvm::Optional<llvm::StringRef> error; llvm::Optional<lldb::TraceEvent> event; llvm::Optional<SymbolInfo> symbol_info; diff --git a/contrib/llvm-project/lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h b/contrib/llvm-project/lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h index bf9409743a6d..5930cd9970e7 100644 --- a/contrib/llvm-project/lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h +++ b/contrib/llvm-project/lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h @@ -91,8 +91,8 @@ struct LinuxPerfZeroTscConversion { /// nanoseconds) is defined by the kernel at boot time and has no particularly /// useful meaning. On the other hand, this value is constant for an entire /// trace session. - // See 'time_zero' section of - // https://man7.org/linux/man-pages/man2/perf_event_open.2.html + /// See 'time_zero' section of + /// https://man7.org/linux/man-pages/man2/perf_event_open.2.html /// /// \param[in] tsc /// The TSC value to be converted. diff --git a/contrib/llvm-project/lldb/include/lldb/lldb-enumerations.h b/contrib/llvm-project/lldb/include/lldb/lldb-enumerations.h index 83b98c37d122..80046e7e6bee 100644 --- a/contrib/llvm-project/lldb/include/lldb/lldb-enumerations.h +++ b/contrib/llvm-project/lldb/include/lldb/lldb-enumerations.h @@ -1159,12 +1159,6 @@ enum SaveCoreStyle { eSaveCoreStackOnly = 3, }; -// Type of counter values associated with instructions in a trace. -enum TraceCounter { - // Timestamp counter, like the one offered by Intel CPUs (TSC). - eTraceCounterTSC = 0, -}; - /// Events that might happen during a trace session. enum TraceEvent { /// Tracing was disabled for some time due to a software trigger @@ -1174,6 +1168,8 @@ enum TraceEvent { /// Event due to CPU change for a thread. This event is also fired when /// suddenly it's not possible to identify the cpu of a given thread. eTraceEventCPUChanged, + /// Event due to a CPU HW clock tick + eTraceEventHWClockTick, }; // Enum used to identify which kind of item a \a TraceCursor is pointing at diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectDisassemble.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectDisassemble.cpp index a11e2b719727..e65e12fe557a 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectDisassemble.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectDisassemble.cpp @@ -216,8 +216,7 @@ CommandObjectDisassemble::CommandObjectDisassemble( "Disassemble specified instructions in the current target. " "Defaults to the current function for the current thread and " "stack frame.", - "disassemble [<cmd-options>]", eCommandRequiresTarget), - m_options() {} + "disassemble [<cmd-options>]", eCommandRequiresTarget) {} CommandObjectDisassemble::~CommandObjectDisassemble() = default; diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectExpression.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectExpression.cpp index 0fb50420f70f..083309121b66 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectExpression.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectExpression.cpp @@ -187,7 +187,7 @@ CommandObjectExpression::CommandObjectExpression( m_format_options(eFormatDefault), m_repl_option(LLDB_OPT_SET_1, false, "repl", 'r', "Drop into REPL", false, true), - m_command_options(), m_expr_line_count(0) { + m_expr_line_count(0) { SetHelpLong( R"( Single and multi-line expressions: diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectMemory.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectMemory.cpp index ca0384cf9453..5051f9aeec85 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectMemory.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectMemory.cpp @@ -1659,7 +1659,7 @@ class CommandObjectMemoryRegion : public CommandObjectParsed { public: class OptionGroupMemoryRegion : public OptionGroup { public: - OptionGroupMemoryRegion() : OptionGroup(), m_all(false, false) {} + OptionGroupMemoryRegion() : m_all(false, false) {} ~OptionGroupMemoryRegion() override = default; diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectThread.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectThread.cpp index 1371b9dbda1e..fe0cb0945cde 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectThread.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectThread.cpp @@ -2162,7 +2162,7 @@ public: break; } case 't': { - m_dumper_options.show_tsc = true; + m_dumper_options.show_timestamps = true; break; } case 'e': { diff --git a/contrib/llvm-project/lldb/source/Commands/Options.td b/contrib/llvm-project/lldb/source/Commands/Options.td index 78221db18e65..cc47db575306 100644 --- a/contrib/llvm-project/lldb/source/Commands/Options.td +++ b/contrib/llvm-project/lldb/source/Commands/Options.td @@ -1146,15 +1146,17 @@ let Command = "thread trace dump instructions" in { Desc<"Dump in simple JSON format.">; def thread_trace_dump_instructions_pretty_print: Option<"pretty-json", "J">, Group<1>, - Desc<"Dump in JSON format but pretty printing the output for easier readability.">; + Desc<"Dump in JSON format but pretty printing the output for easier " + "readability.">; def thread_trace_dump_instructions_show_kind : Option<"kind", "k">, Group<1>, Desc<"Show instruction control flow kind. Refer to the enum " "`InstructionControlFlowKind` for a list of control flow kind. " "As an important note, far jumps, far calls and far returns often indicate " "calls to and from kernel.">; - def thread_trace_dump_instructions_show_tsc : Option<"tsc", "t">, Group<1>, - Desc<"For each instruction, print the corresponding timestamp counter if " - "available.">; + def thread_trace_dump_instructions_show_timestamps: Option<"time", "t">, + Group<1>, + Desc<"For each trace item, print the corresponding wall clock timestamp " + "if available.">; def thread_trace_dump_instructions_show_events : Option<"events", "e">, Group<1>, Desc<"Dump the events that happened during the execution of the target.">; diff --git a/contrib/llvm-project/lldb/source/Core/Disassembler.cpp b/contrib/llvm-project/lldb/source/Core/Disassembler.cpp index 7a9e214748a7..4c57be44dc9c 100644 --- a/contrib/llvm-project/lldb/source/Core/Disassembler.cpp +++ b/contrib/llvm-project/lldb/source/Core/Disassembler.cpp @@ -571,340 +571,36 @@ Instruction::Instruction(const Address &address, AddressClass addr_class) Instruction::~Instruction() = default; -namespace x86 { - -/// These are the three values deciding instruction control flow kind. -/// InstructionLengthDecode function decodes an instruction and get this struct. -/// -/// primary_opcode -/// Primary opcode of the instruction. -/// For one-byte opcode instruction, it's the first byte after prefix. -/// For two- and three-byte opcodes, it's the second byte. -/// -/// opcode_len -/// The length of opcode in bytes. Valid opcode lengths are 1, 2, or 3. -/// -/// modrm -/// ModR/M byte of the instruction. -/// Bits[7:6] indicate MOD. Bits[5:3] specify a register and R/M bits[2:0] -/// may contain a register or specify an addressing mode, depending on MOD. -struct InstructionOpcodeAndModrm { - uint8_t primary_opcode; - uint8_t opcode_len; - uint8_t modrm; -}; - -/// Determine the InstructionControlFlowKind based on opcode and modrm bytes. -/// Refer to http://ref.x86asm.net/coder.html for the full list of opcode and -/// instruction set. -/// -/// \param[in] opcode_and_modrm -/// Contains primary_opcode byte, its length, and ModR/M byte. -/// Refer to the struct InstructionOpcodeAndModrm for details. -/// -/// \return -/// The control flow kind of the instruction or -/// eInstructionControlFlowKindOther if the instruction doesn't affect -/// the control flow of the program. -lldb::InstructionControlFlowKind -MapOpcodeIntoControlFlowKind(InstructionOpcodeAndModrm opcode_and_modrm) { - uint8_t opcode = opcode_and_modrm.primary_opcode; - uint8_t opcode_len = opcode_and_modrm.opcode_len; - uint8_t modrm = opcode_and_modrm.modrm; - - if (opcode_len > 2) - return lldb::eInstructionControlFlowKindOther; - - if (opcode >= 0x70 && opcode <= 0x7F) { - if (opcode_len == 1) - return lldb::eInstructionControlFlowKindCondJump; - else - return lldb::eInstructionControlFlowKindOther; - } - - if (opcode >= 0x80 && opcode <= 0x8F) { - if (opcode_len == 2) - return lldb::eInstructionControlFlowKindCondJump; - else - return lldb::eInstructionControlFlowKindOther; - } - - switch (opcode) { - case 0x9A: - if (opcode_len == 1) - return lldb::eInstructionControlFlowKindFarCall; - break; - case 0xFF: - if (opcode_len == 1) { - uint8_t modrm_reg = (modrm >> 3) & 7; - if (modrm_reg == 2) - return lldb::eInstructionControlFlowKindCall; - else if (modrm_reg == 3) - return lldb::eInstructionControlFlowKindFarCall; - else if (modrm_reg == 4) - return lldb::eInstructionControlFlowKindJump; - else if (modrm_reg == 5) - return lldb::eInstructionControlFlowKindFarJump; - } - break; - case 0xE8: - if (opcode_len == 1) - return lldb::eInstructionControlFlowKindCall; - break; - case 0xCD: - case 0xCC: - case 0xCE: - case 0xF1: - if (opcode_len == 1) - return lldb::eInstructionControlFlowKindFarCall; - break; - case 0xCF: - if (opcode_len == 1) - return lldb::eInstructionControlFlowKindFarReturn; - break; - case 0xE9: - case 0xEB: - if (opcode_len == 1) - return lldb::eInstructionControlFlowKindJump; - break; - case 0xEA: - if (opcode_len == 1) - return lldb::eInstructionControlFlowKindFarJump; - break; - case 0xE3: - case 0xE0: - case 0xE1: - case 0xE2: - if (opcode_len == 1) - return lldb::eInstructionControlFlowKindCondJump; - break; - case 0xC3: - case 0xC2: - if (opcode_len == 1) - return lldb::eInstructionControlFlowKindReturn; - break; - case 0xCB: - case 0xCA: - if (opcode_len == 1) - return lldb::eInstructionControlFlowKindFarReturn; - break; - case 0x05: - case 0x34: - if (opcode_len == 2) - return lldb::eInstructionControlFlowKindFarCall; - break; - case 0x35: - case 0x07: - if (opcode_len == 2) - return lldb::eInstructionControlFlowKindFarReturn; - break; - case 0x01: - if (opcode_len == 2) { - switch (modrm) { - case 0xc1: - return lldb::eInstructionControlFlowKindFarCall; - case 0xc2: - case 0xc3: - return lldb::eInstructionControlFlowKindFarReturn; - default: - break; - } - } - break; - default: - break; - } - - return lldb::eInstructionControlFlowKindOther; -} - -/// Decode an instruction into opcode, modrm and opcode_len. -/// Refer to http://ref.x86asm.net/coder.html for the instruction bytes layout. -/// Opcodes in x86 are generally the first byte of instruction, though two-byte -/// instructions and prefixes exist. ModR/M is the byte following the opcode -/// and adds additional information for how the instruction is executed. -/// -/// \param[in] inst_bytes -/// Raw bytes of the instruction -/// -/// -/// \param[in] bytes_len -/// The length of the inst_bytes array. -/// -/// \param[in] is_exec_mode_64b -/// If true, the execution mode is 64 bit. -/// -/// \return -/// Returns decoded instruction as struct InstructionOpcodeAndModrm, holding -/// primary_opcode, opcode_len and modrm byte. Refer to the struct definition -/// for more details. -/// Otherwise if the given instruction is invalid, returns None. -llvm::Optional<InstructionOpcodeAndModrm> -InstructionLengthDecode(const uint8_t *inst_bytes, int bytes_len, - bool is_exec_mode_64b) { - int op_idx = 0; - bool prefix_done = false; - InstructionOpcodeAndModrm ret = {0, 0, 0}; - - // In most cases, the primary_opcode is the first byte of the instruction - // but some instructions have a prefix to be skipped for these calculations. - // The following mapping is inspired from libipt's instruction decoding logic - // in `src/pt_ild.c` - while (!prefix_done) { - if (op_idx >= bytes_len) - return llvm::None; - - ret.primary_opcode = inst_bytes[op_idx]; - switch (ret.primary_opcode) { - // prefix_ignore - case 0x26: - case 0x2e: - case 0x36: - case 0x3e: - case 0x64: - case 0x65: - // prefix_osz, prefix_asz - case 0x66: - case 0x67: - // prefix_lock, prefix_f2, prefix_f3 - case 0xf0: - case 0xf2: - case 0xf3: - op_idx++; - break; - - // prefix_rex - case 0x40: - case 0x41: - case 0x42: - case 0x43: - case 0x44: - case 0x45: - case 0x46: - case 0x47: - case 0x48: - case 0x49: - case 0x4a: - case 0x4b: - case 0x4c: - case 0x4d: - case 0x4e: - case 0x4f: - if (is_exec_mode_64b) - op_idx++; - else - prefix_done = true; - break; - - // prefix_vex_c4, c5 - case 0xc5: - if (!is_exec_mode_64b && (inst_bytes[op_idx + 1] & 0xc0) != 0xc0) { - prefix_done = true; - break; - } - - ret.opcode_len = 2; - ret.primary_opcode = inst_bytes[op_idx + 2]; - ret.modrm = inst_bytes[op_idx + 3]; - return ret; - - case 0xc4: - if (!is_exec_mode_64b && (inst_bytes[op_idx + 1] & 0xc0) != 0xc0) { - prefix_done = true; - break; - } - ret.opcode_len = inst_bytes[op_idx + 1] & 0x1f; - ret.primary_opcode = inst_bytes[op_idx + 3]; - ret.modrm = inst_bytes[op_idx + 4]; - return ret; - - // prefix_evex - case 0x62: - if (!is_exec_mode_64b && (inst_bytes[op_idx + 1] & 0xc0) != 0xc0) { - prefix_done = true; - break; - } - ret.opcode_len = inst_bytes[op_idx + 1] & 0x03; - ret.primary_opcode = inst_bytes[op_idx + 4]; - ret.modrm = inst_bytes[op_idx + 5]; - return ret; - - default: - prefix_done = true; - break; - } - } // prefix done - - ret.primary_opcode = inst_bytes[op_idx]; - ret.modrm = inst_bytes[op_idx + 1]; - ret.opcode_len = 1; - - // If the first opcode is 0F, it's two- or three- byte opcodes. - if (ret.primary_opcode == 0x0F) { - ret.primary_opcode = inst_bytes[++op_idx]; // get the next byte - - if (ret.primary_opcode == 0x38) { - ret.opcode_len = 3; - ret.primary_opcode = inst_bytes[++op_idx]; // get the next byte - ret.modrm = inst_bytes[op_idx + 1]; - } else if (ret.primary_opcode == 0x3A) { - ret.opcode_len = 3; - ret.primary_opcode = inst_bytes[++op_idx]; - ret.modrm = inst_bytes[op_idx + 1]; - } else if ((ret.primary_opcode & 0xf8) == 0x38) { - ret.opcode_len = 0; - ret.primary_opcode = inst_bytes[++op_idx]; - ret.modrm = inst_bytes[op_idx + 1]; - } else if (ret.primary_opcode == 0x0F) { - ret.opcode_len = 3; - // opcode is 0x0F, no needs to update - ret.modrm = inst_bytes[op_idx + 1]; - } else { - ret.opcode_len = 2; - ret.modrm = inst_bytes[op_idx + 1]; - } - } - - return ret; -} - -lldb::InstructionControlFlowKind GetControlFlowKind(bool is_exec_mode_64b, - Opcode m_opcode) { - llvm::Optional<InstructionOpcodeAndModrm> ret = llvm::None; - - if (m_opcode.GetOpcodeBytes() == nullptr || m_opcode.GetByteSize() <= 0) { - // x86_64 and i386 instructions are categorized as Opcode::Type::eTypeBytes - return lldb::eInstructionControlFlowKindUnknown; - } - - // Opcode bytes will be decoded into primary_opcode, modrm and opcode length. - // These are the three values deciding instruction control flow kind. - ret = InstructionLengthDecode((const uint8_t *)m_opcode.GetOpcodeBytes(), - m_opcode.GetByteSize(), is_exec_mode_64b); - if (!ret) - return lldb::eInstructionControlFlowKindUnknown; - else - return MapOpcodeIntoControlFlowKind(ret.value()); -} - -} // namespace x86 - -lldb::InstructionControlFlowKind -Instruction::GetControlFlowKind(const ArchSpec &arch) { - if (arch.GetTriple().getArch() == llvm::Triple::x86) - return x86::GetControlFlowKind(/*is_exec_mode_64b=*/false, m_opcode); - else if (arch.GetTriple().getArch() == llvm::Triple::x86_64) - return x86::GetControlFlowKind(/*is_exec_mode_64b=*/true, m_opcode); - else - return eInstructionControlFlowKindUnknown; // not implemented -} - AddressClass Instruction::GetAddressClass() { if (m_address_class == AddressClass::eInvalid) m_address_class = m_address.GetAddressClass(); return m_address_class; } +const char *Instruction::GetNameForInstructionControlFlowKind( + lldb::InstructionControlFlowKind instruction_control_flow_kind) { + switch (instruction_control_flow_kind) { + case eInstructionControlFlowKindUnknown: + return "unknown"; + case eInstructionControlFlowKindOther: + return "other"; + case eInstructionControlFlowKindCall: + return "call"; + case eInstructionControlFlowKindReturn: + return "return"; + case eInstructionControlFlowKindJump: + return "jump"; + case eInstructionControlFlowKindCondJump: + return "cond jump"; + case eInstructionControlFlowKindFarCall: + return "far call"; + case eInstructionControlFlowKindFarReturn: + return "far return"; + case eInstructionControlFlowKindFarJump: + return "far jump"; + } +} + void Instruction::Dump(lldb_private::Stream *s, uint32_t max_opcode_byte_size, bool show_address, bool show_bytes, bool show_control_flow_kind, @@ -946,35 +642,10 @@ void Instruction::Dump(lldb_private::Stream *s, uint32_t max_opcode_byte_size, } if (show_control_flow_kind) { - switch (GetControlFlowKind(exe_ctx->GetTargetRef().GetArchitecture())) { - case eInstructionControlFlowKindUnknown: - ss.Printf("%-12s", "unknown"); - break; - case eInstructionControlFlowKindOther: - ss.Printf("%-12s", "other"); - break; - case eInstructionControlFlowKindCall: - ss.Printf("%-12s", "call"); - break; - case eInstructionControlFlowKindReturn: - ss.Printf("%-12s", "return"); - break; - case eInstructionControlFlowKindJump: - ss.Printf("%-12s", "jump"); - break; - case eInstructionControlFlowKindCondJump: - ss.Printf("%-12s", "cond jump"); - break; - case eInstructionControlFlowKindFarCall: - ss.Printf("%-12s", "far call"); - break; - case eInstructionControlFlowKindFarReturn: - ss.Printf("%-12s", "far return"); - break; - case eInstructionControlFlowKindFarJump: - ss.Printf("%-12s", "far jump"); - break; - } + lldb::InstructionControlFlowKind instruction_control_flow_kind = + GetControlFlowKind(exe_ctx); + ss.Printf("%-12s", GetNameForInstructionControlFlowKind( + instruction_control_flow_kind)); } const size_t opcode_pos = ss.GetSizeOfLastLine(); diff --git a/contrib/llvm-project/lldb/source/Host/common/Host.cpp b/contrib/llvm-project/lldb/source/Host/common/Host.cpp index f35eb47ff683..4a0f0240bd19 100644 --- a/contrib/llvm-project/lldb/source/Host/common/Host.cpp +++ b/contrib/llvm-project/lldb/source/Host/common/Host.cpp @@ -172,7 +172,7 @@ MonitorChildProcessThreadFunction(::pid_t pid, ::sigaction(SIGUSR1, &sigUsr1Action, nullptr); #endif // __linux__ - while(1) { + while (true) { log = GetLog(LLDBLog::Process); LLDB_LOG(log, "::waitpid({0}, &status, 0)...", pid); diff --git a/contrib/llvm-project/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp b/contrib/llvm-project/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp index fb404e985f80..973884283f46 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp @@ -85,6 +85,324 @@ private: std::unique_ptr<llvm::MCInstPrinter> m_instr_printer_up; }; +namespace x86 { + +/// These are the three values deciding instruction control flow kind. +/// InstructionLengthDecode function decodes an instruction and get this struct. +/// +/// primary_opcode +/// Primary opcode of the instruction. +/// For one-byte opcode instruction, it's the first byte after prefix. +/// For two- and three-byte opcodes, it's the second byte. +/// +/// opcode_len +/// The length of opcode in bytes. Valid opcode lengths are 1, 2, or 3. +/// +/// modrm +/// ModR/M byte of the instruction. +/// Bits[7:6] indicate MOD. Bits[5:3] specify a register and R/M bits[2:0] +/// may contain a register or specify an addressing mode, depending on MOD. +struct InstructionOpcodeAndModrm { + uint8_t primary_opcode; + uint8_t opcode_len; + uint8_t modrm; +}; + +/// Determine the InstructionControlFlowKind based on opcode and modrm bytes. +/// Refer to http://ref.x86asm.net/coder.html for the full list of opcode and +/// instruction set. +/// +/// \param[in] opcode_and_modrm +/// Contains primary_opcode byte, its length, and ModR/M byte. +/// Refer to the struct InstructionOpcodeAndModrm for details. +/// +/// \return +/// The control flow kind of the instruction or +/// eInstructionControlFlowKindOther if the instruction doesn't affect +/// the control flow of the program. +lldb::InstructionControlFlowKind +MapOpcodeIntoControlFlowKind(InstructionOpcodeAndModrm opcode_and_modrm) { + uint8_t opcode = opcode_and_modrm.primary_opcode; + uint8_t opcode_len = opcode_and_modrm.opcode_len; + uint8_t modrm = opcode_and_modrm.modrm; + + if (opcode_len > 2) + return lldb::eInstructionControlFlowKindOther; + + if (opcode >= 0x70 && opcode <= 0x7F) { + if (opcode_len == 1) + return lldb::eInstructionControlFlowKindCondJump; + else + return lldb::eInstructionControlFlowKindOther; + } + + if (opcode >= 0x80 && opcode <= 0x8F) { + if (opcode_len == 2) + return lldb::eInstructionControlFlowKindCondJump; + else + return lldb::eInstructionControlFlowKindOther; + } + + switch (opcode) { + case 0x9A: + if (opcode_len == 1) + return lldb::eInstructionControlFlowKindFarCall; + break; + case 0xFF: + if (opcode_len == 1) { + uint8_t modrm_reg = (modrm >> 3) & 7; + if (modrm_reg == 2) + return lldb::eInstructionControlFlowKindCall; + else if (modrm_reg == 3) + return lldb::eInstructionControlFlowKindFarCall; + else if (modrm_reg == 4) + return lldb::eInstructionControlFlowKindJump; + else if (modrm_reg == 5) + return lldb::eInstructionControlFlowKindFarJump; + } + break; + case 0xE8: + if (opcode_len == 1) + return lldb::eInstructionControlFlowKindCall; + break; + case 0xCD: + case 0xCC: + case 0xCE: + case 0xF1: + if (opcode_len == 1) + return lldb::eInstructionControlFlowKindFarCall; + break; + case 0xCF: + if (opcode_len == 1) + return lldb::eInstructionControlFlowKindFarReturn; + break; + case 0xE9: + case 0xEB: + if (opcode_len == 1) + return lldb::eInstructionControlFlowKindJump; + break; + case 0xEA: + if (opcode_len == 1) + return lldb::eInstructionControlFlowKindFarJump; + break; + case 0xE3: + case 0xE0: + case 0xE1: + case 0xE2: + if (opcode_len == 1) + return lldb::eInstructionControlFlowKindCondJump; + break; + case 0xC3: + case 0xC2: + if (opcode_len == 1) + return lldb::eInstructionControlFlowKindReturn; + break; + case 0xCB: + case 0xCA: + if (opcode_len == 1) + return lldb::eInstructionControlFlowKindFarReturn; + break; + case 0x05: + case 0x34: + if (opcode_len == 2) + return lldb::eInstructionControlFlowKindFarCall; + break; + case 0x35: + case 0x07: + if (opcode_len == 2) + return lldb::eInstructionControlFlowKindFarReturn; + break; + case 0x01: + if (opcode_len == 2) { + switch (modrm) { + case 0xc1: + return lldb::eInstructionControlFlowKindFarCall; + case 0xc2: + case 0xc3: + return lldb::eInstructionControlFlowKindFarReturn; + default: + break; + } + } + break; + default: + break; + } + + return lldb::eInstructionControlFlowKindOther; +} + +/// Decode an instruction into opcode, modrm and opcode_len. +/// Refer to http://ref.x86asm.net/coder.html for the instruction bytes layout. +/// Opcodes in x86 are generally the first byte of instruction, though two-byte +/// instructions and prefixes exist. ModR/M is the byte following the opcode +/// and adds additional information for how the instruction is executed. +/// +/// \param[in] inst_bytes +/// Raw bytes of the instruction +/// +/// +/// \param[in] bytes_len +/// The length of the inst_bytes array. +/// +/// \param[in] is_exec_mode_64b +/// If true, the execution mode is 64 bit. +/// +/// \return +/// Returns decoded instruction as struct InstructionOpcodeAndModrm, holding +/// primary_opcode, opcode_len and modrm byte. Refer to the struct definition +/// for more details. +/// Otherwise if the given instruction is invalid, returns None. +llvm::Optional<InstructionOpcodeAndModrm> +InstructionLengthDecode(const uint8_t *inst_bytes, int bytes_len, + bool is_exec_mode_64b) { + int op_idx = 0; + bool prefix_done = false; + InstructionOpcodeAndModrm ret = {0, 0, 0}; + + // In most cases, the primary_opcode is the first byte of the instruction + // but some instructions have a prefix to be skipped for these calculations. + // The following mapping is inspired from libipt's instruction decoding logic + // in `src/pt_ild.c` + while (!prefix_done) { + if (op_idx >= bytes_len) + return llvm::None; + + ret.primary_opcode = inst_bytes[op_idx]; + switch (ret.primary_opcode) { + // prefix_ignore + case 0x26: + case 0x2e: + case 0x36: + case 0x3e: + case 0x64: + case 0x65: + // prefix_osz, prefix_asz + case 0x66: + case 0x67: + // prefix_lock, prefix_f2, prefix_f3 + case 0xf0: + case 0xf2: + case 0xf3: + op_idx++; + break; + + // prefix_rex + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4a: + case 0x4b: + case 0x4c: + case 0x4d: + case 0x4e: + case 0x4f: + if (is_exec_mode_64b) + op_idx++; + else + prefix_done = true; + break; + + // prefix_vex_c4, c5 + case 0xc5: + if (!is_exec_mode_64b && (inst_bytes[op_idx + 1] & 0xc0) != 0xc0) { + prefix_done = true; + break; + } + + ret.opcode_len = 2; + ret.primary_opcode = inst_bytes[op_idx + 2]; + ret.modrm = inst_bytes[op_idx + 3]; + return ret; + + case 0xc4: + if (!is_exec_mode_64b && (inst_bytes[op_idx + 1] & 0xc0) != 0xc0) { + prefix_done = true; + break; + } + ret.opcode_len = inst_bytes[op_idx + 1] & 0x1f; + ret.primary_opcode = inst_bytes[op_idx + 3]; + ret.modrm = inst_bytes[op_idx + 4]; + return ret; + + // prefix_evex + case 0x62: + if (!is_exec_mode_64b && (inst_bytes[op_idx + 1] & 0xc0) != 0xc0) { + prefix_done = true; + break; + } + ret.opcode_len = inst_bytes[op_idx + 1] & 0x03; + ret.primary_opcode = inst_bytes[op_idx + 4]; + ret.modrm = inst_bytes[op_idx + 5]; + return ret; + + default: + prefix_done = true; + break; + } + } // prefix done + + ret.primary_opcode = inst_bytes[op_idx]; + ret.modrm = inst_bytes[op_idx + 1]; + ret.opcode_len = 1; + + // If the first opcode is 0F, it's two- or three- byte opcodes. + if (ret.primary_opcode == 0x0F) { + ret.primary_opcode = inst_bytes[++op_idx]; // get the next byte + + if (ret.primary_opcode == 0x38) { + ret.opcode_len = 3; + ret.primary_opcode = inst_bytes[++op_idx]; // get the next byte + ret.modrm = inst_bytes[op_idx + 1]; + } else if (ret.primary_opcode == 0x3A) { + ret.opcode_len = 3; + ret.primary_opcode = inst_bytes[++op_idx]; + ret.modrm = inst_bytes[op_idx + 1]; + } else if ((ret.primary_opcode & 0xf8) == 0x38) { + ret.opcode_len = 0; + ret.primary_opcode = inst_bytes[++op_idx]; + ret.modrm = inst_bytes[op_idx + 1]; + } else if (ret.primary_opcode == 0x0F) { + ret.opcode_len = 3; + // opcode is 0x0F, no needs to update + ret.modrm = inst_bytes[op_idx + 1]; + } else { + ret.opcode_len = 2; + ret.modrm = inst_bytes[op_idx + 1]; + } + } + + return ret; +} + +lldb::InstructionControlFlowKind GetControlFlowKind(bool is_exec_mode_64b, + Opcode m_opcode) { + llvm::Optional<InstructionOpcodeAndModrm> ret = llvm::None; + + if (m_opcode.GetOpcodeBytes() == nullptr || m_opcode.GetByteSize() <= 0) { + // x86_64 and i386 instructions are categorized as Opcode::Type::eTypeBytes + return lldb::eInstructionControlFlowKindUnknown; + } + + // Opcode bytes will be decoded into primary_opcode, modrm and opcode length. + // These are the three values deciding instruction control flow kind. + ret = InstructionLengthDecode((const uint8_t *)m_opcode.GetOpcodeBytes(), + m_opcode.GetByteSize(), is_exec_mode_64b); + if (!ret) + return lldb::eInstructionControlFlowKindUnknown; + else + return MapOpcodeIntoControlFlowKind(ret.value()); +} + +} // namespace x86 + class InstructionLLVMC : public lldb_private::Instruction { public: InstructionLLVMC(DisassemblerLLVMC &disasm, @@ -223,6 +541,19 @@ public: } } + lldb::InstructionControlFlowKind + GetControlFlowKind(const lldb_private::ExecutionContext *exe_ctx) override { + DisassemblerScope disasm(*this, exe_ctx); + if (disasm){ + if (disasm->GetArchitecture().GetMachine() == llvm::Triple::x86) + return x86::GetControlFlowKind(/*is_64b=*/false, m_opcode); + else if (disasm->GetArchitecture().GetMachine() == llvm::Triple::x86_64) + return x86::GetControlFlowKind(/*is_64b=*/true, m_opcode); + } + + return eInstructionControlFlowKindUnknown; + } + void CalculateMnemonicOperandsAndComment( const lldb_private::ExecutionContext *exe_ctx) override { DataExtractor data; diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp index f8443d608ac3..71242925862b 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp @@ -191,12 +191,12 @@ TagDecl *ClangASTSource::FindCompleteType(const TagDecl *decl) { ClangASTImporter::NamespaceMapSP namespace_map = m_ast_importer_sp->GetNamespaceMap(namespace_context); - LLDB_LOGV(log, " CTD Inspecting namespace map{0} ({1} entries)", - namespace_map.get(), namespace_map->size()); - if (!namespace_map) return nullptr; + LLDB_LOGV(log, " CTD Inspecting namespace map{0} ({1} entries)", + namespace_map.get(), namespace_map->size()); + for (const ClangASTImporter::NamespaceMapItem &item : *namespace_map) { LLDB_LOG(log, " CTD Searching namespace {0} in module {1}", item.second.GetName(), item.first->GetFileSpec().GetFilename()); @@ -1430,9 +1430,7 @@ static bool ImportOffsetMap(llvm::DenseMap<const D *, O> &destination_map, std::vector<PairType> sorted_items; sorted_items.reserve(source_map.size()); sorted_items.assign(source_map.begin(), source_map.end()); - llvm::sort(sorted_items, [](const PairType &lhs, const PairType &rhs) { - return lhs.second < rhs.second; - }); + llvm::sort(sorted_items, llvm::less_second()); for (const auto &item : sorted_items) { DeclFromUser<D> user_decl(const_cast<D *>(item.first)); diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp index fad0f724e4c8..ec3dc28a3a8c 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp @@ -722,8 +722,9 @@ ClangExpressionParser::ClangExpressionParser( m_llvm_context = std::make_unique<LLVMContext>(); m_code_generator.reset(CreateLLVMCodeGen( m_compiler->getDiagnostics(), module_name, - m_compiler->getHeaderSearchOpts(), m_compiler->getPreprocessorOpts(), - m_compiler->getCodeGenOpts(), *m_llvm_context)); + &m_compiler->getVirtualFileSystem(), m_compiler->getHeaderSearchOpts(), + m_compiler->getPreprocessorOpts(), m_compiler->getCodeGenOpts(), + *m_llvm_context)); } ClangExpressionParser::~ClangExpressionParser() = default; diff --git a/contrib/llvm-project/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp b/contrib/llvm-project/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp index 5bc745cf3b8b..b00a17736679 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp @@ -14453,10 +14453,10 @@ bool EmulateInstructionARM::TestEmulation(Stream *out_stream, ArchSpec &arch, return false; } - success = before_state.CompareState(after_state); + success = before_state.CompareState(after_state, out_stream); if (!success) out_stream->Printf( - "TestEmulation: 'before' and 'after' states do not match.\n"); + "TestEmulation: State after emulation does not match 'after' state.\n"); return success; } diff --git a/contrib/llvm-project/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.cpp b/contrib/llvm-project/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.cpp index 569482c7b23b..da679a3e8547 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.cpp @@ -97,7 +97,7 @@ uint64_t EmulationStateARM::ReadPseudoRegisterValue(uint32_t reg_num, uint32_t idx = reg_num - dwarf_d0; if (idx < 16) value = (uint64_t)m_vfp_regs.s_regs[idx * 2] | - ((uint64_t)m_vfp_regs.s_regs[idx * 2 + 1] >> 32); + ((uint64_t)m_vfp_regs.s_regs[idx * 2 + 1] << 32); else value = m_vfp_regs.d_regs[idx - 16]; } else @@ -251,27 +251,67 @@ bool EmulationStateARM::WritePseudoRegister( reg_value.GetAsUInt64()); } -bool EmulationStateARM::CompareState(EmulationStateARM &other_state) { +bool EmulationStateARM::CompareState(EmulationStateARM &other_state, + Stream *out_stream) { bool match = true; for (int i = 0; match && i < 17; ++i) { - if (m_gpr[i] != other_state.m_gpr[i]) + if (m_gpr[i] != other_state.m_gpr[i]) { match = false; + out_stream->Printf("r%d: 0x%x != 0x%x\n", i, m_gpr[i], + other_state.m_gpr[i]); + } } for (int i = 0; match && i < 32; ++i) { - if (m_vfp_regs.s_regs[i] != other_state.m_vfp_regs.s_regs[i]) + if (m_vfp_regs.s_regs[i] != other_state.m_vfp_regs.s_regs[i]) { match = false; + out_stream->Printf("s%d: 0x%x != 0x%x\n", i, m_vfp_regs.s_regs[i], + other_state.m_vfp_regs.s_regs[i]); + } } for (int i = 0; match && i < 16; ++i) { - if (m_vfp_regs.d_regs[i] != other_state.m_vfp_regs.d_regs[i]) + if (m_vfp_regs.d_regs[i] != other_state.m_vfp_regs.d_regs[i]) { match = false; + out_stream->Printf("d%d: 0x%" PRIx64 " != 0x%" PRIx64 "\n", i + 16, + m_vfp_regs.d_regs[i], + other_state.m_vfp_regs.d_regs[i]); + } + } + + // other_state is the expected state. If it has memory, check it. + if (!other_state.m_memory.empty() && m_memory != other_state.m_memory) { + match = false; + out_stream->Printf("memory does not match\n"); + out_stream->Printf("got memory:\n"); + for (auto p : m_memory) + out_stream->Printf("0x%08" PRIx64 ": 0x%08x\n", p.first, p.second); + out_stream->Printf("expected memory:\n"); + for (auto p : other_state.m_memory) + out_stream->Printf("0x%08" PRIx64 ": 0x%08x\n", p.first, p.second); } return match; } +bool EmulationStateARM::LoadRegistersStateFromDictionary( + OptionValueDictionary *reg_dict, char kind, int first_reg, int num) { + StreamString sstr; + for (int i = 0; i < num; ++i) { + sstr.Clear(); + sstr.Printf("%c%d", kind, i); + OptionValueSP value_sp = + reg_dict->GetValueForKey(ConstString(sstr.GetString())); + if (value_sp.get() == nullptr) + return false; + uint64_t reg_value = value_sp->GetUInt64Value(); + StorePseudoRegisterValue(first_reg + i, reg_value); + } + + return true; +} + bool EmulationStateARM::LoadStateFromDictionary( OptionValueDictionary *test_data) { static ConstString memory_key("memory"); @@ -321,18 +361,8 @@ bool EmulationStateARM::LoadStateFromDictionary( // Load General Registers OptionValueDictionary *reg_dict = value_sp->GetAsDictionary(); - - StreamString sstr; - for (int i = 0; i < 16; ++i) { - sstr.Clear(); - sstr.Printf("r%d", i); - ConstString reg_name(sstr.GetString()); - value_sp = reg_dict->GetValueForKey(reg_name); - if (value_sp.get() == nullptr) - return false; - uint64_t reg_value = value_sp->GetUInt64Value(); - StorePseudoRegisterValue(dwarf_r0 + i, reg_value); - } + if (!LoadRegistersStateFromDictionary(reg_dict, 'r', dwarf_r0, 16)) + return false; static ConstString cpsr_name("cpsr"); value_sp = reg_dict->GetValueForKey(cpsr_name); @@ -341,16 +371,13 @@ bool EmulationStateARM::LoadStateFromDictionary( StorePseudoRegisterValue(dwarf_cpsr, value_sp->GetUInt64Value()); // Load s/d Registers - for (int i = 0; i < 32; ++i) { - sstr.Clear(); - sstr.Printf("s%d", i); - ConstString reg_name(sstr.GetString()); - value_sp = reg_dict->GetValueForKey(reg_name); - if (value_sp.get() == nullptr) - return false; - uint64_t reg_value = value_sp->GetUInt64Value(); - StorePseudoRegisterValue(dwarf_s0 + i, reg_value); - } - - return true; + // To prevent you giving both types in a state and overwriting + // one or the other, we'll expect to get either all S registers, + // or all D registers. Not a mix of the two. + bool found_s_registers = + LoadRegistersStateFromDictionary(reg_dict, 's', dwarf_s0, 32); + bool found_d_registers = + LoadRegistersStateFromDictionary(reg_dict, 'd', dwarf_d0, 32); + + return found_s_registers != found_d_registers; } diff --git a/contrib/llvm-project/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.h b/contrib/llvm-project/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.h index 28bc5d98649d..bc885dab9ac7 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.h +++ b/contrib/llvm-project/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.h @@ -36,7 +36,8 @@ public: bool LoadStateFromDictionary(lldb_private::OptionValueDictionary *test_data); - bool CompareState(EmulationStateARM &other_state); + bool CompareState(EmulationStateARM &other_state, + lldb_private::Stream *out_stream); static size_t ReadPseudoMemory(lldb_private::EmulateInstruction *instruction, void *baton, @@ -61,6 +62,10 @@ public: const lldb_private::RegisterValue ®_value); private: + bool LoadRegistersStateFromDictionary( + lldb_private::OptionValueDictionary *reg_dict, char kind, int first_reg, + int num); + uint32_t m_gpr[17] = {0}; struct _sd_regs { uint32_t s_regs[32]; // sregs 0 - 31 & dregs 0 - 15 diff --git a/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp b/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp index acb131b8a775..c396cb061c01 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp @@ -348,7 +348,7 @@ llvm::support::ulittle64_t read_register_u64(RegisterContext *reg_ctx, lldb_private::minidump::MinidumpContext_x86_64 GetThreadContext_64(RegisterContext *reg_ctx) { - lldb_private::minidump::MinidumpContext_x86_64 thread_context; + lldb_private::minidump::MinidumpContext_x86_64 thread_context = {}; thread_context.p1_home = {}; thread_context.context_flags = static_cast<uint32_t>( lldb_private::minidump::MinidumpContext_x86_64_Flags::x86_64_Flag | @@ -534,7 +534,7 @@ Status MinidumpFileBuilder::AddException(const lldb::ProcessSP &process_sp) { helper_data.AppendData( &thread_context, sizeof(lldb_private::minidump::MinidumpContext_x86_64)); - Exception exp_record; + Exception exp_record = {}; exp_record.ExceptionCode = static_cast<llvm::support::ulittle32_t>(stop_info_sp->GetValue()); exp_record.ExceptionFlags = static_cast<llvm::support::ulittle32_t>(0); diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.cpp index b71de4cadb18..7e25bc4ea2a2 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.cpp @@ -247,6 +247,71 @@ MemoryTagManagerAArch64MTE::UnpackTagsData(const std::vector<uint8_t> &tags, return unpacked; } +std::vector<lldb::addr_t> +MemoryTagManagerAArch64MTE::UnpackTagsFromCoreFileSegment( + CoreReaderFn reader, lldb::addr_t tag_segment_virtual_address, + lldb::addr_t tag_segment_data_address, lldb::addr_t addr, + size_t len) const { + // We can assume by now that addr and len have been granule aligned by a tag + // manager. However because we have 2 tags per byte we need to round the range + // up again to align to 2 granule boundaries. + const size_t granule = GetGranuleSize(); + const size_t two_granules = granule * 2; + lldb::addr_t aligned_addr = addr; + size_t aligned_len = len; + + // First align the start address down. + if (aligned_addr % two_granules) { + assert(aligned_addr % two_granules == granule); + aligned_addr -= granule; + aligned_len += granule; + } + + // Then align the length up. + bool aligned_length_up = false; + if (aligned_len % two_granules) { + assert(aligned_len % two_granules == granule); + aligned_len += granule; + aligned_length_up = true; + } + + // ProcessElfCore should have validated this when it found the segment. + assert(aligned_addr >= tag_segment_virtual_address); + + // By now we know that aligned_addr is aligned to a 2 granule boundary. + const size_t offset_granules = + (aligned_addr - tag_segment_virtual_address) / granule; + // 2 tags per byte. + const size_t file_offset_in_bytes = offset_granules / 2; + + // By now we know that aligned_len is at least 2 granules. + const size_t tag_bytes_to_read = aligned_len / granule / 2; + std::vector<uint8_t> tag_data(tag_bytes_to_read); + const size_t bytes_copied = + reader(tag_segment_data_address + file_offset_in_bytes, tag_bytes_to_read, + tag_data.data()); + UNUSED_IF_ASSERT_DISABLED(bytes_copied); + assert(bytes_copied == tag_bytes_to_read); + + std::vector<lldb::addr_t> tags; + tags.reserve(2 * tag_data.size()); + // No need to check the range of the tag value here as each occupies only 4 + // bits. + for (auto tag_byte : tag_data) { + tags.push_back(tag_byte & 0xf); + tags.push_back(tag_byte >> 4); + } + + // If we aligned the address down, don't return the extra first tag. + if (addr != aligned_addr) + tags.erase(tags.begin()); + // If we aligned the length up, don't return the extra last tag. + if (aligned_length_up) + tags.pop_back(); + + return tags; +} + llvm::Expected<std::vector<uint8_t>> MemoryTagManagerAArch64MTE::PackTags( const std::vector<lldb::addr_t> &tags) const { std::vector<uint8_t> packed; diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h index 7cda728b140f..365e176e5b1d 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h @@ -44,6 +44,12 @@ public: UnpackTagsData(const std::vector<uint8_t> &tags, size_t granules = 0) const override; + std::vector<lldb::addr_t> + UnpackTagsFromCoreFileSegment(CoreReaderFn reader, + lldb::addr_t tag_segment_virtual_address, + lldb::addr_t tag_segment_data_address, + lldb::addr_t addr, size_t len) const override; + llvm::Expected<std::vector<uint8_t>> PackTags(const std::vector<lldb::addr_t> &tags) const override; diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp index 11b300bc44fb..691e7db3fc79 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp @@ -95,7 +95,7 @@ static size_t k_num_register_infos = RegisterContextDarwin_arm64::RegisterContextDarwin_arm64( Thread &thread, uint32_t concrete_frame_idx) - : RegisterContext(thread, concrete_frame_idx), gpr(), fpu(), exc() { + : RegisterContext(thread, concrete_frame_idx), gpr(), fpu(), exc(), dbg() { uint32_t i; for (i = 0; i < kNumErrors; i++) { gpr_errs[i] = -1; diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp index 7469e7633e71..89ecc757a68f 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/ThreadMemory.cpp @@ -23,7 +23,8 @@ using namespace lldb_private; ThreadMemory::ThreadMemory(Process &process, tid_t tid, const ValueObjectSP &thread_info_valobj_sp) : Thread(process, tid), m_backing_thread_sp(), - m_thread_info_valobj_sp(thread_info_valobj_sp), m_name(), m_queue() {} + m_thread_info_valobj_sp(thread_info_valobj_sp), m_name(), m_queue(), + m_register_data_addr(LLDB_INVALID_ADDRESS) {} ThreadMemory::ThreadMemory(Process &process, lldb::tid_t tid, llvm::StringRef name, llvm::StringRef queue, diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp index 58b4fe3add1b..24d3c4bd0ba2 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -144,6 +144,18 @@ lldb::addr_t ProcessElfCore::AddAddressRangeFromLoadSegment( return addr; } +lldb::addr_t ProcessElfCore::AddAddressRangeFromMemoryTagSegment( + const elf::ELFProgramHeader &header) { + // If lldb understood multiple kinds of tag segments we would record the type + // of the segment here also. As long as there is only 1 type lldb looks for, + // there is no need. + FileRange file_range(header.p_offset, header.p_filesz); + m_core_tag_ranges.Append( + VMRangeToFileOffset::Entry(header.p_vaddr, header.p_memsz, file_range)); + + return header.p_vaddr; +} + // Process Control Status ProcessElfCore::DoLoadCore() { Status error; @@ -170,9 +182,12 @@ Status ProcessElfCore::DoLoadCore() { bool ranges_are_sorted = true; lldb::addr_t vm_addr = 0; + lldb::addr_t tag_addr = 0; /// Walk through segments and Thread and Address Map information. /// PT_NOTE - Contains Thread and Register information /// PT_LOAD - Contains a contiguous range of Process Address Space + /// PT_AARCH64_MEMTAG_MTE - Contains AArch64 MTE memory tags for a range of + /// Process Address Space. for (const elf::ELFProgramHeader &H : segments) { DataExtractor data = core->GetSegmentData(H); @@ -187,12 +202,18 @@ Status ProcessElfCore::DoLoadCore() { if (vm_addr > last_addr) ranges_are_sorted = false; vm_addr = last_addr; + } else if (H.p_type == llvm::ELF::PT_AARCH64_MEMTAG_MTE) { + lldb::addr_t last_addr = AddAddressRangeFromMemoryTagSegment(H); + if (tag_addr > last_addr) + ranges_are_sorted = false; + tag_addr = last_addr; } } if (!ranges_are_sorted) { m_core_aranges.Sort(); m_core_range_infos.Sort(); + m_core_tag_ranges.Sort(); } // Even if the architecture is set in the target, we need to override it to @@ -310,6 +331,15 @@ Status ProcessElfCore::DoGetMemoryRegionInfo(lldb::addr_t load_addr, ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo); region_info.SetMapped(MemoryRegionInfo::eYes); + + // A region is memory tagged if there is a memory tag segment that covers + // the exact same range. + region_info.SetMemoryTagged(MemoryRegionInfo::eNo); + const VMRangeToFileOffset::Entry *tag_entry = + m_core_tag_ranges.FindEntryStartsAt(permission_entry->GetRangeBase()); + if (tag_entry && + tag_entry->GetRangeEnd() == permission_entry->GetRangeEnd()) + region_info.SetMemoryTagged(MemoryRegionInfo::eYes); } else if (load_addr < permission_entry->GetRangeBase()) { region_info.GetRange().SetRangeBase(load_addr); region_info.GetRange().SetRangeEnd(permission_entry->GetRangeBase()); @@ -317,6 +347,7 @@ Status ProcessElfCore::DoGetMemoryRegionInfo(lldb::addr_t load_addr, region_info.SetWritable(MemoryRegionInfo::eNo); region_info.SetExecutable(MemoryRegionInfo::eNo); region_info.SetMapped(MemoryRegionInfo::eNo); + region_info.SetMemoryTagged(MemoryRegionInfo::eNo); } return Status(); } @@ -327,6 +358,7 @@ Status ProcessElfCore::DoGetMemoryRegionInfo(lldb::addr_t load_addr, region_info.SetWritable(MemoryRegionInfo::eNo); region_info.SetExecutable(MemoryRegionInfo::eNo); region_info.SetMapped(MemoryRegionInfo::eNo); + region_info.SetMemoryTagged(MemoryRegionInfo::eNo); return Status(); } @@ -376,6 +408,38 @@ size_t ProcessElfCore::DoReadMemory(lldb::addr_t addr, void *buf, size_t size, return bytes_copied; } +llvm::Expected<std::vector<lldb::addr_t>> +ProcessElfCore::ReadMemoryTags(lldb::addr_t addr, size_t len) { + ObjectFile *core_objfile = m_core_module_sp->GetObjectFile(); + if (core_objfile == nullptr) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "No core object file."); + + llvm::Expected<const MemoryTagManager *> tag_manager_or_err = + GetMemoryTagManager(); + if (!tag_manager_or_err) + return tag_manager_or_err.takeError(); + + // LLDB only supports AArch64 MTE tag segments so we do not need to worry + // about the segment type here. If you got here then you must have a tag + // manager (meaning you are debugging AArch64) and all the segments in this + // list will have had type PT_AARCH64_MEMTAG_MTE. + const VMRangeToFileOffset::Entry *tag_entry = + m_core_tag_ranges.FindEntryThatContains(addr); + // If we don't have a tag segment or the range asked for extends outside the + // segment. + if (!tag_entry || (addr + len) >= tag_entry->GetRangeEnd()) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "No tag segment that covers this range."); + + const MemoryTagManager *tag_manager = *tag_manager_or_err; + return tag_manager->UnpackTagsFromCoreFileSegment( + [core_objfile](lldb::offset_t offset, size_t length, void *dst) { + return core_objfile->CopyData(offset, length, dst); + }, + tag_entry->GetRangeBase(), tag_entry->data.GetRangeBase(), addr, len); +} + void ProcessElfCore::Clear() { m_thread_list.Clear(); @@ -610,9 +674,9 @@ llvm::Error ProcessElfCore::parseNetBSDNotes(llvm::ArrayRef<CoreNote> notes) { // To be extracted from struct netbsd_elfcore_procinfo // Used to sanity check of the LWPs of the process uint32_t nlwps = 0; - uint32_t signo; // killing signal - uint32_t siglwp; // LWP target of killing signal - uint32_t pr_pid; + uint32_t signo = 0; // killing signal + uint32_t siglwp = 0; // LWP target of killing signal + uint32_t pr_pid = 0; for (const auto ¬e : notes) { llvm::StringRef name = note.info.n_name; @@ -764,7 +828,7 @@ llvm::Error ProcessElfCore::parseNetBSDNotes(llvm::ArrayRef<CoreNote> notes) { } llvm::Error ProcessElfCore::parseOpenBSDNotes(llvm::ArrayRef<CoreNote> notes) { - ThreadData thread_data; + ThreadData thread_data = {}; for (const auto ¬e : notes) { // OpenBSD per-thread information is stored in notes named "OpenBSD@nnn" so // match on the initial part of the string. diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h index fd36e5027816..03c23378e3c1 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h @@ -86,6 +86,11 @@ public: size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size, lldb_private::Status &error) override; + // We do not implement DoReadMemoryTags. Instead all the work is done in + // ReadMemoryTags which avoids having to unpack and repack tags. + llvm::Expected<std::vector<lldb::addr_t>> ReadMemoryTags(lldb::addr_t addr, + size_t len) override; + lldb::addr_t GetImageInfoAddress() override; lldb_private::ArchSpec GetArchitecture(); @@ -105,6 +110,8 @@ protected: DoGetMemoryRegionInfo(lldb::addr_t load_addr, lldb_private::MemoryRegionInfo ®ion_info) override; + bool SupportsMemoryTagging() override { return !m_core_tag_ranges.IsEmpty(); } + private: struct NT_FILE_Entry { lldb::addr_t start; @@ -139,6 +146,9 @@ private: // Permissions for all ranges VMRangeToPermissions m_core_range_infos; + // Memory tag ranges found in the core + VMRangeToFileOffset m_core_tag_ranges; + // NT_FILE entries found from the NOTE segment std::vector<NT_FILE_Entry> m_nt_file_entries; @@ -154,6 +164,10 @@ private: lldb::addr_t AddAddressRangeFromLoadSegment(const elf::ELFProgramHeader &header); + // Parse a contiguous address range from a memory tag segment + lldb::addr_t + AddAddressRangeFromMemoryTagSegment(const elf::ELFProgramHeader &header); + llvm::Expected<std::vector<lldb_private::CoreNote>> parseSegment(const lldb_private::DataExtractor &segment); llvm::Error parseFreeBSDNotes(llvm::ArrayRef<lldb_private::CoreNote> notes); diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index c44ace96dd55..580cdde57d80 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -4265,3 +4265,21 @@ bool GDBRemoteCommunicationClient::UsesNativeSignals() { // check whether it is an old version of lldb-server. return GetThreadSuffixSupported(); } + +llvm::Expected<int> GDBRemoteCommunicationClient::KillProcess(lldb::pid_t pid) { + StringExtractorGDBRemote response; + GDBRemoteCommunication::ScopedTimeout(*this, seconds(3)); + + if (SendPacketAndWaitForResponse("k", response, GetPacketTimeout()) != + PacketResult::Success) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "failed to send k packet"); + + char packet_cmd = response.GetChar(0); + if (packet_cmd == 'W' || packet_cmd == 'X') + return response.GetHexU8(); + + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "unexpected response to k packet: %s", + response.GetStringRef().str().c_str()); +} diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index d367f75cee0e..3d838d6d8074 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -521,6 +521,8 @@ public: bool GetSaveCoreSupported() const; + llvm::Expected<int> KillProcess(lldb::pid_t pid); + protected: LazyBool m_supports_not_sending_acks = eLazyBoolCalculate; LazyBool m_supports_thread_suffix = eLazyBoolCalculate; diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 5f18706f67e5..3e1a6fb6620a 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -2394,7 +2394,6 @@ Status ProcessGDBRemote::DoDetach(bool keep_stopped) { } Status ProcessGDBRemote::DoDestroy() { - Status error; Log *log = GetLog(GDBRLog::Process); LLDB_LOGF(log, "ProcessGDBRemote::DoDestroy()"); @@ -2404,54 +2403,35 @@ Status ProcessGDBRemote::DoDestroy() { if (m_gdb_comm.IsConnected()) { if (m_public_state.GetValue() != eStateAttaching) { - StringExtractorGDBRemote response; - GDBRemoteCommunication::ScopedTimeout(m_gdb_comm, - std::chrono::seconds(3)); - - if (m_gdb_comm.SendPacketAndWaitForResponse("k", response, - GetInterruptTimeout()) == - GDBRemoteCommunication::PacketResult::Success) { - char packet_cmd = response.GetChar(0); + llvm::Expected<int> kill_res = m_gdb_comm.KillProcess(GetID()); - if (packet_cmd == 'W' || packet_cmd == 'X') { + if (kill_res) { + exit_status = kill_res.get(); #if defined(__APPLE__) - // For Native processes on Mac OS X, we launch through the Host - // Platform, then hand the process off to debugserver, which becomes - // the parent process through "PT_ATTACH". Then when we go to kill - // the process on Mac OS X we call ptrace(PT_KILL) to kill it, then - // we call waitpid which returns with no error and the correct - // status. But amusingly enough that doesn't seem to actually reap - // the process, but instead it is left around as a Zombie. Probably - // the kernel is in the process of switching ownership back to lldb - // which was the original parent, and gets confused in the handoff. - // Anyway, so call waitpid here to finally reap it. - PlatformSP platform_sp(GetTarget().GetPlatform()); - if (platform_sp && platform_sp->IsHost()) { - int status; - ::pid_t reap_pid; - reap_pid = waitpid(GetID(), &status, WNOHANG); - LLDB_LOGF(log, "Reaped pid: %d, status: %d.\n", reap_pid, status); - } -#endif - SetLastStopPacket(response); - ClearThreadIDList(); - exit_status = response.GetHexU8(); - } else { - LLDB_LOGF(log, - "ProcessGDBRemote::DoDestroy - got unexpected response " - "to k packet: %s", - response.GetStringRef().data()); - exit_string.assign("got unexpected response to k packet: "); - exit_string.append(std::string(response.GetStringRef())); + // For Native processes on Mac OS X, we launch through the Host + // Platform, then hand the process off to debugserver, which becomes + // the parent process through "PT_ATTACH". Then when we go to kill + // the process on Mac OS X we call ptrace(PT_KILL) to kill it, then + // we call waitpid which returns with no error and the correct + // status. But amusingly enough that doesn't seem to actually reap + // the process, but instead it is left around as a Zombie. Probably + // the kernel is in the process of switching ownership back to lldb + // which was the original parent, and gets confused in the handoff. + // Anyway, so call waitpid here to finally reap it. + PlatformSP platform_sp(GetTarget().GetPlatform()); + if (platform_sp && platform_sp->IsHost()) { + int status; + ::pid_t reap_pid; + reap_pid = waitpid(GetID(), &status, WNOHANG); + LLDB_LOGF(log, "Reaped pid: %d, status: %d.\n", reap_pid, status); } +#endif + ClearThreadIDList(); + exit_string.assign("killed"); } else { - LLDB_LOGF(log, "ProcessGDBRemote::DoDestroy - failed to send k packet"); - exit_string.assign("failed to send the k packet"); + exit_string.assign(llvm::toString(kill_res.takeError())); } } else { - LLDB_LOGF(log, - "ProcessGDBRemote::DoDestroy - killed or interrupted while " - "attaching"); exit_string.assign("killed or interrupted while attaching."); } } else { @@ -2465,7 +2445,7 @@ Status ProcessGDBRemote::DoDestroy() { StopAsyncThread(); KillDebugserverProcess(); - return error; + return Status(); } void ProcessGDBRemote::SetLastStopPacket( diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp index c91c111d8df3..64219e1a960b 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp @@ -233,7 +233,8 @@ ProcessMinidump::ProcessMinidump(lldb::TargetSP target_sp, const FileSpec &core_file, DataBufferSP core_data) : PostMortemProcess(target_sp, listener_sp), m_core_file(core_file), - m_core_data(std::move(core_data)), m_is_wow64(false) {} + m_core_data(std::move(core_data)), m_active_exception(nullptr), + m_is_wow64(false) {} ProcessMinidump::~ProcessMinidump() { Clear(); diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp index 6317b140f7e8..7d730ecdd1f3 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp @@ -475,7 +475,7 @@ llvm::StringRef lldb_private::npdb::DropNameScope(llvm::StringRef name) { } VariableInfo lldb_private::npdb::GetVariableNameInfo(CVSymbol sym) { - VariableInfo result; + VariableInfo result = {}; if (sym.kind() == S_REGREL32) { RegRelativeSym reg(SymbolRecordKind::RegRelativeSym); diff --git a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp index 0859c5a20b7e..02f1d2f24d8c 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp @@ -44,11 +44,65 @@ void IntelPTError::log(llvm::raw_ostream &OS) const { OS << formatv(": {0:x+16}", m_address); } -int64_t DecodedThread::GetItemsCount() const { - return static_cast<int64_t>(m_item_kinds.size()); +bool DecodedThread::TSCRange::InRange(uint64_t item_index) const { + return item_index >= first_item_index && + item_index < first_item_index + items_count; +} + +bool DecodedThread::NanosecondsRange::InRange(uint64_t item_index) const { + return item_index >= first_item_index && + item_index < first_item_index + items_count; +} + +double DecodedThread::NanosecondsRange::GetInterpolatedTime( + uint64_t item_index, uint64_t begin_of_time_nanos, + const LinuxPerfZeroTscConversion &tsc_conversion) const { + uint64_t items_since_last_tsc = item_index - first_item_index; + + auto interpolate = [&](uint64_t next_range_start_ns) { + if (next_range_start_ns == nanos) { + // If the resolution of the conversion formula is bad enough to consider + // these two timestamps as equal, then we just increase the next one by 1 + // for correction + next_range_start_ns++; + } + long double item_duration = + static_cast<long double>(items_count) / (next_range_start_ns - nanos); + return (nanos - begin_of_time_nanos) + items_since_last_tsc * item_duration; + }; + + if (!next_range) { + // If this is the last TSC range, so we have to extrapolate. In this case, + // we assume that each instruction took one TSC, which is what an + // instruction would take if no parallelism is achieved and the frequency + // multiplier is 1. + return interpolate(tsc_conversion.ToNanos(tsc + items_count)); + } + if (items_count < (next_range->tsc - tsc)) { + // If the numbers of items in this range is less than the total TSC duration + // of this range, i.e. each instruction taking longer than 1 TSC, then we + // can assume that something else happened between these TSCs (e.g. a + // context switch, change to kernel, decoding errors, etc). In this case, we + // also assume that each instruction took 1 TSC. A proper way to improve + // this would be to analize the next events in the trace looking for context + // switches or trace disablement events, but for now, as we only want an + // approximation, we keep it simple. We are also guaranteed that the time in + // nanos of the next range is different to the current one, just because of + // the definition of a NanosecondsRange. + return interpolate( + std::min(tsc_conversion.ToNanos(tsc + items_count), next_range->nanos)); + } + + // In this case, each item took less than 1 TSC, so some parallelism was + // achieved, which is an indication that we didn't suffered of any kind of + // interruption. + return interpolate(next_range->nanos); } -lldb::addr_t DecodedThread::GetInstructionLoadAddress(size_t item_index) const { +uint64_t DecodedThread::GetItemsCount() const { return m_item_kinds.size(); } + +lldb::addr_t +DecodedThread::GetInstructionLoadAddress(uint64_t item_index) const { return m_item_data[item_index].load_address; } @@ -58,33 +112,69 @@ DecodedThread::TraceItemStorage & DecodedThread::CreateNewTraceItem(lldb::TraceItemKind kind) { m_item_kinds.push_back(kind); m_item_data.emplace_back(); + if (m_last_tsc) + (*m_last_tsc)->second.items_count++; + if (m_last_nanoseconds) + (*m_last_nanoseconds)->second.items_count++; return m_item_data.back(); } -void DecodedThread::NotifyTsc(uint64_t tsc) { - if (!m_last_tsc || *m_last_tsc != tsc) { - m_timestamps.emplace(m_item_kinds.size(), tsc); - m_last_tsc = tsc; +void DecodedThread::NotifyTsc(TSC tsc) { + if (m_last_tsc && (*m_last_tsc)->second.tsc == tsc) + return; + + m_last_tsc = + m_tscs.emplace(GetItemsCount(), TSCRange{tsc, 0, GetItemsCount()}).first; + + if (m_tsc_conversion) { + uint64_t nanos = m_tsc_conversion->ToNanos(tsc); + if (!m_last_nanoseconds || (*m_last_nanoseconds)->second.nanos != nanos) { + m_last_nanoseconds = + m_nanoseconds + .emplace(GetItemsCount(), NanosecondsRange{nanos, tsc, nullptr, 0, + GetItemsCount()}) + .first; + if (*m_last_nanoseconds != m_nanoseconds.begin()) { + auto prev_range = prev(*m_last_nanoseconds); + prev_range->second.next_range = &(*m_last_nanoseconds)->second; + } + } } + AppendEvent(lldb::eTraceEventHWClockTick); } void DecodedThread::NotifyCPU(lldb::cpu_id_t cpu_id) { if (!m_last_cpu || *m_last_cpu != cpu_id) { - m_cpus.emplace(m_item_kinds.size(), cpu_id); + m_cpus.emplace(GetItemsCount(), cpu_id); m_last_cpu = cpu_id; AppendEvent(lldb::eTraceEventCPUChanged); } } Optional<lldb::cpu_id_t> -DecodedThread::GetCPUByIndex(uint64_t insn_index) const { - // Could possibly optimize the search - auto it = m_cpus.upper_bound(insn_index); +DecodedThread::GetCPUByIndex(uint64_t item_index) const { + auto it = m_cpus.upper_bound(item_index); if (it == m_cpus.begin()) return None; return prev(it)->second; } +Optional<DecodedThread::TSCRange> +DecodedThread::GetTSCRangeByIndex(uint64_t item_index) const { + auto next_it = m_tscs.upper_bound(item_index); + if (next_it == m_tscs.begin()) + return None; + return prev(next_it)->second; +} + +Optional<DecodedThread::NanosecondsRange> +DecodedThread::GetNanosecondsRangeByIndex(uint64_t item_index) { + auto next_it = m_nanoseconds.upper_bound(item_index); + if (next_it == m_nanoseconds.begin()) + return None; + return prev(next_it)->second; +} + void DecodedThread::AppendEvent(lldb::TraceEvent event) { CreateNewTraceItem(lldb::eTraceItemKindEvent).event = event; m_events_stats.RecordEvent(event); @@ -134,90 +224,24 @@ void DecodedThread::EventsStats::RecordEvent(lldb::TraceEvent event) { total_count++; } -Optional<DecodedThread::TscRange> DecodedThread::CalculateTscRange( - size_t insn_index, - const Optional<DecodedThread::TscRange> &hint_range) const { - // We first try to check the given hint range in case we are traversing the - // trace in short jumps. If that fails, then we do the more expensive - // arbitrary lookup. - if (hint_range) { - Optional<TscRange> candidate_range; - if (insn_index < hint_range->GetStartInstructionIndex()) - candidate_range = hint_range->Prev(); - else if (insn_index > hint_range->GetEndInstructionIndex()) - candidate_range = hint_range->Next(); - else - candidate_range = hint_range; - - if (candidate_range && candidate_range->InRange(insn_index)) - return candidate_range; - } - // Now we do a more expensive lookup - auto it = m_timestamps.upper_bound(insn_index); - if (it == m_timestamps.begin()) - return None; - - return TscRange(--it, *this); -} - -lldb::TraceItemKind DecodedThread::GetItemKindByIndex(size_t item_index) const { +lldb::TraceItemKind +DecodedThread::GetItemKindByIndex(uint64_t item_index) const { return static_cast<lldb::TraceItemKind>(m_item_kinds[item_index]); } -const char *DecodedThread::GetErrorByIndex(size_t item_index) const { +const char *DecodedThread::GetErrorByIndex(uint64_t item_index) const { return m_item_data[item_index].error; } -DecodedThread::DecodedThread(ThreadSP thread_sp) : m_thread_sp(thread_sp) {} - -lldb::TraceCursorUP DecodedThread::CreateNewCursor() { - return std::make_unique<TraceCursorIntelPT>(m_thread_sp, shared_from_this()); -} +DecodedThread::DecodedThread( + ThreadSP thread_sp, + const llvm::Optional<LinuxPerfZeroTscConversion> &tsc_conversion) + : m_thread_sp(thread_sp), m_tsc_conversion(tsc_conversion) {} size_t DecodedThread::CalculateApproximateMemoryUsage() const { return sizeof(TraceItemStorage) * m_item_data.size() + sizeof(uint8_t) * m_item_kinds.size() + - (sizeof(size_t) + sizeof(uint64_t)) * m_timestamps.size() + - (sizeof(size_t) + sizeof(lldb::cpu_id_t)) * m_cpus.size(); -} - -DecodedThread::TscRange::TscRange(std::map<size_t, uint64_t>::const_iterator it, - const DecodedThread &decoded_thread) - : m_it(it), m_decoded_thread(&decoded_thread) { - auto next_it = m_it; - ++next_it; - m_end_index = (next_it == m_decoded_thread->m_timestamps.end()) - ? std::numeric_limits<uint64_t>::max() - : next_it->first - 1; -} - -size_t DecodedThread::TscRange::GetTsc() const { return m_it->second; } - -size_t DecodedThread::TscRange::GetStartInstructionIndex() const { - return m_it->first; -} - -size_t DecodedThread::TscRange::GetEndInstructionIndex() const { - return m_end_index; -} - -bool DecodedThread::TscRange::InRange(size_t insn_index) const { - return GetStartInstructionIndex() <= insn_index && - insn_index <= GetEndInstructionIndex(); -} - -Optional<DecodedThread::TscRange> DecodedThread::TscRange::Next() const { - auto next_it = m_it; - ++next_it; - if (next_it == m_decoded_thread->m_timestamps.end()) - return None; - return TscRange(next_it, *m_decoded_thread); -} - -Optional<DecodedThread::TscRange> DecodedThread::TscRange::Prev() const { - if (m_it == m_decoded_thread->m_timestamps.begin()) - return None; - auto prev_it = m_it; - --prev_it; - return TscRange(prev_it, *m_decoded_thread); + (sizeof(uint64_t) + sizeof(TSC)) * m_tscs.size() + + (sizeof(uint64_t) + sizeof(uint64_t)) * m_nanoseconds.size() + + (sizeof(uint64_t) + sizeof(lldb::cpu_id_t)) * m_cpus.size(); } diff --git a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h index bd1a90aaf250..9376a0af169d 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h +++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h @@ -71,45 +71,7 @@ private: /// stopped at. See \a Trace::GetCursorPosition for more information. class DecodedThread : public std::enable_shared_from_this<DecodedThread> { public: - /// \class TscRange - /// Class that represents the trace range associated with a given TSC. - /// It provides efficient iteration to the previous or next TSC range in the - /// decoded trace. - /// - /// TSC timestamps are emitted by the decoder infrequently, which means - /// that each TSC covers a range of instruction indices, which can be used to - /// speed up TSC lookups. - class TscRange { - public: - /// Check if this TSC range includes the given instruction index. - bool InRange(size_t insn_index) const; - - /// Get the next range chronologically. - llvm::Optional<TscRange> Next() const; - - /// Get the previous range chronologically. - llvm::Optional<TscRange> Prev() const; - - /// Get the TSC value. - size_t GetTsc() const; - /// Get the smallest instruction index that has this TSC. - size_t GetStartInstructionIndex() const; - /// Get the largest instruction index that has this TSC. - size_t GetEndInstructionIndex() const; - - private: - friend class DecodedThread; - - TscRange(std::map<size_t, uint64_t>::const_iterator it, - const DecodedThread &decoded_thread); - - /// The iterator pointing to the beginning of the range. - std::map<size_t, uint64_t>::const_iterator m_it; - /// The largest instruction index that has this TSC. - size_t m_end_index; - - const DecodedThread *m_decoded_thread; - }; + using TSC = uint64_t; // Struct holding counts for libipts errors; struct LibiptErrorsStats { @@ -120,6 +82,61 @@ public: void RecordError(int libipt_error_code); }; + /// A structure that represents a maximal range of trace items associated to + /// the same TSC value. + struct TSCRange { + TSC tsc; + /// Number of trace items in this range. + uint64_t items_count; + /// Index of the first trace item in this range. + uint64_t first_item_index; + + /// \return + /// \b true if and only if the given \p item_index is covered by this + /// range. + bool InRange(uint64_t item_index) const; + }; + + /// A structure that represents a maximal range of trace items associated to + /// the same non-interpolated timestamps in nanoseconds. + struct NanosecondsRange { + /// The nanoseconds value for this range. + uint64_t nanos; + /// The corresponding TSC value for this range. + TSC tsc; + /// A nullable pointer to the next range. + NanosecondsRange *next_range; + /// Number of trace items in this range. + uint64_t items_count; + /// Index of the first trace item in this range. + uint64_t first_item_index; + + /// Calculate an interpolated timestamp in nanoseconds for the given item + /// index. It's guaranteed that two different item indices will produce + /// different interpolated values. + /// + /// \param[in] item_index + /// The index of the item whose timestamp will be estimated. It has to be + /// part of this range. + /// + /// \param[in] beginning_of_time_nanos + /// The timestamp at which tracing started. + /// + /// \param[in] tsc_conversion + /// The tsc -> nanos conversion utility + /// + /// \return + /// An interpolated timestamp value for the given trace item. + double + GetInterpolatedTime(uint64_t item_index, uint64_t beginning_of_time_nanos, + const LinuxPerfZeroTscConversion &tsc_conversion) const; + + /// \return + /// \b true if and only if the given \p item_index is covered by this + /// range. + bool InRange(uint64_t item_index) const; + }; + // Struct holding counts for events; struct EventsStats { /// A count for each individual event kind. We use an unordered map instead @@ -130,39 +147,21 @@ public: void RecordEvent(lldb::TraceEvent event); }; - DecodedThread(lldb::ThreadSP thread_sp); - - /// Utility constructor that initializes the trace with a provided error. - DecodedThread(lldb::ThreadSP thread_sp, llvm::Error &&err); + DecodedThread( + lldb::ThreadSP thread_sp, + const llvm::Optional<LinuxPerfZeroTscConversion> &tsc_conversion); /// Get the total number of instruction, errors and events from the decoded /// trace. - int64_t GetItemsCount() const; - - /// Construct the TSC range that covers the given instruction index. - /// This operation is O(logn) and should be used sparingly. - /// If the trace was collected with TSC support, all the instructions of - /// the trace will have associated TSCs. This means that this method will - /// only return \b llvm::None if there are no TSCs whatsoever in the trace. - /// - /// \param[in] insn_index - /// The instruction index in question. - /// - /// \param[in] hint_range - /// An optional range that might include the given index or might be a - /// neighbor of it. It might help speed it traversals of the trace with - /// short jumps. - llvm::Optional<TscRange> CalculateTscRange( - size_t insn_index, - const llvm::Optional<DecodedThread::TscRange> &hint_range) const; + uint64_t GetItemsCount() const; /// \return /// The error associated with a given trace item. - const char *GetErrorByIndex(size_t item_index) const; + const char *GetErrorByIndex(uint64_t item_index) const; /// \return /// The trace item kind given an item index. - lldb::TraceItemKind GetItemKindByIndex(size_t item_index) const; + lldb::TraceItemKind GetItemKindByIndex(uint64_t item_index) const; /// \return /// The underlying event type for the given trace item index. @@ -177,12 +176,31 @@ public: /// The requested cpu id, or \a llvm::None if not available. llvm::Optional<lldb::cpu_id_t> GetCPUByIndex(uint64_t item_index) const; + /// Get a maximal range of trace items that include the given \p item_index + /// that have the same TSC value. + /// + /// \param[in] item_index + /// The trace item index to compare with. + /// + /// \return + /// The requested TSC range, or \a llvm::None if not available. + llvm::Optional<DecodedThread::TSCRange> + GetTSCRangeByIndex(uint64_t item_index) const; + + /// Get a maximal range of trace items that include the given \p item_index + /// that have the same nanoseconds timestamp without interpolation. + /// + /// \param[in] item_index + /// The trace item index to compare with. + /// + /// \return + /// The requested nanoseconds range, or \a llvm::None if not available. + llvm::Optional<DecodedThread::NanosecondsRange> + GetNanosecondsRangeByIndex(uint64_t item_index); + /// \return /// The load address of the instruction at the given index. - lldb::addr_t GetInstructionLoadAddress(size_t item_index) const; - - /// Get a new cursor for the decoded thread. - lldb::TraceCursorUP CreateNewCursor(); + lldb::addr_t GetInstructionLoadAddress(uint64_t item_index) const; /// Return an object with statistics of the TSC decoding errors that happened. /// A TSC error is not a fatal error and doesn't create gaps in the trace. @@ -214,7 +232,7 @@ public: /// Notify this object that a new tsc has been seen. /// If this a new TSC, an event will be created. - void NotifyTsc(uint64_t tsc); + void NotifyTsc(TSC tsc); /// Notify this object that a CPU has been seen. /// If this a new CPU, an event will be created. @@ -262,15 +280,22 @@ private: /// it in TraceItemStorage to avoid padding. std::vector<uint8_t> m_item_kinds; - /// This map contains the TSCs of the decoded instructions. It maps - /// `instruction index -> TSC`, where `instruction index` is the first index - /// at which the mapped TSC appears. We use this representation because TSCs - /// are sporadic and we can think of them as ranges. If TSCs are present in - /// the trace, all instructions will have an associated TSC, including the - /// first one. Otherwise, this map will be empty. - std::map<uint64_t, uint64_t> m_timestamps; + /// This map contains the TSCs of the decoded trace items. It maps + /// `item index -> TSC`, where `item index` is the first index + /// at which the mapped TSC first appears. We use this representation because + /// TSCs are sporadic and we can think of them as ranges. + std::map<uint64_t, TSCRange> m_tscs; /// This is the chronologically last TSC that has been added. - llvm::Optional<uint64_t> m_last_tsc = llvm::None; + llvm::Optional<std::map<uint64_t, TSCRange>::iterator> m_last_tsc = + llvm::None; + /// This map contains the non-interpolated nanoseconds timestamps of the + /// decoded trace items. It maps `item index -> nanoseconds`, where `item + /// index` is the first index at which the mapped nanoseconds first appears. + /// We use this representation because timestamps are sporadic and we think of + /// them as ranges. + std::map<uint64_t, NanosecondsRange> m_nanoseconds; + llvm::Optional<std::map<uint64_t, NanosecondsRange>::iterator> + m_last_nanoseconds = llvm::None; // The cpu information is stored as a map. It maps `instruction index -> CPU` // A CPU is associated with the next instructions that follow until the next @@ -279,6 +304,9 @@ private: /// This is the chronologically last CPU ID. llvm::Optional<uint64_t> m_last_cpu = llvm::None; + /// TSC -> nanos conversion utility. + llvm::Optional<LinuxPerfZeroTscConversion> m_tsc_conversion; + /// Statistics of all tracing events. EventsStats m_events_stats; /// Statistics of libipt errors when decoding TSCs. diff --git a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.cpp b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.cpp index a98337a4e058..234b9f917d32 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.cpp @@ -285,9 +285,23 @@ Error lldb_private::trace_intel_pt::DecodeSystemWideTraceForThread( for (size_t i = 0; i < executions.size(); i++) { const IntelPTThreadContinousExecution &execution = executions[i]; - decoded_thread.NotifyCPU(execution.thread_execution.cpu_id); auto variant = execution.thread_execution.variant; + // We report the TSCs we are sure of + switch (variant) { + case ThreadContinuousExecution::Variant::Complete: + decoded_thread.NotifyTsc(execution.thread_execution.tscs.complete.start); + break; + case ThreadContinuousExecution::Variant::OnlyStart: + decoded_thread.NotifyTsc( + execution.thread_execution.tscs.only_start.start); + break; + default: + break; + } + + decoded_thread.NotifyCPU(execution.thread_execution.cpu_id); + // If we haven't seen a PSB yet, then it's fine not to show errors if (has_seen_psbs) { if (execution.intelpt_subtraces.empty()) { @@ -299,12 +313,12 @@ Error lldb_private::trace_intel_pt::DecodeSystemWideTraceForThread( } // If the first execution is incomplete because it doesn't have a previous - // context switch in its cpu, all good. + // context switch in its cpu, all good, otherwise we report the error. if (variant == ThreadContinuousExecution::Variant::OnlyEnd || variant == ThreadContinuousExecution::Variant::HintedStart) { decoded_thread.AppendCustomError( - formatv("Thread execution starting on cpu id = {0} doesn't " - "have a matching context switch in.", + formatv("Unable to find the context switch in for the thread " + "execution starting on cpu id = {0}", execution.thread_execution.cpu_id) .str()); } @@ -318,6 +332,18 @@ Error lldb_private::trace_intel_pt::DecodeSystemWideTraceForThread( decoder.DecodePSB(intel_pt_execution.psb_offset); } + // We report the TSCs we are sure of + switch (variant) { + case ThreadContinuousExecution::Variant::Complete: + decoded_thread.NotifyTsc(execution.thread_execution.tscs.complete.end); + break; + case ThreadContinuousExecution::Variant::OnlyEnd: + decoded_thread.NotifyTsc(execution.thread_execution.tscs.only_end.end); + break; + default: + break; + } + // If we haven't seen a PSB yet, then it's fine not to show errors if (has_seen_psbs) { // If the last execution is incomplete because it doesn't have a following @@ -326,8 +352,8 @@ Error lldb_private::trace_intel_pt::DecodeSystemWideTraceForThread( i + 1 != executions.size()) || variant == ThreadContinuousExecution::Variant::HintedEnd) { decoded_thread.AppendCustomError( - formatv("Thread execution on cpu id = {0} doesn't have a " - "matching context switch out", + formatv("Unable to find the context switch out for the thread " + "execution on cpu id = {0}", execution.thread_execution.cpu_id) .str()); } @@ -380,3 +406,22 @@ lldb_private::trace_intel_pt::SplitTraceInContinuousExecutions( } return executions; } + +Expected<Optional<uint64_t>> +lldb_private::trace_intel_pt::FindLowestTSCInTrace(TraceIntelPT &trace_intel_pt, + ArrayRef<uint8_t> buffer) { + Expected<PtInsnDecoderUP> decoder_up = + CreateInstructionDecoder(trace_intel_pt, buffer); + if (!decoder_up) + return decoder_up.takeError(); + + pt_insn_decoder *decoder = decoder_up.get().get(); + int status = pte_ok; + if (IsLibiptError(status = pt_insn_sync_forward(decoder))) + return None; + + uint64_t tsc; + if (IsLibiptError(pt_insn_time(decoder, &tsc, nullptr, nullptr))) + return None; + return tsc; +} diff --git a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.h b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.h index cad4d39fcf24..66f3798cd600 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.h +++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.h @@ -94,6 +94,16 @@ llvm::Expected<std::vector<IntelPTThreadSubtrace>> SplitTraceInContinuousExecutions(TraceIntelPT &trace_intel_pt, llvm::ArrayRef<uint8_t> buffer); +/// Find the lowest TSC in the given trace. +/// +/// \return +/// The lowest TSC value in this trace if available, \a llvm::None if the +/// trace is empty or the trace contains no timing information, or an \a +/// llvm::Error if it was not possible to set up the decoder. +llvm::Expected<llvm::Optional<uint64_t>> +FindLowestTSCInTrace(TraceIntelPT &trace_intel_pt, + llvm::ArrayRef<uint8_t> buffer); + } // namespace trace_intel_pt } // namespace lldb_private diff --git a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.cpp b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.cpp index d3ac61f7e658..920992d9d636 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.cpp @@ -23,6 +23,21 @@ using namespace llvm; ThreadDecoder::ThreadDecoder(const ThreadSP &thread_sp, TraceIntelPT &trace) : m_thread_sp(thread_sp), m_trace(trace) {} +Expected<Optional<uint64_t>> ThreadDecoder::FindLowestTSC() { + Optional<uint64_t> lowest_tsc; + Error err = m_trace.OnThreadBufferRead( + m_thread_sp->GetID(), [&](llvm::ArrayRef<uint8_t> data) -> llvm::Error { + Expected<Optional<uint64_t>> tsc = FindLowestTSCInTrace(m_trace, data); + if (!tsc) + return tsc.takeError(); + lowest_tsc = *tsc; + return Error::success(); + }); + if (err) + return std::move(err); + return lowest_tsc; +} + Expected<DecodedThreadSP> ThreadDecoder::Decode() { if (!m_decoded_thread.hasValue()) { if (Expected<DecodedThreadSP> decoded_thread = DoDecode()) { @@ -38,8 +53,8 @@ llvm::Expected<DecodedThreadSP> ThreadDecoder::DoDecode() { return m_trace.GetThreadTimer(m_thread_sp->GetID()) .TimeTask( "Decoding instructions", [&]() -> Expected<DecodedThreadSP> { - DecodedThreadSP decoded_thread_sp = - std::make_shared<DecodedThread>(m_thread_sp); + DecodedThreadSP decoded_thread_sp = std::make_shared<DecodedThread>( + m_thread_sp, m_trace.GetPerfZeroTscConversion()); Error err = m_trace.OnThreadBufferRead( m_thread_sp->GetID(), [&](llvm::ArrayRef<uint8_t> data) { diff --git a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.h b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.h index 5c77ad93d27a..d580bc4dd335 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.h +++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.h @@ -36,6 +36,12 @@ public: /// A \a DecodedThread instance. llvm::Expected<DecodedThreadSP> Decode(); + /// \return + /// The lowest TSC value in this trace if available, \a llvm::None if the + /// trace is empty or the trace contains no timing information, or an \a + /// llvm::Error if it was not possible to set up the decoder. + llvm::Expected<llvm::Optional<uint64_t>> FindLowestTSC(); + ThreadDecoder(const ThreadDecoder &other) = delete; ThreadDecoder &operator=(const ThreadDecoder &other) = delete; diff --git a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp index 185c02b6bcd9..a4d86fb48ebe 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp @@ -17,28 +17,55 @@ using namespace lldb_private; using namespace lldb_private::trace_intel_pt; using namespace llvm; -TraceCursorIntelPT::TraceCursorIntelPT(ThreadSP thread_sp, - DecodedThreadSP decoded_thread_sp) - : TraceCursor(thread_sp), m_decoded_thread_sp(decoded_thread_sp) { +TraceCursorIntelPT::TraceCursorIntelPT( + ThreadSP thread_sp, DecodedThreadSP decoded_thread_sp, + const Optional<LinuxPerfZeroTscConversion> &tsc_conversion, + Optional<uint64_t> beginning_of_time_nanos) + : TraceCursor(thread_sp), m_decoded_thread_sp(decoded_thread_sp), + m_tsc_conversion(tsc_conversion), + m_beginning_of_time_nanos(beginning_of_time_nanos) { Seek(0, SeekType::End); } -void TraceCursorIntelPT::CalculateTscRange() { - // If we failed, then we look for the exact range - if (!m_tsc_range || !m_tsc_range->InRange(m_pos)) - m_tsc_range = m_decoded_thread_sp->CalculateTscRange( - m_pos, /*hit_range=*/m_tsc_range); -} - void TraceCursorIntelPT::Next() { m_pos += IsForwards() ? 1 : -1; + ClearTimingRangesIfInvalid(); +} + +void TraceCursorIntelPT::ClearTimingRangesIfInvalid() { + if (m_tsc_range_calculated) { + if (!m_tsc_range || m_pos < 0 || !m_tsc_range->InRange(m_pos)) { + m_tsc_range = None; + m_tsc_range_calculated = false; + } + } + + if (m_nanoseconds_range_calculated) { + if (!m_nanoseconds_range || m_pos < 0 || + !m_nanoseconds_range->InRange(m_pos)) { + m_nanoseconds_range = None; + m_nanoseconds_range_calculated = false; + } + } +} - // We try to go to a neighbor tsc range that might contain the current pos - if (m_tsc_range && !m_tsc_range->InRange(m_pos)) - m_tsc_range = IsForwards() ? m_tsc_range->Next() : m_tsc_range->Prev(); +const Optional<DecodedThread::TSCRange> & +TraceCursorIntelPT::GetTSCRange() const { + if (!m_tsc_range_calculated) { + m_tsc_range_calculated = true; + m_tsc_range = m_decoded_thread_sp->GetTSCRangeByIndex(m_pos); + } + return m_tsc_range; +} - // If we failed, this call will fix it - CalculateTscRange(); +const Optional<DecodedThread::NanosecondsRange> & +TraceCursorIntelPT::GetNanosecondsRange() const { + if (!m_nanoseconds_range_calculated) { + m_nanoseconds_range_calculated = true; + m_nanoseconds_range = + m_decoded_thread_sp->GetNanosecondsRangeByIndex(m_pos); + } + return m_nanoseconds_range; } bool TraceCursorIntelPT::Seek(int64_t offset, SeekType origin) { @@ -52,13 +79,15 @@ bool TraceCursorIntelPT::Seek(int64_t offset, SeekType origin) { case TraceCursor::SeekType::Current: m_pos += offset; } - CalculateTscRange(); + + ClearTimingRangesIfInvalid(); return HasValue(); } bool TraceCursorIntelPT::HasValue() const { - return m_pos >= 0 && m_pos < m_decoded_thread_sp->GetItemsCount(); + return m_pos >= 0 && + static_cast<uint64_t>(m_pos) < m_decoded_thread_sp->GetItemsCount(); } lldb::TraceItemKind TraceCursorIntelPT::GetItemKind() const { @@ -73,15 +102,18 @@ lldb::addr_t TraceCursorIntelPT::GetLoadAddress() const { return m_decoded_thread_sp->GetInstructionLoadAddress(m_pos); } -Optional<uint64_t> -TraceCursorIntelPT::GetCounter(lldb::TraceCounter counter_type) const { - switch (counter_type) { - case lldb::eTraceCounterTSC: - if (m_tsc_range) - return m_tsc_range->GetTsc(); - else - return llvm::None; - } +Optional<uint64_t> TraceCursorIntelPT::GetHWClock() const { + if (const Optional<DecodedThread::TSCRange> &range = GetTSCRange()) + return range->tsc; + return None; +} + +Optional<double> TraceCursorIntelPT::GetWallClockTime() const { + if (const Optional<DecodedThread::NanosecondsRange> &range = + GetNanosecondsRange()) + return range->GetInterpolatedTime(m_pos, *m_beginning_of_time_nanos, + *m_tsc_conversion); + return None; } Optional<lldb::cpu_id_t> TraceCursorIntelPT::GetCPU() const { @@ -96,13 +128,12 @@ bool TraceCursorIntelPT::GoToId(user_id_t id) { if (!HasId(id)) return false; m_pos = id; - m_tsc_range = m_decoded_thread_sp->CalculateTscRange(m_pos, m_tsc_range); - + ClearTimingRangesIfInvalid(); return true; } bool TraceCursorIntelPT::HasId(lldb::user_id_t id) const { - return static_cast<int64_t>(id) < m_decoded_thread_sp->GetItemsCount(); + return id < m_decoded_thread_sp->GetItemsCount(); } user_id_t TraceCursorIntelPT::GetId() const { return m_pos; } diff --git a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.h b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.h index 2e0f67e67dfc..3cd9ab831f5e 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.h +++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.h @@ -16,8 +16,10 @@ namespace trace_intel_pt { class TraceCursorIntelPT : public TraceCursor { public: - TraceCursorIntelPT(lldb::ThreadSP thread_sp, - DecodedThreadSP decoded_thread_sp); + TraceCursorIntelPT( + lldb::ThreadSP thread_sp, DecodedThreadSP decoded_thread_sp, + const llvm::Optional<LinuxPerfZeroTscConversion> &tsc_conversion, + llvm::Optional<uint64_t> beginning_of_time_nanos); bool Seek(int64_t offset, SeekType origin) override; @@ -29,13 +31,12 @@ public: lldb::addr_t GetLoadAddress() const override; - llvm::Optional<uint64_t> - GetCounter(lldb::TraceCounter counter_type) const override; - lldb::TraceEvent GetEventType() const override; llvm::Optional<lldb::cpu_id_t> GetCPU() const override; + llvm::Optional<uint64_t> GetHWClock() const override; + lldb::TraceItemKind GetItemKind() const override; bool GoToId(lldb::user_id_t id) override; @@ -44,16 +45,43 @@ public: bool HasId(lldb::user_id_t id) const override; + llvm::Optional<double> GetWallClockTime() const override; + private: - /// Calculate the tsc range for the current position if needed. - void CalculateTscRange(); + /// Clear the current TSC and nanoseconds ranges if after moving they are not + /// valid anymore. + void ClearTimingRangesIfInvalid(); + + /// Get or calculate the TSC range that includes the current trace item. + const llvm::Optional<DecodedThread::TSCRange> &GetTSCRange() const; + + /// Get or calculate the TSC range that includes the current trace item. + const llvm::Optional<DecodedThread::NanosecondsRange> & + GetNanosecondsRange() const; /// Storage of the actual instructions DecodedThreadSP m_decoded_thread_sp; /// Internal instruction index currently pointing at. int64_t m_pos; - /// Tsc range covering the current instruction. - llvm::Optional<DecodedThread::TscRange> m_tsc_range; + + /// Timing information and cached values. + /// \{ + + /// TSC -> nanos conversion utility. \a None if not available at all. + llvm::Optional<LinuxPerfZeroTscConversion> m_tsc_conversion; + /// Lowest nanoseconds timestamp seen in any thread trace, \a None if not + /// available at all. + llvm::Optional<uint64_t> m_beginning_of_time_nanos; + /// Range of trace items with the same TSC that includes the current trace + /// item, \a None if not calculated or not available. + llvm::Optional<DecodedThread::TSCRange> mutable m_tsc_range; + bool mutable m_tsc_range_calculated = false; + /// Range of trace items with the same non-interpolated timestamps in + /// nanoseconds that includes the current trace item, \a None if not + /// calculated or not available. + llvm::Optional<DecodedThread::NanosecondsRange> mutable m_nanoseconds_range; + bool mutable m_nanoseconds_range_calculated = false; + /// \} }; } // namespace trace_intel_pt diff --git a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp index 57433ffb14cb..f3f0a513e3fa 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp @@ -8,6 +8,8 @@ #include "TraceIntelPT.h" +#include "TraceCursorIntelPT.h" + #include "../common/ThreadPostMortemTrace.h" #include "CommandObjectTraceStartIntelPT.h" #include "DecodedThread.h" @@ -138,11 +140,53 @@ Expected<DecodedThreadSP> TraceIntelPT::Decode(Thread &thread) { return it->second->Decode(); } +Expected<Optional<uint64_t>> TraceIntelPT::FindBeginningOfTimeNanos() { + Storage &storage = GetUpdatedStorage(); + if (storage.beginning_of_time_nanos_calculated) + return storage.beginning_of_time_nanos; + storage.beginning_of_time_nanos_calculated = true; + + if (!storage.tsc_conversion) + return None; + + Optional<uint64_t> lowest_tsc; + + if (storage.multicpu_decoder) { + if (Expected<Optional<uint64_t>> tsc = + storage.multicpu_decoder->FindLowestTSC()) { + lowest_tsc = *tsc; + } else { + return tsc.takeError(); + } + } + + for (auto &decoder : storage.thread_decoders) { + Expected<Optional<uint64_t>> tsc = decoder.second->FindLowestTSC(); + if (!tsc) + return tsc.takeError(); + + if (*tsc && (!lowest_tsc || *lowest_tsc > **tsc)) + lowest_tsc = **tsc; + } + + if (lowest_tsc) { + storage.beginning_of_time_nanos = + storage.tsc_conversion->ToNanos(*lowest_tsc); + } + return storage.beginning_of_time_nanos; +} + llvm::Expected<lldb::TraceCursorUP> TraceIntelPT::CreateNewCursor(Thread &thread) { - if (Expected<DecodedThreadSP> decoded_thread = Decode(thread)) - return decoded_thread.get()->CreateNewCursor(); - else + if (Expected<DecodedThreadSP> decoded_thread = Decode(thread)) { + if (Expected<Optional<uint64_t>> beginning_of_time = + FindBeginningOfTimeNanos()) + return std::make_unique<TraceCursorIntelPT>( + thread.shared_from_this(), *decoded_thread, m_storage.tsc_conversion, + *beginning_of_time); + else + return beginning_of_time.takeError(); + } else return decoded_thread.takeError(); } diff --git a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h index d3e58374867d..7f2c3f8dda5d 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h +++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h @@ -220,6 +220,13 @@ private: /// returned if the decoder couldn't be properly set up. llvm::Expected<DecodedThreadSP> Decode(Thread &thread); + /// \return + /// The lowest timestamp in nanoseconds in all traces if available, \a + /// llvm::None if all the traces were empty or no trace contained no + /// timing information, or an \a llvm::Error if it was not possible to set + /// up the decoder for some trace. + llvm::Expected<llvm::Optional<uint64_t>> FindBeginningOfTimeNanos(); + // Dump out trace info in JSON format void DumpTraceInfoAsJson(Thread &thread, Stream &s, bool verbose); @@ -236,6 +243,8 @@ private: /// It is provided by either a trace bundle or a live process to convert TSC /// counters to and from nanos. It might not be available on all hosts. llvm::Optional<LinuxPerfZeroTscConversion> tsc_conversion; + llvm::Optional<uint64_t> beginning_of_time_nanos; + bool beginning_of_time_nanos_calculated = false; } m_storage; /// It is provided by either a trace bundle or a live process' "cpuInfo" diff --git a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.cpp b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.cpp index e547032f739d..08f54b582e3f 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.cpp @@ -35,6 +35,28 @@ bool TraceIntelPTMultiCpuDecoder::TracesThread(lldb::tid_t tid) const { return m_tids.count(tid); } +Expected<Optional<uint64_t>> TraceIntelPTMultiCpuDecoder::FindLowestTSC() { + Optional<uint64_t> lowest_tsc; + TraceIntelPTSP trace_sp = GetTrace(); + + Error err = GetTrace()->OnAllCpusBinaryDataRead( + IntelPTDataKinds::kIptTrace, + [&](const DenseMap<cpu_id_t, ArrayRef<uint8_t>> &buffers) -> Error { + for (auto &cpu_id_to_buffer : buffers) { + Expected<Optional<uint64_t>> tsc = + FindLowestTSCInTrace(*trace_sp, cpu_id_to_buffer.second); + if (!tsc) + return tsc.takeError(); + if (*tsc && (!lowest_tsc || *lowest_tsc > **tsc)) + lowest_tsc = **tsc; + } + return Error::success(); + }); + if (err) + return std::move(err); + return lowest_tsc; +} + Expected<DecodedThreadSP> TraceIntelPTMultiCpuDecoder::Decode(Thread &thread) { if (Error err = CorrelateContextSwitchesAndIntelPtTraces()) return std::move(err); @@ -48,8 +70,8 @@ Expected<DecodedThreadSP> TraceIntelPTMultiCpuDecoder::Decode(Thread &thread) { if (it != m_decoded_threads.end()) return it->second; - DecodedThreadSP decoded_thread_sp = - std::make_shared<DecodedThread>(thread.shared_from_this()); + DecodedThreadSP decoded_thread_sp = std::make_shared<DecodedThread>( + thread.shared_from_this(), trace_sp->GetPerfZeroTscConversion()); Error err = trace_sp->OnAllCpusBinaryDataRead( IntelPTDataKinds::kIptTrace, diff --git a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.h b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.h index 3b7926760f3c..87c370e88ae6 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.h +++ b/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.h @@ -66,6 +66,12 @@ public: /// The total number of PSB blocks in all cores. size_t GetTotalPSBBlocksCount() const; + /// \return + /// The lowest TSC value in this trace if available, \a llvm::None if the + /// trace is empty or the trace contains no timing information, or an \a + /// llvm::Error if it was not possible to set up the decoder. + llvm::Expected<llvm::Optional<uint64_t>> FindLowestTSC(); + private: /// Traverse the context switch traces and the basic intel pt continuous /// subtraces and produce a list of continuous executions for each process and diff --git a/contrib/llvm-project/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp b/contrib/llvm-project/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp index 92eec139e07c..c796cbc75c1b 100644 --- a/contrib/llvm-project/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp @@ -968,7 +968,7 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly( UnwindPlan::RowSP prologue_completed_row; // copy of prologue row of CFI int prologue_completed_sp_bytes_offset_from_cfa; // The sp value before the // epilogue started executed - bool prologue_completed_is_aligned; + bool prologue_completed_is_aligned = false; std::vector<bool> prologue_completed_saved_registers; while (current_func_text_offset < size) { diff --git a/contrib/llvm-project/lldb/source/Symbol/Type.cpp b/contrib/llvm-project/lldb/source/Symbol/Type.cpp index 4ee5a3e76ae4..f83bdcdc1c74 100644 --- a/contrib/llvm-project/lldb/source/Symbol/Type.cpp +++ b/contrib/llvm-project/lldb/source/Symbol/Type.cpp @@ -162,8 +162,8 @@ Type::Type(lldb::user_id_t uid, SymbolFile *symbol_file, ConstString name, } Type::Type() - : std::enable_shared_from_this<Type>(), UserID(0), - m_name("<INVALID TYPE>") { + : std::enable_shared_from_this<Type>(), UserID(0), m_name("<INVALID TYPE>"), + m_payload(0) { m_byte_size = 0; m_byte_size_has_value = false; } diff --git a/contrib/llvm-project/lldb/source/Target/Process.cpp b/contrib/llvm-project/lldb/source/Target/Process.cpp index 046706637691..b2f1318ca91d 100644 --- a/contrib/llvm-project/lldb/source/Target/Process.cpp +++ b/contrib/llvm-project/lldb/source/Target/Process.cpp @@ -433,7 +433,8 @@ Process::Process(lldb::TargetSP target_sp, ListenerSP listener_sp, m_profile_data_comm_mutex(), m_profile_data(), m_iohandler_sync(0), m_memory_cache(*this), m_allocated_memory_cache(*this), m_should_detach(false), m_next_event_action_up(), m_public_run_lock(), - m_private_run_lock(), m_finalizing(false), + m_private_run_lock(), m_currently_handling_do_on_removals(false), + m_resume_requested(false), m_finalizing(false), m_clear_thread_plans_on_stop(false), m_force_next_event_delivery(false), m_last_broadcast_state(eStateInvalid), m_destroy_in_process(false), m_can_interpret_function_calls(false), m_run_thread_plan_lock(), @@ -2566,8 +2567,8 @@ Status Process::LaunchPrivate(ProcessLaunchInfo &launch_info, StateType &state, if (state == eStateStopped || state == eStateCrashed) { DidLaunch(); - - // Now that we know the process type, update its signal responses from the + + // Now that we know the process type, update its signal responses from the // ones stored in the Target: if (m_unix_signals_sp) { StreamSP warning_strm = GetTarget().GetDebugger().GetAsyncErrorStream(); @@ -2935,7 +2936,7 @@ void Process::CompleteAttach() { } } } - // Now that we know the process type, update its signal responses from the + // Now that we know the process type, update its signal responses from the // ones stored in the Target: if (m_unix_signals_sp) { StreamSP warning_strm = GetTarget().GetDebugger().GetAsyncErrorStream(); @@ -4550,9 +4551,9 @@ public: private: lldb::ThreadPlanSP m_thread_plan_sp; bool m_already_reset = false; - bool m_private; - bool m_is_controlling; - bool m_okay_to_discard; + bool m_private = false; + bool m_is_controlling = false; + bool m_okay_to_discard = false; }; } // anonymous namespace diff --git a/contrib/llvm-project/lldb/source/Target/RegisterContextUnwind.cpp b/contrib/llvm-project/lldb/source/Target/RegisterContextUnwind.cpp index a0f97d7e7cff..2da40ba2bf61 100644 --- a/contrib/llvm-project/lldb/source/Target/RegisterContextUnwind.cpp +++ b/contrib/llvm-project/lldb/source/Target/RegisterContextUnwind.cpp @@ -1525,7 +1525,7 @@ RegisterContextUnwind::SavedLocationForRegister( // unwindplan_regloc has valid contents about where to retrieve the register if (unwindplan_regloc.IsUnspecified()) { - lldb_private::UnwindLLDB::RegisterLocation new_regloc; + lldb_private::UnwindLLDB::RegisterLocation new_regloc = {}; new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterNotSaved; m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = new_regloc; UnwindLogMsg("save location for %s (%d) is unspecified, continue searching", @@ -1731,7 +1731,7 @@ bool RegisterContextUnwind::TryFallbackUnwindPlan() { addr_t old_caller_pc_value = LLDB_INVALID_ADDRESS; addr_t new_caller_pc_value = LLDB_INVALID_ADDRESS; - UnwindLLDB::RegisterLocation regloc; + UnwindLLDB::RegisterLocation regloc = {}; if (SavedLocationForRegister(pc_regnum.GetAsKind(eRegisterKindLLDB), regloc) == UnwindLLDB::RegisterSearchResult::eRegisterFound) { diff --git a/contrib/llvm-project/lldb/source/Target/StackFrame.cpp b/contrib/llvm-project/lldb/source/Target/StackFrame.cpp index e87cf5af3e39..4fb5ba0b735e 100644 --- a/contrib/llvm-project/lldb/source/Target/StackFrame.cpp +++ b/contrib/llvm-project/lldb/source/Target/StackFrame.cpp @@ -1145,26 +1145,34 @@ bool StackFrame::HasDebugInformation() { ValueObjectSP StackFrame::GetValueObjectForFrameVariable(const VariableSP &variable_sp, DynamicValueType use_dynamic) { - std::lock_guard<std::recursive_mutex> guard(m_mutex); ValueObjectSP valobj_sp; - if (IsHistorical()) { - return valobj_sp; - } - VariableList *var_list = GetVariableList(true); - if (var_list) { - // Make sure the variable is a frame variable - const uint32_t var_idx = var_list->FindIndexForVariable(variable_sp.get()); - const uint32_t num_variables = var_list->GetSize(); - if (var_idx < num_variables) { - valobj_sp = m_variable_list_value_objects.GetValueObjectAtIndex(var_idx); - if (!valobj_sp) { - if (m_variable_list_value_objects.GetSize() < num_variables) - m_variable_list_value_objects.Resize(num_variables); - valobj_sp = ValueObjectVariable::Create(this, variable_sp); - m_variable_list_value_objects.SetValueObjectAtIndex(var_idx, valobj_sp); + { // Scope for stack frame mutex. We need to drop this mutex before we figure + // out the dynamic value. That will require converting the StackID in the + // VO back to a StackFrame, which will in turn require locking the + // StackFrameList. If we still hold the StackFrame mutex, we could suffer + // lock inversion against the pattern of getting the StackFrameList and + // then the stack frame, which is fairly common. + std::lock_guard<std::recursive_mutex> guard(m_mutex); + if (IsHistorical()) { + return valobj_sp; + } + VariableList *var_list = GetVariableList(true); + if (var_list) { + // Make sure the variable is a frame variable + const uint32_t var_idx = var_list->FindIndexForVariable(variable_sp.get()); + const uint32_t num_variables = var_list->GetSize(); + if (var_idx < num_variables) { + valobj_sp = m_variable_list_value_objects.GetValueObjectAtIndex(var_idx); + if (!valobj_sp) { + if (m_variable_list_value_objects.GetSize() < num_variables) + m_variable_list_value_objects.Resize(num_variables); + valobj_sp = ValueObjectVariable::Create(this, variable_sp); + m_variable_list_value_objects.SetValueObjectAtIndex(var_idx, + valobj_sp); + } } } - } + } // End of StackFrame mutex scope. if (use_dynamic != eNoDynamicValues && valobj_sp) { ValueObjectSP dynamic_sp = valobj_sp->GetDynamicValue(use_dynamic); if (dynamic_sp) diff --git a/contrib/llvm-project/lldb/source/Target/ThreadPlanCallFunction.cpp b/contrib/llvm-project/lldb/source/Target/ThreadPlanCallFunction.cpp index a9f774aa6109..7e9bb963bb5d 100644 --- a/contrib/llvm-project/lldb/source/Target/ThreadPlanCallFunction.cpp +++ b/contrib/llvm-project/lldb/source/Target/ThreadPlanCallFunction.cpp @@ -104,7 +104,10 @@ ThreadPlanCallFunction::ThreadPlanCallFunction( m_ignore_breakpoints(options.DoesIgnoreBreakpoints()), m_debug_execution(options.GetDebug()), m_trap_exceptions(options.GetTrapExceptions()), m_function_addr(function), - m_function_sp(0), m_takedown_done(false), + m_start_addr(), m_function_sp(0), m_subplan_sp(), + m_cxx_language_runtime(nullptr), m_objc_language_runtime(nullptr), + m_stored_thread_state(), m_real_stop_info_sp(), m_constructor_errors(), + m_return_valobj_sp(), m_takedown_done(false), m_should_clear_objc_exception_bp(false), m_should_clear_cxx_exception_bp(false), m_stop_address(LLDB_INVALID_ADDRESS), m_return_type(return_type) { @@ -134,7 +137,10 @@ ThreadPlanCallFunction::ThreadPlanCallFunction( m_ignore_breakpoints(options.DoesIgnoreBreakpoints()), m_debug_execution(options.GetDebug()), m_trap_exceptions(options.GetTrapExceptions()), m_function_addr(function), - m_function_sp(0), m_takedown_done(false), + m_start_addr(), m_function_sp(0), m_subplan_sp(), + m_cxx_language_runtime(nullptr), m_objc_language_runtime(nullptr), + m_stored_thread_state(), m_real_stop_info_sp(), m_constructor_errors(), + m_return_valobj_sp(), m_takedown_done(false), m_should_clear_objc_exception_bp(false), m_should_clear_cxx_exception_bp(false), m_stop_address(LLDB_INVALID_ADDRESS), m_return_type(CompilerType()) {} diff --git a/contrib/llvm-project/lldb/source/Target/ThreadPlanTracer.cpp b/contrib/llvm-project/lldb/source/Target/ThreadPlanTracer.cpp index f5331428038b..7e0925307644 100644 --- a/contrib/llvm-project/lldb/source/Target/ThreadPlanTracer.cpp +++ b/contrib/llvm-project/lldb/source/Target/ThreadPlanTracer.cpp @@ -36,11 +36,11 @@ using namespace lldb_private; ThreadPlanTracer::ThreadPlanTracer(Thread &thread, lldb::StreamSP &stream_sp) : m_process(*thread.GetProcess().get()), m_tid(thread.GetID()), - m_enabled(false), m_stream_sp(stream_sp) {} + m_enabled(false), m_stream_sp(stream_sp), m_thread(nullptr) {} ThreadPlanTracer::ThreadPlanTracer(Thread &thread) : m_process(*thread.GetProcess().get()), m_tid(thread.GetID()), - m_enabled(false), m_stream_sp() {} + m_enabled(false), m_stream_sp(), m_thread(nullptr) {} Stream *ThreadPlanTracer::GetLogStream() { if (m_stream_sp) diff --git a/contrib/llvm-project/lldb/source/Target/TraceCursor.cpp b/contrib/llvm-project/lldb/source/Target/TraceCursor.cpp index f99b0d28c154..de3f9bf1b33d 100644 --- a/contrib/llvm-project/lldb/source/Target/TraceCursor.cpp +++ b/contrib/llvm-project/lldb/source/Target/TraceCursor.cpp @@ -50,6 +50,8 @@ const char *TraceCursor::EventKindToString(lldb::TraceEvent event_kind) { return "software disabled tracing"; case lldb::eTraceEventCPUChanged: return "CPU core changed"; + case lldb::eTraceEventHWClockTick: + return "HW clock tick"; } llvm_unreachable("Fully covered switch above"); } diff --git a/contrib/llvm-project/lldb/source/Target/TraceDumper.cpp b/contrib/llvm-project/lldb/source/Target/TraceDumper.cpp index 739105e9e9fb..5b71e9e4e97a 100644 --- a/contrib/llvm-project/lldb/source/Target/TraceDumper.cpp +++ b/contrib/llvm-project/lldb/source/Target/TraceDumper.cpp @@ -128,16 +128,26 @@ public: m_s.Format(" {0}: ", item.id); - if (m_options.show_tsc) { - m_s.Format("[tsc={0}] ", - item.tsc ? std::to_string(*item.tsc) : "unavailable"); + if (m_options.show_timestamps) { + m_s.Format("[{0}] ", item.timestamp + ? formatv("{0:3} ns", *item.timestamp).str() + : "unavailable"); } if (item.event) { m_s << "(event) " << TraceCursor::EventKindToString(*item.event); - if (*item.event == eTraceEventCPUChanged) { + switch (*item.event) { + case eTraceEventCPUChanged: m_s.Format(" [new CPU={0}]", item.cpu_id ? std::to_string(*item.cpu_id) : "unavailable"); + break; + case eTraceEventHWClockTick: + m_s.Format(" [{0}]", item.hw_clock ? std::to_string(*item.hw_clock) + : "unavailable"); + break; + case eTraceEventDisabledHW: + case eTraceEventDisabledSW: + break; } } else if (item.error) { m_s << "(error) " << *item.error; @@ -181,7 +191,8 @@ class OutputWriterJSON : public TraceDumper::OutputWriter { | { "loadAddress": string decimal, "id": decimal, - "tsc"?: string decimal, + "hwClock"?: string decimal, + "timestamp_ns"?: string decimal, "module"?: string, "symbol"?: string, "line"?: decimal, @@ -202,8 +213,17 @@ public: void DumpEvent(const TraceDumper::TraceItem &item) { m_j.attribute("event", TraceCursor::EventKindToString(*item.event)); - if (item.event == eTraceEventCPUChanged) + switch (*item.event) { + case eTraceEventCPUChanged: m_j.attribute("cpuId", item.cpu_id); + break; + case eTraceEventHWClockTick: + m_j.attribute("hwClock", item.hw_clock); + break; + case eTraceEventDisabledHW: + case eTraceEventDisabledSW: + break; + } } void DumpInstruction(const TraceDumper::TraceItem &item) { @@ -234,10 +254,11 @@ public: void TraceItem(const TraceDumper::TraceItem &item) override { m_j.object([&] { m_j.attribute("id", item.id); - if (m_options.show_tsc) - m_j.attribute( - "tsc", - item.tsc ? Optional<std::string>(std::to_string(*item.tsc)) : None); + if (m_options.show_timestamps) + m_j.attribute("timestamp_ns", item.timestamp + ? Optional<std::string>( + std::to_string(*item.timestamp)) + : None); if (item.event) { DumpEvent(item); @@ -286,11 +307,11 @@ TraceDumper::TraceDumper(lldb::TraceCursorUP &&cursor_up, Stream &s, } TraceDumper::TraceItem TraceDumper::CreatRawTraceItem() { - TraceItem item; + TraceItem item = {}; item.id = m_cursor_up->GetId(); - if (m_options.show_tsc) - item.tsc = m_cursor_up->GetCounter(lldb::eTraceCounterTSC); + if (m_options.show_timestamps) + item.timestamp = m_cursor_up->GetWallClockTime(); return item; } @@ -366,8 +387,17 @@ Optional<lldb::user_id_t> TraceDumper::DumpInstructions(size_t count) { if (!m_options.show_events) continue; item.event = m_cursor_up->GetEventType(); - if (*item.event == eTraceEventCPUChanged) + switch (*item.event) { + case eTraceEventCPUChanged: item.cpu_id = m_cursor_up->GetCPU(); + break; + case eTraceEventHWClockTick: + item.hw_clock = m_cursor_up->GetHWClock(); + break; + case eTraceEventDisabledHW: + case eTraceEventDisabledSW: + break; + } } else if (m_cursor_up->IsError()) { item.error = m_cursor_up->GetError(); } else { |